Déploie ton premier workflow géré
Versions des paquets
Le code de cette page a été développé avec les prérequis suivants. Nous te recommandons d'utiliser ces versions ou des versions plus récentes.
qiskit[all]~=2.6.1
qiskit-serverless~=0.38.0
Utilise cette page pour téléverser un workflow, l'exécuter et obtenir son résultat. Le workflow d'exemple optimise et simule un circuit Qiskit. Il simule le circuit sur du matériel classique, il n'utilise donc pas de temps QPU.
Avant de commencer, installe le paquet client et authentifie-toi.
Pour déployer ton propre code avec l'aide d'un assistant IA, utilise les compétences IA du dépôt de modèles Qiskit Function.
# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util
_needed = {"qiskit": "qiskit", "qiskit_ibm_catalog": "qiskit-ibm-catalog", "qiskit_serverless": "qiskit-serverless"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
Écrire un workflow
Créer la structure de dossiers
Un workflow géré est un dossier de fichiers Python avec un fichier de point d'entrée. Un workflow géré téléverse tout le contenu du dossier, jusqu'à 50 Mo, et exécute le point d'entrée comme un script. Comme un workflow téléverse tout le dossier, garde tes fichiers locaux, comme deploy.ipynb, en dehors du dossier. Crée l'arborescence suivante :
hello_world_project/
├── deploy.ipynb # Your local notebook: upload and run the workflow
└── source_files/ # The working directory that you upload
└── hello_world.py # The entrypoint
Écrire le point d'entrée hello world
Le point d'entrée lit un circuit, l'optimise et le simule, puis enregistre les comptages et la profondeur à deux qubits. Enregistre le code suivant sous source_files/hello_world.py :
Si tu lis cette page sous forme de notebook, la cellule de code de hello_world.py commence par la commande magique %%writefile. Lorsque tu exécutes cette cellule, elle enregistre le code dans le fichier au lieu de l'exécuter.
# This cell is hidden from users. It creates the working directory.
from pathlib import Path
Path("./source_files").mkdir(exist_ok=True)
%%writefile ./source_files/hello_world.py
from qiskit.primitives import StatevectorSampler
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_serverless import Job, get_arguments, save_result, update_status
# Read the arguments that you pass to run()
arguments = get_arguments()
circuit = arguments["circuit"]
shots = arguments.get("shots", 1024)
# Optimize the circuit. Printed text goes to the job's logs.
update_status(Job.OPTIMIZING_HARDWARE)
pass_manager = generate_preset_pass_manager(
optimization_level=1, basis_gates=["cz", "rz", "sx", "x"]
)
isa_circuit = pass_manager.run(circuit)
two_qubit_depth = isa_circuit.depth(lambda instruction: instruction.operation.num_qubits == 2)
print(f"Two-qubit depth after optimization: {two_qubit_depth}", flush=True)
# Simulate the circuit and return the counts
sampler = StatevectorSampler(seed=1234)
pub_result = sampler.run([isa_circuit], shots=shots).result()[0]
save_result({"counts": pub_result.data.meas.get_counts(), "two_qubit_depth": two_qubit_depth})
Writing ./source_files/hello_world.py
Le point d'entrée utilise trois fonctions de qiskit_serverless :
-
get_arguments()renvoie sous forme de dictionnaire les arguments nommés que tu passes àrun(). Chaque valeur doit être sérialisable en JSON, ou être un objet que le client peut encoder, comme unQuantumCircuit. Les objets encodés arrivent sous la forme des mêmes objets que ceux que tu as passés. -
update_status(Job.OPTIMIZING_HARDWARE)définit le statut détailléRUNNING: OPTIMIZING_FOR_HARDWARE, que tu peux voir pendant l'exécution du job. Consulte Signaler la progression avec update_status(). -
save_result()stocke une valeur sérialisable en JSON que tu lis ensuite avecjob.result(). Le workflow renvoie les comptages sous forme de dictionnaire et la profondeur à deux qubits du circuit optimisé sous forme d'entier.
Tout ce que le workflow écrit sur la sortie standard, comme la profondeur à deux qubits, va dans les logs du job. Pour ajouter des horodatages et des niveaux de log, utilise le module logging. Consulte Écrire des logs et gérer les erreurs.
Téléverser le workflow
Dans ton notebook local, exécute le code suivant depuis le dossier hello_world_project. Le code se connecte avec ton compte enregistré, définit le workflow et le téléverse. entrypoint est le fichier que le workflow exécute, et working_dir est le dossier que tu téléverses :
from qiskit_ibm_catalog import ManagedWorkflow, ManagedWorkflowClient
client = ManagedWorkflowClient()
hello_world = ManagedWorkflow(
title="hello-world",
entrypoint="hello_world.py",
working_dir="./source_files/",
)
hello_world = client.upload(hello_world)
Exécuter le workflow avec des entrées
Construis un circuit GHZ à trois qubits à passer à hello_world comme entrée :
from qiskit import QuantumCircuit
circuit = QuantumCircuit(3)
circuit.h(0)
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.measure_all()
Exécute hello_world avec le circuit et le nombre de shots comme arguments nommés. Les noms des arguments correspondent aux clés que le point d'entrée lit avec get_arguments() :
job = hello_world.run(circuit=circuit, shots=1024)
print(job.job_id)
54705348-5117-44b7-935b-e6986ef182fa
run() renvoie un Job une fois que le workflow a mis le job en file d'attente. Elle n'attend pas que le job s'exécute. Le job continue dans le cloud après la fermeture de ta session Python. Pour le retrouver plus tard, liste tes jobs récents avec client.jobs().
Obtenir le statut, le résultat et les logs
Juste après l'appel à run(), le statut est généralement QUEUED :
job.status()
'QUEUED'
Le statut passe de QUEUED à INITIALIZING, RUNNING, puis DONE.
job.result() attend la fin du job, puis renvoie la valeur que le workflow a passée à save_result() :
job.result()
{'counts': {'111': 514, '000': 510}, 'two_qubit_depth': 2}
# This cell is hidden from users. It checks the result.
assert set(_["counts"]) <= {"000", "111"} # noqa: F821
assert sum(_["counts"].values()) == 1024 # noqa: F821
from qiskit.visualization import plot_histogram
plot_histogram(job.result()["counts"])
Tu peux lire les logs pendant l'exécution du job. Le workflow téléverse de nouvelles lignes environ toutes les 15 secondes. Les logs incluent la ligne que le workflow a affichée :
print(job.logs())
Two-qubit depth after optimization: 2
# This cell is hidden from users. It checks the logs.
assert "Two-qubit depth after optimization" in job.logs()
Mettre à jour le workflow
Pour modifier un workflow, édite ses fichiers et appelle à nouveau upload() avec le même title. Le nouveau téléversement remplace le précédent, et les jobs déjà démarrés ne sont pas affectés.
Les champs comme arguments_schema et sizes_map conservent leurs valeurs enregistrées lorsque tu les omets dans le nouveau téléversement.
Prochaines étapes
- Définis les entrées et les sorties pour savoir quels types d'arguments et de résultats un workflow prend en charge.
- Déclare les dépendances pour utiliser davantage de paquets Python dans ton workflow.
- Exécute des jobs quantiques depuis un workflow pour exécuter tes circuits sur un QPU, signaler chaque étape et suivre les jobs QPU.
- Exécute un workflow géré pour connaître tous les statuts de job, déboguer un job en échec et retrouver un job plus tard.
- Pour partir d'un code qui fonctionne, déploie l'un des modèles Qiskit Function, ou adapte un modèle à ton propre workflow.