Vai al contenuto principale
Questo progetto è in fase beta. Hai trovato un bug? Apri una issue su GitHub. Hai una domanda o un'idea? Chiedi su GitHub Discussions — apprezziamo il tuo feedback!
Com'è la qualità della traduzione su questa pagina?

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.

Usa le skill AI (facoltativo)

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:

nota

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 a run(). Ogni valore deve essere serializzabile in JSON, oppure un oggetto che il client può codificare, come un QuantumCircuit. Gli oggetti codificati arrivano come gli stessi oggetti che hai passato.

  • update_status(Job.OPTIMIZING_HARDWARE) imposta lo stato dettagliato RUNNING: 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 con job.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"])

Output of the previous code cell

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​

Raccomandazioni