Distribuisci il tuo primo workflow gestito
Versioni dei pacchetti
Il codice in questa pagina è stato sviluppato usando i seguenti requisiti. Ti consigliamo di usare queste versioni o più recenti.
qiskit[all]~=2.6.1
qiskit-serverless~=0.38.0
Usa questa pagina per caricare un workflow, eseguirlo e ottenerne il risultato. Il workflow di esempio ottimizza e simula un circuito Qiskit. Simula il circuito su hardware classico, quindi non usa tempo QPU.
Prima di iniziare, installa il pacchetto client e autenticati.
Per distribuire il tuo codice con l'aiuto di un assistente AI, usa le skill AI nel repository dei template di 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")
Scrivere un workflow
Creare la struttura delle cartelle
Un workflow gestito è una cartella di file Python con un file entrypoint. Un workflow gestito carica tutto il contenuto della cartella, fino a 50 MB, ed esegue l'entrypoint come script. Poiché un workflow carica l'intera cartella, tieni i tuoi file locali, come deploy.ipynb, fuori dalla cartella. Crea la seguente struttura:
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
Scrivere l'entrypoint hello world
L'entrypoint legge un circuito, lo ottimizza e lo simula, e salva i conteggi e la profondità a due qubit. Salva il codice seguente come source_files/hello_world.py:
Se leggi questa pagina come notebook, la cella di codice per hello_world.py inizia con il comando magic %%writefile. Quando esegui questa cella, salva il codice nel file invece di eseguirlo.
# 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
L'entrypoint usa tre funzioni di qiskit_serverless:
-
get_arguments()restituisce come dizionario gli argomenti con nome che passi arun(). Ogni valore deve essere serializzabile in JSON, oppure un oggetto che il client può codificare, come unQuantumCircuit. Gli oggetti codificati arrivano come gli stessi oggetti che hai passato. -
update_status(Job.OPTIMIZING_HARDWARE)imposta lo stato dettagliatoRUNNING: OPTIMIZING_FOR_HARDWARE, che puoi vedere mentre il job è in esecuzione. Consulta Segnalare l'avanzamento con update_status(). -
save_result()memorizza un valore serializzabile in JSON che leggi in seguito conjob.result(). Il workflow restituisce i conteggi come dizionario e la profondità a due qubit del circuito ottimizzato come intero.
Tutto ciò che il workflow scrive sullo standard output, come la profondità a due qubit, va nei log del job. Per aggiungere timestamp e livelli di log, usa il modulo logging. Consulta Scrivere i log e gestire gli errori.
Caricare il workflow
Nel tuo notebook locale, esegui il codice seguente dalla cartella hello_world_project. Il codice si connette con il tuo account salvato, definisce il workflow e lo carica. entrypoint è il file che il workflow esegue e working_dir è la cartella che carichi:
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)
Eseguire il workflow con degli input
Costruisci un circuito GHZ a tre qubit da passare a hello_world come input:
from qiskit import QuantumCircuit
circuit = QuantumCircuit(3)
circuit.h(0)
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.measure_all()
Esegui hello_world con il circuito e il numero di shot come argomenti con nome. I nomi degli argomenti corrispondono alle chiavi che l'entrypoint legge con get_arguments():
job = hello_world.run(circuit=circuit, shots=1024)
print(job.job_id)
54705348-5117-44b7-935b-e6986ef182fa
run() restituisce un Job dopo che il workflow ha messo in coda il job. Non attende l'esecuzione del job. Il job continua nel cloud dopo che chiudi la sessione Python. Per ritrovarlo in seguito, elenca i tuoi job recenti con client.jobs().
Ottenere stato, risultato e log
Subito dopo aver chiamato run(), lo stato è di solito QUEUED:
job.status()
'QUEUED'
Lo stato passa da QUEUED a INITIALIZING, RUNNING e infine DONE.
job.result() attende il termine del job, quindi restituisce il valore che il workflow ha passato a 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"])
Puoi leggere i log mentre il job è in esecuzione. Il workflow carica nuove righe circa ogni 15 secondi. I log includono la riga che il workflow ha stampato:
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()
Aggiornare il workflow
Per modificare un workflow, modifica i suoi file e chiama di nuovo upload() con lo stesso title. Il nuovo caricamento sostituisce quello precedente e i job già avviati non sono interessati.
Campi come arguments_schema e sizes_map mantengono i valori memorizzati quando li ometti dal nuovo caricamento.
Passi successivi
- Definisci input e output per scoprire quali tipi di argomenti e di risultati supporta un workflow.
- Dichiara le dipendenze per usare più pacchetti Python nel tuo workflow.
- Esegui job quantistici da un workflow per eseguire i tuoi circuiti su una QPU, segnalare ogni fase e tracciare i job QPU.
- Esegui un workflow gestito per conoscere tutti gli stati dei job, fare il debug di un job fallito e ritrovare un job in seguito.
- Per partire da codice funzionante, distribuisci uno dei template di Qiskit Function, oppure adatta un template al tuo workflow.