Aller au contenu principal
Ce projet est en phase bêta. Tu as trouvé un bug ? Ouvrir un ticket GitHub. Une question ou une idée ? Pose ta question dans Discussions — tes retours sont les bienvenus !
Quelle est la qualité de la traduction sur cette page ?

Définir les entrées et les sorties

Un workflow géré fonctionne comme une fonction Python qui s'exécute sur du calcul distant. Compare une fonction locale avec le même code sous forme de workflow :

Local Python

def my_workflow(circuits, shots=4096):
...
return {"counts": counts}

result = my_workflow(circuits=circuits, shots=1024)

Dans un workflow géré, run() est l'appel, get_arguments() donne ses paramètres au workflow, et save_result() est son instruction return. Comme le workflow s'exécute comme un job séparé sur du calcul distant, il diffère d'un appel de fonction local de trois façons :

Your local notebook, run_workflow_remotely.ipynb, calls run(args). A workflow runs an optional schema check, then creates the managed workflow job, source_files/my_workflow.py. The job reads its arguments with get_arguments(), runs your code, such as mapping, transpiling circuits, running primitives, and post-processing, and returns a result with save_result(). A workflow stores the result, and your notebook reads it with job.result().

Lire les arguments dans ton workflow​

Passe des entrées à ton workflow depuis ton notebook local :

run_workflow_remotely.ipynb

job = my_workflow.run(circuits=circuits, shots=1024)

Pour activer cela, modifie le code de ton workflow afin de récupérer les arguments avec get_arguments(), qui renvoie un dictionnaire dont les clés sont les noms des arguments :

source_files/my_workflow.py

from qiskit_serverless import get_arguments

arguments = get_arguments()
circuits = arguments["circuits"]
shots = arguments.get("shots", 4096)

Le dictionnaire ne contient que les arguments que l'exécution a passés ; utilise donc arguments.get() avec une valeur par défaut pour les arguments facultatifs. Tu peux utiliser n'importe quel nom d'argument, sauf les mots-clés protégés config et function_size, car run() utilise directement ces mots-clés. run() rejette aussi compute_profile. Pour choisir les ressources de calcul, passe function_size.

Pour lire la taille à laquelle le job s'exécute, appelle get_function_size() dans le code de ton workflow :

source_files/my_workflow.py

from qiskit_serverless import get_function_size

size = get_function_size() # For example, "M"

Si l'exécution ne passe pas function_size, get_function_size() renvoie la taille par défaut du workflow. Consulte Choisir une taille pour chaque exécution.

Types d'arguments pris en charge​

Chaque valeur doit être sérialisable en JSON, ou être un objet que le client peut encoder, comme un circuit Qiskit ou un tableau NumPy. Comme le client encode chaque argument avant d'envoyer le job et que get_arguments() le décode dans le workflow, le workflow reçoit l'objet Python d'origine.

Le client envoie int, float, str, bool, None, ainsi que les listes ou dictionnaires de ces types, sans modification. Il encode les autres objets, comme un QuantumCircuit, un numpy.ndarray ou un nombre complex, sous forme d'un dictionnaire avec une balise __type__ et une __value__. Tu as besoin de cette forme lorsque tu écris un schéma d'arguments.

Comme JSON n'a pas d'équivalent pour certains types, ces types changent pendant l'encodage. Les tuples arrivent sous forme de listes, les clés de dictionnaire arrivent sous forme de chaînes, et les entiers NumPy comme np.int64 arrivent sous forme de int. Si le client ne peut pas encoder une valeur, comme bytes ou np.float32, run() lève une TypeError et ne crée pas de job.

Certains objets ne peuvent pas être passés en argument. Par exemple, passe le nom d'un backend sous forme de chaîne plutôt qu'un objet Backend, et crée le backend dans le workflow. Consulte Exécuter des jobs quantiques depuis un workflow.

Limites de taille​

Les arguments d'une exécution peuvent atteindre 32 Mo après encodage. Par exemple, un circuit de 100 qubits avec une profondeur de 100 s'encode en environ 39 Ko, donc une seule exécution peut prendre un lot d'environ 800 circuits de ce type. Pour des entrées plus volumineuses, téléverse un fichier et passe son nom en argument.

Enregistrer les résultats​

Utilise save_result() à la fin de ton workflow pour renvoyer un résultat à ton notebook. Lis le résultat dans ton notebook avec job.result() :

run_workflow_remotely.ipynb

result = job.result()

Pour activer cela, appelle save_result() dans le code de ton 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() encode le résultat de la même façon que le client encode les arguments, et job.result() le décode. Un résultat peut donc contenir les types d'arguments pris en charge, comme des circuits, des tableaux NumPy et le résultat d'un job de primitive, avec les mêmes changements de type.

  • Vérifie la valeur de retour. Si save_result() ne peut pas encoder la valeur, il journalise un avertissement et renvoie False au lieu de lever une erreur. Sans vérification, le job peut se terminer avec le statut DONE et sans résultat.

  • Seul le dernier save_result() est stocké. Chaque appel remplace le résultat enregistré. Pour renvoyer plusieurs valeurs, enregistre-les dans un seul dictionnaire, ou écris-les dans les logs.

  • Un dictionnaire vide signifie aucun résultat. Si le workflow n'appelle jamais save_result(), job.result() renvoie {}.

Pour renvoyer des fichiers, comme de grands tableaux ou des graphiques, enregistre-les dans le stockage de fichiers et renvoie leurs noms dans le résultat.

Bonne pratique : valider les arguments avec un schéma​

Par bonne pratique, associe un JSON Schema à chaque workflow qui prend des arguments. Le schéma décrit les arguments que le workflow accepte, et le workflow vérifie les arguments de chaque exécution par rapport à lui avant de créer le job. Si les arguments ne correspondent pas, run() échoue immédiatement avec une erreur qui nomme le champ incorrect, et le workflow ne crée pas de job. Sans schéma, les arguments incorrects atteignent le workflow après le démarrage du job, et le workflow ignore un nom d'argument mal orthographié.

Définis le schéma avec arguments_schema lorsque tu téléverses le workflow. Passe un dictionnaire, pas une chaîne 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,
)
)

Garde les points suivants à l'esprit lorsque tu écris un schéma :

  • Décris la forme encodée des objets Qiskit et NumPy. Le schéma vérifie les arguments tels que le client les envoie, donc un circuit est un objet tel que {"__type__": "QuantumCircuit", "__value__": "<base64-encoded QPY>"}, et non une chaîne ou un tableau. Vérifie la balise __type__, et traite __value__ comme une chaîne opaque. Un schéma qui décrit un circuit comme une chaîne rejette toutes les exécutions valides.

  • Définis "additionalProperties": false. Sans ce paramètre, le workflow ignore sans avertissement un nom d'argument mal orthographié, comme shotz, et s'exécute avec sa valeur par défaut. Déclare chaque argument que le workflow accepte avant d'activer ce paramètre.

  • Marque les arguments comme obligatoires. Ajoute à required chaque argument que le workflow lit sans valeur par défaut.

Si les arguments ne correspondent pas au schéma, le message d'erreur nomme la règle et l'emplacement de la valeur incorrecte :

'type' validation failed, schema requires 'integer': rejected value '4096'
path: ['shots']

Un schéma vérifie le type, la forme et la plage de chaque argument. Un schéma ne peut pas vérifier si deux arguments valides entrent en conflit, ni si un circuit convient à un backend. Garde ces vérifications dans le code du workflow.

Mettre à jour ou supprimer un schéma​

  • Pour remplacer le schéma, définis un nouveau arguments_schema et téléverse à nouveau le workflow.

  • Pour supprimer le schéma, téléverse le workflow avec arguments_schema={}.

  • Si tu téléverses le workflow sans arguments_schema, le workflow conserve le schéma stocké.

Pour voir le schéma en vigueur, lis my_workflow.arguments_schema. Une valeur None signifie que le workflow n'a pas de schéma.

Vérifier les arguments avant d'exécuter​

Appelle validate_arguments() pour vérifier un ensemble d'arguments par rapport au schéma sans démarrer de job :

run_workflow_remotely.ipynb

my_workflow.validate_arguments({"circuits": [circuit], "shots": 1024})
# {'valid': True}

Si les arguments ne sont pas valides, validate_arguments() lève une QiskitServerlessException avec le même message que celui que run() renvoie pour ces arguments. Si le workflow n'a pas de schéma, tous les arguments sont valides. Un résultat valide ne garantit pas que run() réussisse, car run() vérifie aussi d'autres limites, comme le nombre de jobs actifs.

Règles du schéma​

Un workflow géré rejette le téléversement si le schéma enfreint l'une des règles suivantes :

  • Le schéma peut atteindre 64 Kio, avec jusqu'à 64 niveaux d'imbrication et jusqu'à 200 sous-schémas.

  • Les références doivent pointer à l'intérieur du même schéma, comme #/$defs/circuit, et chaque référence doit pouvoir être résolue. Les références à des URL ou à des fichiers ne sont pas autorisées.

  • Le schéma doit être un objet ou un booléen.

Évite aussi les problèmes suivants, que le téléversement ne détecte pas :

  • Quantificateurs imbriqués dans pattern. Un motif comme ^(a+)+$ peut prendre très longtemps à être évalué. Un workflow arrête la validation après une limite de temps CPU et rejette l'exécution. Écris des motifs sans quantificateur autour d'un groupe qui en contient déjà un, comme ^ibm_[a-z0-9_]{1,40}$.

  • false comme schéma. Le schéma false rejette toutes les exécutions. Pour supprimer la validation, utilise {}.

Dépanner un schéma​

ProblèmeCause
Toutes les exécutions sont rejetées sur un argument de circuit.Le schéma décrit le circuit comme une chaîne ou un tableau. Décris-le comme un objet avec une balise __type__.
Des exécutions valides sont rejetées.additionalProperties vaut false, et le schéma ne déclare pas un argument que l'exécution passe. Le path de l'erreur nomme l'argument.
Des exécutions invalides ne sont pas rejetées.Le workflow n'a pas de schéma. Vérifie my_workflow.arguments_schema.
Aucune exécution n'est vérifiée, bien que tu aies défini un schéma.Le schéma a été passé sous forme de chaîne JSON. Passe un dictionnaire.
Le téléversement échoue avec une erreur 400.Le schéma enfreint l'une des règles du schéma.
L'erreur indique que la validation a pris trop de temps CPU.Un pattern a des quantificateurs imbriqués. Réécris le motif.