דלג לתוכן הראשי
פרויקט זה בשלב בטא. מצאת באג? פתח issue ב-GitHub. יש שאלה או רעיון? שאל ב-Discussions — נשמח לשמוע ממך!
מה איכות התרגום בדף זה?

הרצת 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, ולמצוא את הסיבה לשגיאה.