Ein- und Ausgaben definieren
Ein verwalteter Workflow funktioniert wie eine Python-Funktion, die auf Remote-Rechenressourcen läuft. Vergleiche eine lokale Funktion mit demselben Code als Workflow:
Local Python
def my_workflow(circuits, shots=4096):
...
return {"counts": counts}
result = my_workflow(circuits=circuits, shots=1024)
In einem verwalteten Workflow ist run() der Aufruf, get_arguments() liefert dem Workflow seine Parameter, und save_result() ist sein return-Statement. Da der Workflow als separater Job auf Remote-Rechenressourcen läuft, unterscheidet er sich in drei Punkten von einem lokalen Funktionsaufruf:
-
Der Client kodiert Argumente und Ergebnisse. Jeder Wert muss einer sein, den der Client kodieren kann, und manche Typen ändern sich. Siehe Argumente in deinem Workflow lesen.
-
Der Aufruf wartet nicht.
run()gibt sofort einen Job zurück, und das Ergebnis liest du später mitjob.result(). Siehe Ergebnisse speichern. -
Nichts prüft den Aufruf. Eine Python-Funktion weist ein unbekanntes Schlüsselwortargument zurück, ein Workflow ignoriert es jedoch, solange du kein Schema anhängst. Siehe Best Practice: Argumente mit einem Schema validieren.
Argumente in deinem Workflow lesen
Übergib Eingaben aus deinem lokalen Notebook an deinen Workflow:
run_workflow_remotely.ipynb
job = my_workflow.run(circuits=circuits, shots=1024)
Damit das funktioniert, bearbeite den Code deines Workflows so, dass er Argumente mit get_arguments() abruft, das ein Dictionary zurückgibt, dessen Schlüssel die Argumentnamen sind:
source_files/my_workflow.py
from qiskit_serverless import get_arguments
arguments = get_arguments()
circuits = arguments["circuits"]
shots = arguments.get("shots", 4096)
Das Dictionary enthält nur die Argumente, die der Lauf übergeben hat. Verwende daher für optionale Argumente arguments.get() mit einem Standardwert. Du kannst jeden Argumentnamen verwenden, außer den geschützten Schlüsselwörtern config und function_size, da run() diese Schlüsselwörter direkt verwendet. run() weist außerdem compute_profile zurück. Um Rechenressourcen auszuwählen, übergib function_size.
Um die Größe zu lesen, mit der der Job läuft, rufe get_function_size() im Code deines Workflows auf:
source_files/my_workflow.py
from qiskit_serverless import get_function_size
size = get_function_size() # For example, "M"
Wenn der Lauf function_size nicht übergibt, gibt get_function_size() die Standardgröße des Workflows zurück. Siehe Eine Größe für jeden Lauf wählen.
Unterstützte Argumenttypen
Jeder Wert muss JSON-serialisierbar sein oder ein Objekt, das der Client kodieren kann, etwa ein Qiskit-Circuit oder ein NumPy-Array. Da der Client jedes Argument kodiert, bevor er den Job sendet, und get_arguments() es im Workflow dekodiert, erhält der Workflow das ursprüngliche Python-Objekt.
Der Client sendet int, float, str, bool, None sowie Listen oder Dictionaries davon unverändert. Andere Objekte, etwa ein QuantumCircuit, ein numpy.ndarray oder eine complex-Zahl, kodiert er als Dictionary mit einem __type__-Tag und einem __value__. Diese Form brauchst du, wenn du ein Argumentschema schreibst.
Da JSON für manche Typen keine Entsprechung hat, ändern sich diese Typen bei der Kodierung. Tupel kommen als Listen an, Dictionary-Schlüssel kommen als Strings an, und NumPy-Ganzzahlen wie np.int64 kommen als int an. Wenn der Client einen Wert nicht kodieren kann, etwa bytes oder np.float32, löst run() einen TypeError aus und erstellt keinen Job.
Manche Objekte können nicht als Argumente übergeben werden. Übergib zum Beispiel den Namen eines Backends als String statt eines Backend-Objekts, und erstelle das Backend innerhalb des Workflows. Siehe Quantenjobs aus einem Workflow ausführen.
Größenbeschränkungen
Die Argumente eines Laufs dürfen nach der Kodierung bis zu 32 MB groß sein. Ein Circuit mit 100 Qubits und einer Tiefe von 100 wird zum Beispiel auf etwa 39 KB kodiert, sodass ein einzelner Lauf einen Batch von etwa 800 solcher Circuits aufnehmen kann. Für größere Eingaben lade eine Datei hoch und übergib ihren Namen als Argument.
Ergebnisse speichern
Verwende save_result() am Ende deines Workflows, um ein Ergebnis an dein Notebook zurückzugeben. Lies das Ergebnis in deinem Notebook mit job.result():
run_workflow_remotely.ipynb
result = job.result()
Damit das funktioniert, rufe save_result() im Code deines Workflows auf:
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() kodiert das Ergebnis auf dieselbe Weise, wie der Client Argumente kodiert, und job.result() dekodiert es. Ein Ergebnis kann daher die unterstützten Argumenttypen enthalten, etwa Circuits, NumPy-Arrays und das Ergebnis eines Primitive-Jobs, mit denselben Typänderungen.
-
Prüfe den Rückgabewert. Wenn
save_result()den Wert nicht kodieren kann, protokolliert es eine Warnung und gibtFalsezurück, statt einen Fehler auszulösen. Ohne Prüfung kann der Job mit dem StatusDONEund ohne Ergebnis enden. -
Nur das letzte
save_result()wird gespeichert. Jeder Aufruf ersetzt das gespeicherte Ergebnis. Um mehrere Werte zurückzugeben, speichere sie in einem Dictionary oder schreibe sie in die Logs. -
Ein leeres Dictionary bedeutet kein Ergebnis. Wenn der Workflow
save_result()nie aufruft, gibtjob.result(){}zurück.
Um Dateien zurückzugeben, etwa große Arrays oder Plots, speichere sie im Dateispeicher und gib ihre Namen im Ergebnis zurück.
Best Practice: Argumente mit einem Schema validieren
Als Best Practice hängst du an jeden Workflow, der Argumente entgegennimmt, ein JSON Schema an. Das Schema beschreibt die Argumente, die der Workflow akzeptiert, und der Workflow prüft die Argumente jedes Laufs dagegen, bevor er den Job erstellt. Wenn die Argumente nicht passen, schlägt run() sofort mit einem Fehler fehl, der das fehlerhafte Feld nennt, und der Workflow erstellt keinen Job. Ohne Schema erreichen fehlerhafte Argumente den Workflow erst, nachdem der Job gestartet ist, und der Workflow ignoriert einen falsch geschriebenen Argumentnamen.
Setze das Schema mit arguments_schema, wenn du den Workflow hochlädst. Übergib ein Dictionary, keinen JSON-String:
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,
)
)
Beachte beim Schreiben eines Schemas die folgenden Punkte:
-
Beschreibe die kodierte Form von Qiskit- und NumPy-Objekten. Das Schema prüft die Argumente so, wie der Client sie sendet. Ein Circuit ist daher ein Objekt wie
{"__type__": "QuantumCircuit", "__value__": "<base64-encoded QPY>"}, kein String und kein Array. Prüfe das__type__-Tag und behandle__value__als undurchsichtigen String. Ein Schema, das einen Circuit als String beschreibt, weist jeden gültigen Lauf zurück. -
Setze
"additionalProperties": false. Ohne diese Einstellung ignoriert der Workflow einen falsch geschriebenen Argumentnamen, wieshotz, ohne Warnung und läuft mit seinem Standardwert. Deklariere jedes Argument, das der Workflow akzeptiert, bevor du diese Einstellung aktivierst. -
Markiere Argumente als erforderlich. Füge jedes Argument, das der Workflow ohne Standardwert liest, zu
requiredhinzu.
Wenn die Argumente nicht zum Schema passen, nennt die Fehlermeldung die Regel und die Stelle des fehlerhaften Werts:
'type' validation failed, schema requires 'integer': rejected value '4096'
path: ['shots']
Ein Schema prüft Typ, Form und Bereich jedes Arguments. Ein Schema kann nicht prüfen, ob zwei gültige Argumente einander widersprechen oder ob ein Circuit auf ein Backend passt. Behalte diese Prüfungen im Workflow-Code.
Ein Schema aktualisieren oder entfernen
-
Um das Schema zu ersetzen, setze ein neues
arguments_schemaund lade den Workflow erneut hoch. -
Um das Schema zu entfernen, lade den Workflow mit
arguments_schema={}hoch. -
Wenn du den Workflow ohne
arguments_schemahochlädst, behält der Workflow das gespeicherte Schema.
Um das gültige Schema zu sehen, lies my_workflow.arguments_schema. Der Wert None bedeutet, dass der Workflow kein Schema hat.
Argumente vor dem Ausführen prüfen
Rufe validate_arguments() auf, um eine Menge von Argumenten gegen das Schema zu prüfen, ohne einen Job zu starten:
run_workflow_remotely.ipynb
my_workflow.validate_arguments({"circuits": [circuit], "shots": 1024})
# {'valid': True}
Wenn die Argumente nicht gültig sind, löst validate_arguments() eine QiskitServerlessException mit derselben Meldung aus, die run() für diese Argumente zurückgibt. Wenn der Workflow kein Schema hat, sind beliebige Argumente gültig. Ein gültiges Ergebnis garantiert nicht, dass run() erfolgreich ist, denn run() prüft auch andere Limits, etwa die Anzahl aktiver Jobs.
Schemaregeln
Ein verwalteter Workflow lehnt den Upload ab, wenn das Schema eine der folgenden Regeln verletzt:
-
Das Schema darf bis zu 64 KiB groß sein, mit bis zu 64 Verschachtelungsebenen und bis zu 200 Teilschemas.
-
Referenzen müssen innerhalb desselben Schemas liegen, etwa
#/$defs/circuit, und jede Referenz muss sich auflösen lassen. Referenzen auf URLs oder Dateien sind nicht erlaubt. -
Das Schema muss ein Objekt oder ein Boolean sein.
Vermeide außerdem die folgenden Probleme, die der Upload nicht erkennt:
-
Verschachtelte Quantifizierer in
pattern. Ein Muster wie^(a+)+$kann sehr lange zur Auswertung brauchen. Ein Workflow beendet die Validierung nach einem CPU-Zeitlimit und weist den Lauf zurück. Schreibe Muster ohne Quantifizierer um eine Gruppe, die bereits einen enthält, etwa^ibm_[a-z0-9_]{1,40}$. -
falseals Schema. Das Schemafalseweist jeden Lauf zurück. Um die Validierung zu entfernen, verwende{}.
Ein Schema beheben
| Problem | Ursache |
|---|---|
| Jeder Lauf wird wegen eines Circuit-Arguments zurückgewiesen. | Das Schema beschreibt den Circuit als String oder Array. Beschreibe ihn als Objekt mit einem __type__-Tag. |
| Gültige Läufe werden zurückgewiesen. | additionalProperties ist false, und das Schema deklariert ein Argument nicht, das der Lauf übergibt. Der Fehler-path nennt das Argument. |
| Ungültige Läufe werden nicht zurückgewiesen. | Der Workflow hat kein Schema. Prüfe my_workflow.arguments_schema. |
| Kein Lauf wird geprüft, obwohl du ein Schema gesetzt hast. | Das Schema wurde als JSON-String übergeben. Übergib ein Dictionary. |
Der Upload schlägt mit einem 400-Fehler fehl. | Das Schema verletzt eine der Schemaregeln. |
| Der Fehler besagt, dass die Validierung zu viel CPU-Zeit benötigt hat. | Ein pattern hat verschachtelte Quantifizierer. Schreibe das Muster um. |