入力と出力の定義
マネージド・ワークフローは、リモートのコンピュート上で実行される Python 関数のように動作します。ローカル関数と、同じコードをワークフローにしたものを比較します。
Local Python
def my_workflow(circuits, shots=4096):
...
return {"counts": counts}
result = my_workflow(circuits=circuits, shots=1024)
マネージド・ワークフローでは、run() が呼び出し、get_arguments() がワークフローにパラメーターを渡し、save_result() がその return 文に相当します。ワークフローはリモートのコンピュート上で別のジョブとして実行されるため、ローカル関数の呼び出しとは次の3点で異なります。
-
クライアントが引数と結果をエンコードします。 各値は、クライアントがエンコードできるものでなければならず、一部の型は変化します。ワークフローでの引数の読み取りを参照してください。
-
呼び出しは待機しません。
run()はジョブをすぐに返し、結果は後でjob.result()で読み取ります。結果の保存を参照してください。 -
呼び出しは何もチェックされません。 Python 関数は未知のキーワード引数を拒否しますが、ワークフローはスキーマを添付しない限りそれを無視します。ベストプラクティス:スキーマで引数を検証するを参照してください。
ワークフローでの引数の読み取り
ローカルのノートブックから、ワークフローに入力を渡します。
run_workflow_remotely.ipynb
job = my_workflow.run(circuits=circuits, shots=1024)
これを有効にするには、ワークフローのコードを編集し、get_arguments() で引数を取得します。これは、引数名をキーとする辞書を返します。
source_files/my_workflow.py
from qiskit_serverless import get_arguments
arguments = get_arguments()
circuits = arguments["circuits"]
shots = arguments.get("shots", 4096)
辞書には、実行時に渡された引数のみが含まれます。そのため、オプションの引数には、デフォルト値を指定して arguments.get() を使用してください。保護されたキーワード config と function_size を除き、任意の引数名を使用できます。run() がこれらのキーワードを直接使用するためです。run() は compute_profile も拒否します。コンピュートリソースを選択するには、function_size を渡します。
ジョブが実行されるサイズを読み取るには、ワークフローのコードで get_function_size() を呼び出します。
source_files/my_workflow.py
from qiskit_serverless import get_function_size
size = get_function_size() # For example, "M"
実行時に function_size を渡さない場合、get_function_size() はワークフローのデフォルトのサイズを返します。実行ごとのサイズの選択を参照してください。
サポートされている引数の型
各値は、JSON シリアライズ可能であるか、Qiskit の回路や NumPy 配列など、クライアントがエンコードできるオブジェクトでなければなりません。クライアントはジョブを送信する前に各引数をエンコードし、get_arguments() がワークフロー内でそれをデコードするため、ワークフローは元の Python オブジェクトを受け取ります。
クライアントは、int、float、str、bool、None、およびこれらのリストや辞書を、そのまま送信します。QuantumCircuit、numpy.ndarray、complex 数などの他のオブジェクトは、__type__ タグと __value__ を持つ辞書としてエンコードします。引数スキーマを作成する際には、この形式が必要です。
JSON には一部の型に相当するものがないため、これらの型はエンコード時に変化します。タプルはリストとして、辞書のキーは文字列として、np.int64 などの NumPy 整数は int として届きます。bytes や np.float32 など、クライアントが値をエンコードできない場合、run() は TypeError を発生させ、ジョブを作成しません。
一部のオブジェクトは引数として渡せません。たとえば、バックエンドは Backend オブジェクトではなく、その名前を文字列として渡し、ワークフロー内でバックエンドを作成します。ワークフローから量子ジョブを実行するを参照してください。
サイズの上限
1回の実行の引数は、エンコード後に最大 32 MB までです。たとえば、深さ 100 の100量子ビット回路1つは約 39 KB にエンコードされるため、1回の実行で約800個のそのような回路のバッチを処理できます。より大きな入力については、ファイルをアップロードし、そのファイル名を引数として渡してください。
結果の保存
ワークフローの最後に save_result() を使用して、ノートブックに結果を返します。ノートブックでは job.result() で結果を読み取ります。
run_workflow_remotely.ipynb
result = job.result()
これを有効にするには、ワークフローのコードで save_result() を呼び出します。
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() は、クライアントが引数をエンコードするのと同じ方法で結果をエンコードし、job.result() がそれをデコードします。したがって、結果には、回路、NumPy 配列、プリミティブジョブの結果など、サポートされている引数の型を含めることができ、同じ型の変化が生じます。
-
戻り値を確認してください。
save_result()が値をエンコードできない場合、エラーを発生させる代わりに、警告をログに記録してFalseを返します。確認しないと、ジョブが結果なしでDONEステータスで終了することがあります。 -
最後の
save_result()のみが保存されます。 呼び出しのたびに、保存された結果が置き換えられます。複数の値を返すには、1つの辞書にまとめて保存するか、ログに書き込んでください。 -
空の辞書は結果がないことを意味します。 ワークフローが
save_result()を一度も呼び出さない場合、job.result()は{}を返します。
大きな配列やプロットなどのファイルを返すには、それらをファイルストレージに保存し、結果にその名前を含めて返します。
ベストプラクティス:スキーマで引数を検証する
ベストプラクティスとして、引数を受け取るすべてのワークフローに JSON Schema を添付してください。スキーマはワークフローが受け付ける引数を記述し、ワークフローはジョブを作成する前に、実行ごとの引数をそれに照らして確認します。引数が一致しない場合、run() は不正なフィールドを示すエラーですぐに失敗し、ワークフローはジョブを作成しません。スキーマがないと、不正な引数はジョブの開始後にワークフローに到達し、ワークフローは誤ったスペルの引数名を無視します。
ワークフローをアップロードするときに、arguments_schema でスキーマを設定します。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,
)
)
スキーマを作成する際は、次の点に注意してください。
-
Qiskit と NumPy のオブジェクトのエンコード後の形式を記述してください。 スキーマは、クライアントが送信する形式で引数を確認します。そのため、回路は文字列や配列ではなく、
{"__type__": "QuantumCircuit", "__value__": "<base64-encoded QPY>"}のようなオブジェクトです。__type__タグを確認し、__value__は不透明な文字列として扱ってください。回路を文字列として記述するスキーマは、有効な実行をすべて拒否します。 -
"additionalProperties": falseを設定してください。 この設定がないと、ワークフローはshotzのような誤ったスペルの引数名を警告なしで無視し、デフォルト値で実行します。この設定を有効にする前に、ワークフローが受け付けるすべての引数を宣言してください。 -
引数を必須に設定してください。 ワークフローがデフォルト値なしで読み取る各引数を、
requiredに追加します。
引数がスキーマと一致しない場合、エラーメッセージには、違反したルールと不正な値の場所が示されます。
'type' validation failed, schema requires 'integer': rejected value '4096'
path: ['shots']
スキーマは、各引数の型、形状、範囲を確認します。2つの有効な引数が競合するかどうか、または回路がバックエンドに適合するかどうかは、スキーマでは確認できません。これらの確認は、ワークフローのコードで行ってください。
スキーマの更新または削除
-
スキーマを置き換えるには、新しい
arguments_schemaを設定して、ワークフローを再度アップロードします。 -
スキーマを削除するには、
arguments_schema={}を指定してワークフローをアップロードします。 -
arguments_schemaを指定せずにワークフローをアップロードした場合、ワークフローは保存済みのスキーマを保持します。
有効なスキーマを確認するには、my_workflow.arguments_schema を読み取ります。値が None の場合、ワークフローにスキーマがないことを意味します。
実行前の引数の確認
validate_arguments() を呼び出すと、ジョブを開始せずに、一連の引数をスキーマに照らして確認できます。
run_workflow_remotely.ipynb
my_workflow.validate_arguments({"circuits": [circuit], "shots": 1024})
# {'valid': True}
引数が有効でない場合、validate_arguments() は、その引数に対して run() が返すのと同じメッセージの QiskitServerlessException を発生させます。ワークフローにスキーマがない場合、どの引数も有効です。run() はアクティブなジョブの数などの他の制限も確認するため、有効という結果が run() の成功を保証するものではありません。
スキーマのルール
スキーマが次のいずれかのルールに違反する場合、マネージド・ワークフローはアップロードを拒否します。
-
スキーマは最大 64 KiB、ネストは最大64レベル、サブスキーマは最大200個までです。
-
参照は、
#/$defs/circuitのように同じスキーマ内を指す必要があり、すべての参照が解決できなければなりません。URL やファイルへの参照は使用できません。 -
スキーマは、オブジェクトまたはブール値でなければなりません。
また、アップロード時には検出されない次の問題も避けてください。
-
pattern内のネストされた量指定子。^(a+)+$のようなパターンは、評価に非常に長い時間がかかることがあります。ワークフローは、CPU 時間の上限を超えると検証を停止し、その実行を拒否します。^ibm_[a-z0-9_]{1,40}$のように、すでに量指定子を含むグループの周りに量指定子を付けないパターンを書いてください。 -
スキーマとしての
false。 スキーマfalseは、すべての実行を拒否します。検証を無効にするには、{}を使用します。
スキーマのトラブルシューティング
| 問題 | 原因 |
|---|---|
| 回路の引数で、すべての実行が拒否される。 | スキーマが回路を文字列または配列として記述しています。__type__ タグを持つオブジェクトとして記述してください。 |
| 有効な実行が拒否される。 | additionalProperties が false で、スキーマが実行で渡される引数を宣言していません。エラーの path が引数を示します。 |
| 無効な実行が拒否されない。 | ワークフローにスキーマがありません。my_workflow.arguments_schema を確認してください。 |
| スキーマを設定したのに、どの実行も確認されない。 | スキーマが JSON 文字列として渡されました。辞書を渡してください。 |
アップロードが 400 エラーで失敗する。 | スキーマがスキーマのルールのいずれかに違反しています。 |
| 検証に CPU 時間がかかりすぎたというエラーが出る。 | pattern にネストされた量指定子があります。パターンを書き直してください。 |