Definisci input e output
Un workflow gestito funziona come una funzione Python eseguita su calcolo remoto. Confronta una funzione locale con lo stesso codice come workflow:
Local Python
def my_workflow(circuits, shots=4096):
...
return {"counts": counts}
result = my_workflow(circuits=circuits, shots=1024)
In un workflow gestito, run() è la chiamata, get_arguments() fornisce al workflow i suoi parametri e save_result() è la sua istruzione return. Poiché il workflow viene eseguito come job separato su calcolo remoto, differisce da una chiamata di funzione locale in tre modi:
-
Il client codifica argomenti e risultati. Ogni valore deve essere uno che il client sia in grado di codificare, e alcuni tipi cambiano. Vedi Leggi gli argomenti nel tuo workflow.
-
La chiamata non attende.
run()restituisce subito un job, e leggi il risultato in seguito conjob.result(). Vedi Salva i risultati. -
Nulla controlla la chiamata. Una funzione Python rifiuta un argomento keyword sconosciuto, ma un workflow lo ignora a meno che tu non alleghi uno schema. Vedi Buona pratica: convalida gli argomenti con uno schema.
Leggi gli argomenti nel tuo workflow
Passa gli input al tuo workflow dal tuo notebook locale:
run_workflow_remotely.ipynb
job = my_workflow.run(circuits=circuits, shots=1024)
Per abilitarlo, modifica il codice del tuo workflow in modo che recuperi gli argomenti con get_arguments(), che restituisce un dizionario le cui chiavi sono i nomi degli argomenti:
source_files/my_workflow.py
from qiskit_serverless import get_arguments
arguments = get_arguments()
circuits = arguments["circuits"]
shots = arguments.get("shots", 4096)
Il dizionario contiene solo gli argomenti passati dall'esecuzione, quindi usa arguments.get() con un valore predefinito per gli argomenti opzionali. Puoi usare qualsiasi nome di argomento tranne le parole chiave protette config e function_size, perché run() usa direttamente queste parole chiave. run() rifiuta anche compute_profile. Per scegliere le risorse di calcolo, passa function_size.
Per leggere la dimensione con cui viene eseguito il job, chiama get_function_size() nel codice del tuo workflow:
source_files/my_workflow.py
from qiskit_serverless import get_function_size
size = get_function_size() # For example, "M"
Se l'esecuzione non passa function_size, get_function_size() restituisce la dimensione predefinita del workflow. Vedi Scegli una dimensione per ogni esecuzione.
Tipi di argomento supportati
Ogni valore deve essere serializzabile in JSON, oppure un oggetto che il client sia in grado di codificare, come un circuito Qiskit o un array NumPy. Poiché il client codifica ogni argomento prima di inviare il job e get_arguments() lo decodifica all'interno del workflow, il workflow riceve l'oggetto Python originale.
Il client invia int, float, str, bool, None e liste o dizionari di questi senza modifiche. Codifica altri oggetti, come un QuantumCircuit, un numpy.ndarray o un numero complex, come un dizionario con un tag __type__ e un __value__. Hai bisogno di questa forma quando scrivi uno schema degli argomenti.
Poiché JSON non ha un equivalente per alcuni tipi, questi tipi cambiano durante la codifica. Le tuple arrivano come liste, le chiavi dei dizionari arrivano come stringhe e gli interi NumPy come np.int64 arrivano come int. Se il client non riesce a codificare un valore, come bytes o np.float32, run() solleva un TypeError e non crea un job.
Alcuni oggetti non possono essere passati come argomenti. Ad esempio, passa il nome di un backend come stringa invece di un oggetto Backend, e crea il backend all'interno del workflow. Vedi Esegui job quantistici da un workflow.
Limiti di dimensione
Gli argomenti di una singola esecuzione possono arrivare a 32 MB dopo la codifica. Ad esempio, un circuito da 100 qubit con una profondità di 100 si codifica in circa 39 KB, quindi una singola esecuzione può accettare un batch di circa 800 circuiti di questo tipo. Per input più grandi, carica un file e passa il suo nome come argomento.
Salva i risultati
Usa save_result() alla fine del tuo workflow per restituire un risultato al tuo notebook. Leggi il risultato nel tuo notebook con job.result():
run_workflow_remotely.ipynb
result = job.result()
Per abilitarlo, chiama save_result() nel codice del tuo workflow:
source_files/my_workflow.py
from qiskit_serverless import save_result
if not save_result({"counts": counts, "circuit": isa_circuit}):
raise ValueError("The result could not be encoded.")
save_result() codifica il risultato allo stesso modo in cui il client codifica gli argomenti, e job.result() lo decodifica. Un risultato può quindi contenere i tipi di argomento supportati, come circuiti, array NumPy e il risultato di un job primitivo, con le stesse modifiche di tipo.
-
Controlla il valore restituito. Se
save_result()non riesce a codificare il valore, registra un avviso e restituisceFalseinvece di sollevare un errore. Senza un controllo, il job può terminare con lo statoDONEe nessun risultato. -
Viene archiviato solo l'ultimo
save_result(). Ogni chiamata sostituisce il risultato salvato. Per restituire più valori, salvali in un unico dizionario, oppure scrivili nei log. -
Un dizionario vuoto significa nessun risultato. Se il workflow non chiama mai
save_result(),job.result()restituisce{}.
Per restituire file, come array di grandi dimensioni o grafici, salvali nell'archiviazione file e restituisci i loro nomi nel risultato.
Buona pratica: convalida gli argomenti con uno schema
Come buona pratica, allega uno JSON Schema a ogni workflow che accetta argomenti. Lo schema descrive gli argomenti che il workflow accetta, e il workflow controlla gli argomenti di ogni esecuzione rispetto a esso prima di creare il job. Se gli argomenti non corrispondono, run() fallisce immediatamente con un errore che indica il campo errato, e il workflow non crea un job. Senza uno schema, gli argomenti errati raggiungono il workflow dopo l'avvio del job, e il workflow ignora il nome di un argomento scritto in modo errato.
Imposta lo schema con arguments_schema quando carichi il workflow. Passa un dizionario, non una stringa JSON:
run_workflow_remotely.ipynb
from qiskit_ibm_catalog import ManagedWorkflow, ManagedWorkflowClient
arguments_schema = {
"type": "object",
"additionalProperties": False,
"required": ["circuits"],
"properties": {
"circuits": {
"type": "array",
"minItems": 1,
"items": {"$ref": "#/$defs/circuit"},
},
"shots": {"type": "integer", "minimum": 1, "maximum": 100000},
"backend_name": {"type": "string", "minLength": 1},
},
"$defs": {
"circuit": {
"type": "object",
"required": ["__type__", "__value__"],
"properties": {
"__type__": {"const": "QuantumCircuit"},
"__value__": {"type": "string"},
},
}
},
}
client = ManagedWorkflowClient()
my_workflow = client.upload(
ManagedWorkflow(
title="my-workflow",
entrypoint="my_workflow.py",
working_dir="./source_files/",
arguments_schema=arguments_schema,
)
)
Tieni presenti i seguenti punti quando scrivi uno schema:
-
Descrivi la forma codificata degli oggetti Qiskit e NumPy. Lo schema controlla gli argomenti così come li invia il client, quindi un circuito è un oggetto come
{"__type__": "QuantumCircuit", "__value__": "<base64-encoded QPY>"}, non una stringa o un array. Controlla il tag__type__e tratta__value__come una stringa opaca. Uno schema che descrive un circuito come stringa rifiuta ogni esecuzione valida. -
Imposta
"additionalProperties": false. Senza questa impostazione, il workflow ignora senza avviso il nome di un argomento scritto in modo errato, comeshotz, ed esegue con il suo valore predefinito. Dichiara ogni argomento che il workflow accetta prima di abilitare questa impostazione. -
Contrassegna gli argomenti come obbligatori. Aggiungi a
requiredogni argomento che il workflow legge senza un valore predefinito.
Se gli argomenti non corrispondono allo schema, il messaggio di errore indica la regola e la posizione del valore errato:
'type' validation failed, schema requires 'integer': rejected value '4096'
path: ['shots']
Uno schema controlla il tipo, la forma e l'intervallo di ogni argomento. Uno schema non può controllare se due argomenti validi sono in conflitto, o se un circuito si adatta a un backend. Mantieni questi controlli nel codice del workflow.
Aggiorna o rimuovi uno schema
-
Per sostituire lo schema, imposta un nuovo
arguments_schemae carica di nuovo il workflow. -
Per rimuovere lo schema, carica il workflow con
arguments_schema={}. -
Se carichi il workflow senza
arguments_schema, il workflow mantiene lo schema archiviato.
Per vedere lo schema in vigore, leggi my_workflow.arguments_schema. Un valore None significa che il workflow non ha schema.
Controlla gli argomenti prima di eseguire
Chiama validate_arguments() per controllare un insieme di argomenti rispetto allo schema senza avviare un job:
run_workflow_remotely.ipynb
my_workflow.validate_arguments({"circuits": [circuit], "shots": 1024})
# {'valid': True}
Se gli argomenti non sono validi, validate_arguments() solleva una QiskitServerlessException con lo stesso messaggio che run() restituisce per quegli argomenti. Se il workflow non ha uno schema, qualsiasi argomento è valido. Un risultato valido non garantisce che run() abbia successo, perché run() controlla anche altri limiti, come il numero di job attivi.
Regole dello schema
Un workflow gestito rifiuta il caricamento se lo schema viola una qualsiasi delle seguenti regole:
-
Lo schema può essere grande fino a 64 KiB, con fino a 64 livelli di annidamento e fino a 200 sottoschemi.
-
I riferimenti devono puntare all'interno dello stesso schema, come
#/$defs/circuit, e ogni riferimento deve essere risolvibile. I riferimenti a URL o file non sono consentiti. -
Lo schema deve essere un oggetto o un booleano.
Evita anche i seguenti problemi, che il caricamento non rileva:
-
Quantificatori annidati in
pattern. Un pattern come^(a+)+$può richiedere moltissimo tempo per essere valutato. Un workflow interrompe la convalida dopo un limite di tempo CPU e rifiuta l'esecuzione. Scrivi pattern senza un quantificatore attorno a un gruppo che ne contiene già uno, come^ibm_[a-z0-9_]{1,40}$. -
falsecome schema. Lo schemafalserifiuta ogni esecuzione. Per rimuovere la convalida, usa{}.
Risolvi i problemi di uno schema
| Problema | Causa |
|---|---|
| Ogni esecuzione viene rifiutata per un argomento circuito. | Lo schema descrive il circuito come una stringa o un array. Descrivilo come un oggetto con un tag __type__. |
| Esecuzioni valide vengono rifiutate. | additionalProperties è false, e lo schema non dichiara un argomento che l'esecuzione passa. Il path dell'errore indica l'argomento. |
| Esecuzioni non valide non vengono rifiutate. | Il workflow non ha uno schema. Controlla my_workflow.arguments_schema. |
| Nessuna esecuzione viene controllata, anche se hai impostato uno schema. | Lo schema è stato passato come stringa JSON. Passa un dizionario. |
Il caricamento fallisce con un errore 400. | Lo schema viola una delle regole dello schema. |
| L'errore dice che la convalida ha richiesto troppo tempo CPU. | Un pattern ha quantificatori annidati. Riscrivi il pattern. |