Definește intrările și ieșirile
Un workflow gestionat funcționează ca o funcție Python care rulează pe resurse de calcul la distanță. Compară o funcție locală cu același cod ca workflow:
Local Python
def my_workflow(circuits, shots=4096):
...
return {"counts": counts}
result = my_workflow(circuits=circuits, shots=1024)
Într-un workflow gestionat, run() este apelul, get_arguments() oferă workflow-ului parametrii săi, iar save_result() este instrucțiunea sa return. Deoarece workflow-ul rulează ca un job separat pe resurse de calcul la distanță, diferă de un apel local de funcție în trei moduri:
-
Clientul codifică argumentele și rezultatele. Fiecare valoare trebuie să fie una pe care clientul o poate codifica, iar unele tipuri se schimbă. Vezi Citește argumentele în workflow-ul tău.
-
Apelul nu așteaptă.
run()returnează imediat un job, iar rezultatul îl citești mai târziu cujob.result(). Vezi Salvează rezultatele. -
Nimic nu verifică apelul. O funcție Python respinge un argument cu nume necunoscut, dar un workflow îl ignoră dacă nu atașezi o schemă. Vezi Bună practică: validează argumentele cu o schemă.
Citește argumentele în workflow-ul tău
Transmite intrări workflow-ului tău din notebookul tău local:
run_workflow_remotely.ipynb
job = my_workflow.run(circuits=circuits, shots=1024)
Pentru a activa acest lucru, modifică codul workflow-ului ca să preia argumentele cu get_arguments(), care returnează un dicționar ale cărui chei sunt numele argumentelor:
source_files/my_workflow.py
from qiskit_serverless import get_arguments
arguments = get_arguments()
circuits = arguments["circuits"]
shots = arguments.get("shots", 4096)
Dicționarul conține doar argumentele transmise de rulare, deci folosește arguments.get() cu o valoare implicită pentru argumentele opționale. Poți folosi orice nume de argument, cu excepția cuvintelor cheie protejate config și function_size, deoarece run() folosește direct aceste cuvinte cheie. run() respinge și compute_profile. Pentru a alege resursele de calcul, transmite function_size.
Pentru a citi dimensiunea la care rulează jobul, apelează get_function_size() în codul workflow-ului tău:
source_files/my_workflow.py
from qiskit_serverless import get_function_size
size = get_function_size() # For example, "M"
Dacă rularea nu transmite function_size, get_function_size() returnează dimensiunea implicită a workflow-ului. Vezi Alege o dimensiune pentru fiecare rulare.
Tipuri de argumente suportate
Fiecare valoare trebuie să fie serializabilă JSON sau un obiect pe care clientul îl poate codifica, precum un circuit Qiskit sau un tablou NumPy. Deoarece clientul codifică fiecare argument înainte de a trimite jobul, iar get_arguments() îl decodifică în interiorul workflow-ului, workflow-ul primește obiectul Python original.
Clientul trimite int, float, str, bool, None și liste sau dicționare ale acestora neschimbate. Codifică alte obiecte, precum un QuantumCircuit, un numpy.ndarray sau un număr complex, ca dicționar cu o etichetă __type__ și o __value__. Ai nevoie de această formă când scrii o schemă de argumente.
Deoarece JSON nu are echivalent pentru unele tipuri, acestea se schimbă în timpul codificării. Tuplurile ajung ca liste, cheile dicționarelor ajung ca șiruri, iar întregii NumPy precum np.int64 ajung ca int. Dacă clientul nu poate codifica o valoare, precum bytes sau np.float32, run() ridică o TypeError și nu creează un job.
Unele obiecte nu pot fi transmise ca argumente. De exemplu, transmite numele unui backend ca șir, nu un obiect Backend, și creează backendul în interiorul workflow-ului. Vezi Rulează joburi cuantice dintr-un workflow.
Limite de dimensiune
Argumentele unei rulări pot avea până la 32 MB după codificare. De exemplu, un circuit de 100 de qubiți cu adâncimea 100 se codifică la aproximativ 39 KB, deci o singură rulare poate primi un batch de aproximativ 800 de astfel de circuite. Pentru intrări mai mari, încarcă un fișier și transmite numele lui ca argument.
Salvează rezultatele
Folosește save_result() la sfârșitul workflow-ului pentru a returna un rezultat în notebookul tău. Citește rezultatul în notebook cu job.result():
run_workflow_remotely.ipynb
result = job.result()
Pentru a activa acest lucru, apelează save_result() în codul workflow-ului tău:
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() codifică rezultatul în același mod în care clientul codifică argumentele, iar job.result() îl decodifică. Un rezultat poate deci conține tipurile de argumente suportate, precum circuite, tablouri NumPy și rezultatul unui job primitiv, cu aceleași schimbări de tip.
-
Verifică valoarea returnată. Dacă
save_result()nu poate codifica valoarea, înregistrează un avertisment și returneazăFalseîn loc să ridice o eroare. Fără verificare, jobul se poate încheia cu statusulDONEși fără rezultat. -
Se stochează doar ultimul
save_result(). Fiecare apel înlocuiește rezultatul salvat. Pentru a returna mai multe valori, salvează-le într-un singur dicționar sau scrie-le în loguri. -
Un dicționar gol înseamnă lipsa rezultatului. Dacă workflow-ul nu apelează niciodată
save_result(),job.result()returnează{}.
Pentru a returna fișiere, precum tablouri mari sau grafice, salvează-le în stocarea de fișiere și returnează numele lor în rezultat.
Bună practică: validează argumentele cu o schemă
Ca bună practică, atașează o schemă JSON fiecărui workflow care primește argumente. Schema descrie argumentele pe care le acceptă workflow-ul, iar workflow-ul verifică argumentele fiecărei rulări în raport cu ea înainte de a crea jobul. Dacă argumentele nu se potrivesc, run() eșuează imediat cu o eroare care numește câmpul greșit, iar workflow-ul nu creează un job. Fără schemă, argumentele greșite ajung la workflow după pornirea jobului, iar workflow-ul ignoră un nume de argument scris greșit.
Setează schema cu arguments_schema când încarci workflow-ul. Transmite un dicționar, nu un șir 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,
)
)
Ține cont de următoarele puncte când scrii o schemă:
-
Descrie forma codificată a obiectelor Qiskit și NumPy. Schema verifică argumentele așa cum le trimite clientul, deci un circuit este un obiect precum
{"__type__": "QuantumCircuit", "__value__": "<base64-encoded QPY>"}, nu un șir sau un tablou. Verifică eticheta__type__și tratează__value__ca un șir opac. O schemă care descrie un circuit ca șir respinge fiecare rulare validă. -
Setează
"additionalProperties": false. Fără această setare, workflow-ul ignoră fără avertisment un nume de argument scris greșit, precumshotz, și rulează cu valoarea implicită. Declară fiecare argument pe care îl acceptă workflow-ul înainte de a activa această setare. -
Marchează argumentele ca obligatorii. Adaugă în
requiredfiecare argument pe care workflow-ul îl citește fără valoare implicită.
Dacă argumentele nu se potrivesc cu schema, mesajul de eroare numește regula și locația valorii greșite:
'type' validation failed, schema requires 'integer': rejected value '4096'
path: ['shots']
O schemă verifică tipul, forma și intervalul fiecărui argument. O schemă nu poate verifica dacă două argumente valide intră în conflict sau dacă un circuit se potrivește unui backend. Păstrează aceste verificări în codul workflow-ului.
Actualizează sau elimină o schemă
-
Pentru a înlocui schema, setează un nou
arguments_schemași încarcă din nou workflow-ul. -
Pentru a elimina schema, încarcă workflow-ul cu
arguments_schema={}. -
Dacă încarci workflow-ul fără
arguments_schema, workflow-ul păstrează schema stocată.
Pentru a vedea schema aflată în vigoare, citește my_workflow.arguments_schema. O valoare None înseamnă că workflow-ul nu are schemă.
Verifică argumentele înainte de rulare
Apelează validate_arguments() pentru a verifica un set de argumente în raport cu schema, fără a porni un job:
run_workflow_remotely.ipynb
my_workflow.validate_arguments({"circuits": [circuit], "shots": 1024})
# {'valid': True}
Dacă argumentele nu sunt valide, validate_arguments() ridică o QiskitServerlessException cu același mesaj pe care run() îl returnează pentru acele argumente. Dacă workflow-ul nu are schemă, orice argumente sunt valide. Un rezultat valid nu garantează că run() reușește, deoarece run() verifică și alte limite, precum numărul de joburi active.
Reguli pentru schemă
Un workflow gestionat respinge încărcarea dacă schema încalcă oricare dintre următoarele reguli:
-
Schema poate avea până la 64 KiB, cu până la 64 de niveluri de imbricare și până la 200 de subscheme.
-
Referințele trebuie să indice în interiorul aceleiași scheme, precum
#/$defs/circuit, iar fiecare referință trebuie să se rezolve. Referințele la URL-uri sau fișiere nu sunt permise. -
Schema trebuie să fie un obiect sau un boolean.
Evită și următoarele probleme, pe care încărcarea nu le detectează:
-
Cuantificatori imbricați în
pattern. Un tipar precum^(a+)+$poate dura foarte mult la evaluare. Un workflow oprește validarea după o limită de timp CPU și respinge rularea. Scrie tipare fără cuantificator în jurul unui grup care conține deja unul, precum^ibm_[a-z0-9_]{1,40}$. -
falseca schemă. Schemafalserespinge fiecare rulare. Pentru a elimina validarea, folosește{}.
Depanează o schemă
| Problemă | Cauză |
|---|---|
| Fiecare rulare este respinsă pe un argument de tip circuit. | Schema descrie circuitul ca șir sau tablou. Descrie-l ca obiect cu o etichetă __type__. |
| Rulări valide sunt respinse. | additionalProperties este false, iar schema nu declară un argument pe care îl transmite rularea. path din eroare numește argumentul. |
| Rulări invalide nu sunt respinse. | Workflow-ul nu are schemă. Verifică my_workflow.arguments_schema. |
| Nicio rulare nu este verificată, deși ai setat o schemă. | Schema a fost transmisă ca șir JSON. Transmite un dicționar. |
Încărcarea eșuează cu o eroare 400. | Schema încalcă una dintre regulile pentru schemă. |
| Eroarea spune că validarea a durat prea mult timp CPU. | Un pattern are cuantificatori imbricați. Rescrie tiparul. |