הרצת jobs קוונטיים מתוך workflow
גרסאות חבילות
הקוד בדף הזה פותח לפי הדרישות הבאות. מומלץ להשתמש בגרסאות האלה או בחדשות יותר.
qiskit[all]~=2.6.1
qiskit-ibm-runtime~=0.51.0
qiskit-serverless~=0.38.0
workflow קוונטי-קלאסי רץ כ-job אחד של managed workflow. השלבים הקלאסיים שלו רצים על ה-compute profile שלכם, וה-jobs של primitives שהוא שולח ל-QPU של IBM Quantum® רצים על ה-instance שלכם ונספרים בשימוש שלכם. מתוך ה-job האחד הזה אפשר לדווח על כל שלב, למצוא את ה-jobs של QPU ולבטל אותם. כדי להתחיל job ולבדוק את הסטטוס וה-logs שלו, ראו הרצת managed workflow.
לפני שמתחילים, פרסו את ה-managed workflow הראשון שלכם.
יצירת שירות Runtime
צרו את שירות Runtime בקוד ה-workflow שלכם באמצעות get_runtime_service(), והשתמשו בו באותו אופן שבו אתם משתמשים ב-QiskitRuntimeService מקומית. ה-workflow הבא מריץ circuit של Bell עם ה-primitive מסוג Sampler, מדווח על כל שלב באמצעות update_status(), ומחזיר את הספירות:
# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util
_needed = {"qiskit": "qiskit", "qiskit_ibm_catalog": "qiskit-ibm-catalog", "qiskit_ibm_runtime": "qiskit-ibm-runtime", "qiskit_serverless": "qiskit-serverless"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
# This cell is hidden from users. It creates the working directory.
from pathlib import Path
Path("./source_files").mkdir(exist_ok=True)
%%writefile ./source_files/my_workflow.py
from qiskit import QuantumCircuit
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime.executor_sampler import Sampler
from qiskit_serverless import (
Job,
get_arguments,
get_runtime_service,
save_result,
update_status,
)
arguments = get_arguments()
service = get_runtime_service()
backend = service.backend(arguments["backend_name"])
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.cx(0, 1)
circuit.measure_all()
update_status(Job.OPTIMIZING_HARDWARE)
pass_manager = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_circuit = pass_manager.run(circuit)
update_status(Job.WAITING_QPU)
sampler = Sampler(mode=backend)
primitive_job = sampler.run([isa_circuit])
counts = primitive_job.result()[0].data.meas.get_counts()
update_status(Job.POST_PROCESSING)
save_result({"backend": backend.name, "counts": counts})
Overwriting ./source_files/my_workflow.py
get_runtime_service() מחזירה QiskitRuntimeService שמוגדר ל-job של ה-managed workflow שלכם, והיא מספקת את הדברים הבאים:
-
אישורי גישה. שירות Runtime משתמש במפתח ה-API, ב-instance ובערוץ שבהם קראתם ל-
run(), ולכן קוד ה-workflow לא צריך אישורי גישה. -
מעקב. workflow רושם כל job של primitive שרץ דרך שירות Runtime הזה תחת ה-job של ה-managed workflow, כולל jobs של Sampler, Estimator ו-Executor, וכן jobs ב-session או ב-batch. אפשר לרשום אותם באמצעות
job.runtime_jobs(). -
ביטול. כשקוראים ל-
job.cancel(), ה-managed workflow מבטל גם את ה-sessions, ה-batches וה-jobs של primitives של ה-workflow שעדיין רצים.
managed workflow לא עוקב אחרי ה-jobs של שירות שיוצרים באמצעות QiskitRuntimeService() ולא מבטל אותם, אף על פי שה-jobs ממשיכים לרוץ. אם ה-workflow חייב להשתמש בשירות אחר, בטלו את ה-jobs שלו ב-handler של SIGTERM.
הרצת primitives ב-session או ב-batch
managed workflow עוקב גם אחרי jobs של primitives שרצים ב-session או ב-batch. צרו את ה-session או ה-batch מ-backend ששירות Runtime החזיר, וצרו את ה-primitives בתוך בלוק ה-with. Session עובד באותו אופן:
source_files/my_workflow.py
from qiskit_ibm_runtime import Batch
with Batch(backend=backend) as batch:
sampler = Sampler(mode=batch)
primitive_jobs = [sampler.run([isa_circuit]) for _ in range(2)]
results = [primitive_job.result() for primitive_job in primitive_jobs]
דיווח על התקדמות עם update_status()
ה-workflow ב-יצירת שירות Runtime קורא ל-update_status() בתחילת כל שלב, כדי שסטטוס ה-job יראה איפה ה-workflow נמצא, למשל RUNNING: WAITING_FOR_QPU. העבירו אחד מקבועי Job הבאים:
| קריאה ב-workflow | סטטוס ה-job |
|---|---|
update_status(Job.MAPPING) | RUNNING: MAPPING |
update_status(Job.OPTIMIZING_HARDWARE) | RUNNING: OPTIMIZING_FOR_HARDWARE |
update_status(Job.WAITING_QPU) | RUNNING: WAITING_FOR_QPU |
update_status(Job.EXECUTING_QPU) | RUNNING: EXECUTING_QPU |
update_status(Job.POST_PROCESSING) | RUNNING: POST_PROCESSING |
update_status() מחזירה True אם ה-workflow שינה את הסטטוס. היא מחזירה False וכותבת אזהרה ל-logs אם הערך אינו אחד מהקבועים האלה, אם ה-job כבר לא פעיל, או אם הקוד רץ מחוץ ל-job. היא לא מעלה שגיאה, ולכן שגיאת הקלדה לא עוצרת את ה-workflow.
להתקדמות בתוך שלב, כמו האיטרציות של optimizer, כתבו שורות log.
מציאת ה-jobs של QPU בהרצה
במחברת המקומית שלכם, בחרו QPU שה-instance שלכם יכול לגשת אליו. client.backends() מציגה אותם, ו-client.least_busy() מחזירה את זה עם מספר ה-jobs הממתינים הנמוך ביותר:
from qiskit_ibm_catalog import ManagedWorkflowClient
client = ManagedWorkflowClient()
print([backend.name for backend in client.backends(simulator=False)])
backend_name = client.least_busy(operational=True, simulator=False).name
['ibm_boston', 'ibm_fez', 'ibm_kingston', 'ibm_marrakesh', 'ibm_phoenix', 'ibm_pittsburgh']
העלו את ה-workflow, והעבירו את שם ה-backend כשאתם מריצים אותו:
from qiskit_ibm_catalog import ManagedWorkflow
my_workflow = client.upload(
ManagedWorkflow(
title="my-workflow",
entrypoint="my_workflow.py",
working_dir="./source_files/",
)
)
job = my_workflow.run(backend_name=backend_name)
# This cell is hidden from users. It waits for the job to finish.
assert job.wait_for_final_state() == "DONE", job.logs()
אחרי שה-job מסתיים, קבלו את המזהים של ה-jobs של QPU של ה-workflow מה-job של ה-managed workflow:
runtime_job_ids = job.runtime_jobs()
runtime_job_ids
['dbl6lst8ft8s738secf0']
# This cell is hidden from users. It checks the tracked job.
assert len(runtime_job_ids) == 1, runtime_job_ids
כל מזהה הוא מזהה רגיל של job של primitive. כדי לקרוא את הסטטוס והתוצאות של job, ראו אחזור תוצאות job במועד מאוחר יותר.
אם ה-workflow הריץ primitives ב-session או ב-batch, רשמו את מזהי ה-session וה-batch באמצעות runtime_sessions(), והעבירו אחד מהם ל-runtime_jobs() כדי לקבל רק את ה-jobs שבו:
run_workflow_remotely.ipynb
for session_id in job.runtime_sessions():
print(session_id, job.runtime_jobs(session_id))
dc101077-d085-40fb-8fbe-78852e355994 ['dbjqp48nceqs73aki1k0', 'dbjqp4l6p51s73clb91g']
האובייקט job קיים רק במחברת שהתחילה את ההרצה. במחברת חדשה, קבלו את ה-job שוב באמצעות client.job("<your-job-id>"), ואז קראו עליו ל-runtime_jobs(). ראו מציאת job מ-session חדש.
לשימוש ב-QPU ולזמני הריצה של כל job של QPU, ראו הצגת מדדי job. לשימוש של כל ה-instance שלכם בתקופה הנוכחית, קראו ל-client.usage(). כדי לראות כמה זמן לקח כל שלב ב-job של ה-managed workflow, ראו בדיקה כמה זמן לקח כל שלב.
ביטול jobs מקושרים של QPU
כשמבטלים job של managed workflow באמצעות job.cancel(), ה-workflow מנסה לבטל גם את עבודת ה-QPU שה-workflow התחיל:
-
Sessions ו-batches. ה-workflow מבטל כל אחד מה-sessions וה-batches שלו, מה שמבטל גם את ה-jobs שלהם שממתינים בתור.
-
jobs אחרים של primitives. ה-workflow מבטל כל אחד מה-jobs האחרים של primitives שלו שעדיין ממתינים בתור או רצים.
job.cancel() מחזירה הודעה לכל job ו-session של QPU, כך שאפשר לבדוק מה בוטל:
run_workflow_remotely.ipynb
print(job.cancel())
ב-workflow שרץ ב-batch, ההודעה נראית כך:
Job is stopping. Canceled runtime session: eb8874c9-a15e-45f8-9a90-a9fb35267f9d and associated runtime jobs.
אם הלקוח לא יכול ליצור QiskitRuntimeService מאישורי הגישה המקומיים שלכם, הוא מבטל רק את ה-job של ה-managed workflow. בטלו בעצמכם את ה-jobs של QPU לפי המזהים שלהם מ-job.runtime_jobs().
כש-workflow עוצר job בעצמו, למשל כי הגיע למגבלה של 24 שעות, הוא לא מבטל את ה-jobs של QPU שלו. בטלו אותם לפי המזהים שלהם מ-job.runtime_jobs().
פתרון בעיות ב-jobs של QPU ב-workflow
| בעיה | סיבה |
|---|---|
get_runtime_service() מעלה KeyError: 'QISKIT_IBM_CHANNEL'. | הקוד רץ במחברת המקומית שלכם ולא ב-job של managed workflow. השתמשו ב-QiskitRuntimeService() מקומית. |
update_status() מחזירה False, וה-logs מציגים 'sub_status' not provided or is not valid. | הערך אינו אחד מהקבועים של Job, או שה-job כבר לא פעיל. |
job.runtime_jobs() מחזירה []. | ה-workflow יצר את השירות שלו עם QiskitRuntimeService(), או שעדיין לא הריץ primitive. |
| ה-jobs של session לא נמצאים במעקב. | ה-session נוצר מ-backend של שירות אחר. קבלו את ה-backend מ-get_runtime_service(). |
ה-logs של ה-workflow מציגים Could not associate runtime job with serverless job. | ה-workflow לא הצליח לרשום job של primitive. ה-job של ה-primitive עדיין רץ, אבל הוא לא נמצא במעקב. |
job.cancel() מציגה No QiskitRuntimeService can be associated to the given token and instance. | הלקוח לא הצליח ליצור QiskitRuntimeService מאישורי הגישה המקומיים שלכם, ולכן ביטל רק את ה-job של ה-managed workflow. |
client.job() נכשלת עם Job [...] not found. | מזהה ה-job שגוי, או שה-job שייך למשתמש אחר. |
השלבים הבאים
- הריצו managed workflow כדי לבדוק את הסטטוס, התוצאה וה-logs של job, ולמצוא את הסיבה לשגיאה.