הגדרת קלט ופלט
workflow מנוהל עובד כמו פונקציית Python שרצה על מחשוב מרוחק. השוו פונקציה מקומית לאותו קוד כ-workflow:
Local Python
def my_workflow(circuits, shots=4096):
...
return {"counts": counts}
result = my_workflow(circuits=circuits, shots=1024)
ב-workflow מנוהל, run() היא הקריאה, get_arguments() נותנת ל-workflow את הפרמטרים שלו, ו-save_result() היא משפט ה-return שלו. מכיוון שה-workflow רץ כמשימה נפרדת על מחשוב מרוחק, הוא שונה מקריאה לפונקציה מקומית בשלוש דרכים:
-
הלקוח מקודד ארגומנטים ותוצאות. כל ערך חייב להיות כזה שהלקוח יכול לקודד, וחלק מהסוגים משתנים. ראו קריאת ארגומנטים ב-workflow שלכם.
-
הקריאה לא ממתינה.
run()מחזירה משימה מיד, ואת התוצאה קוראים מאוחר יותר עםjob.result(). ראו שמירת תוצאות. -
שום דבר לא בודק את הקריאה. פונקציית Python דוחה ארגומנט מילת מפתח לא מוכר, אבל workflow מתעלם ממנו אלא אם מצרפים סכמה. ראו שיטה מומלצת: אימות ארגומנטים באמצעות סכמה.
קריאת ארגומנטים ב-workflow שלכם
העבירו קלט ל-workflow מהמחברת המקומית שלכם:
run_workflow_remotely.ipynb
job = my_workflow.run(circuits=circuits, shots=1024)
כדי לאפשר זאת, ערכו את קוד ה-workflow כך שיביא ארגומנטים באמצעות 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() בקוד ה-workflow שלכם:
source_files/my_workflow.py
from qiskit_serverless import get_function_size
size = get_function_size() # For example, "M"
אם ההרצה לא מעבירה function_size, הפונקציה get_function_size() מחזירה את גודל ברירת המחדל של ה-workflow. ראו בחירת גודל לכל הרצה.
סוגי ארגומנטים נתמכים
כל ערך חייב להיות ניתן לסריאליזציה ל-JSON, או אובייקט שהלקוח יכול לקודד, כמו Circuit של Qiskit או מערך NumPy. מכיוון שהלקוח מקודד כל ארגומנט לפני ששולח את המשימה ו-get_arguments() מפענחת אותו בתוך ה-workflow, ה-workflow מקבל את אובייקט ה-Python המקורי.
הלקוח שולח int, float, str, bool, None, ורשימות או מילונים שלהם ללא שינוי. הוא מקודד אובייקטים אחרים, כמו QuantumCircuit, numpy.ndarray או מספר complex, כמילון עם תג __type__ ו-__value__. אתם צריכים את הצורה הזו כשכותבים סכמת ארגומנטים.
מכיוון שב-JSON אין מקבילה לחלק מהסוגים, הסוגים האלה משתנים במהלך הקידוד. Tuples מגיעים כרשימות, מפתחות של מילון מגיעים כמחרוזות, ומספרים שלמים של NumPy כמו np.int64 מגיעים כ-int. אם הלקוח לא יכול לקודד ערך, כמו bytes או np.float32, הפונקציה run() מעלה TypeError ולא יוצרת משימה.
אי אפשר להעביר חלק מהאובייקטים כארגומנטים. לדוגמה, העבירו את שם ה-Backend כמחרוזת במקום אובייקט Backend, וצרו את ה-Backend בתוך ה-workflow. ראו הרצת משימות קוונטיות מתוך workflow.
מגבלות גודל
הארגומנטים של הרצה אחת יכולים להגיע עד 32 MB אחרי הקידוד. לדוגמה, Circuit אחד של 100 Qubits בעומק 100 מקודד לכ-39 KB, ולכן הרצה אחת יכולה לקבל אצווה של כ-800 Circuits כאלה. עבור קלט גדול יותר, העלו קובץ והעבירו את שמו כארגומנט.
שמירת תוצאות
השתמשו ב-save_result() בסוף ה-workflow כדי להחזיר תוצאה למחברת שלכם. קראו את התוצאה במחברת באמצעות job.result():
run_workflow_remotely.ipynb
result = job.result()
כדי לאפשר זאת, קראו ל-save_result() בקוד ה-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() מקודדת את התוצאה באותו אופן שבו הלקוח מקודד ארגומנטים, ו-job.result() מפענחת אותה. לכן תוצאה יכולה להכיל את סוגי הארגומנטים הנתמכים, כמו Circuits, מערכי NumPy והתוצאה של משימת primitive, עם אותם שינויי סוגים.
-
בדקו את ערך ההחזרה. אם
save_result()לא מצליחה לקודד את הערך, היא רושמת אזהרה ללוג ומחזירהFalseבמקום להעלות שגיאה. בלי בדיקה, המשימה יכולה להסתיים בסטטוסDONEוללא תוצאה. -
רק ה-
save_result()האחרונה נשמרת. כל קריאה מחליפה את התוצאה שנשמרה. כדי להחזיר כמה ערכים, שמרו אותם במילון אחד, או כתבו אותם ללוגים. -
מילון ריק פירושו שאין תוצאה. אם ה-workflow אף פעם לא קורא ל-
save_result(), הפונקציהjob.result()מחזירה{}.
כדי להחזיר קבצים, כמו מערכים גדולים או גרפים, שמרו אותם באחסון קבצים והחזירו את שמותיהם בתוצאה.
שיטה מומלצת: אימות ארגומנטים באמצעות סכמה
כשיטה מומלצת, צרפו JSON Schema לכל workflow שמקבל ארגומנטים. הסכמה מתארת את הארגומנטים שה-workflow מקבל, וה-workflow בודק מולה את הארגומנטים של כל הרצה לפני שהוא יוצר את המשימה. אם הארגומנטים לא תואמים, run() נכשלת מיד עם שגיאה ששמה את השדה הפגום, וה-workflow לא יוצר משימה. בלי סכמה, ארגומנטים פגומים מגיעים ל-workflow אחרי שהמשימה מתחילה, וה-workflow מתעלם משם ארגומנט שנכתב בטעות.
הגדירו את הסכמה באמצעות arguments_schema כשאתם מעלים את ה-workflow. העבירו מילון, לא מחרוזת 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. הסכמה בודקת את הארגומנטים כפי שהלקוח שולח אותם, ולכן Circuit הוא אובייקט כמו
{"__type__": "QuantumCircuit", "__value__": "<base64-encoded QPY>"}, ולא מחרוזת או מערך. בדקו את התג__type__, והתייחסו ל-__value__כמחרוזת אטומה. סכמה שמתארת Circuit כמחרוזת דוחה כל הרצה תקינה. -
הגדירו
"additionalProperties": false. בלי ההגדרה הזו, ה-workflow מתעלם משם ארגומנט שנכתב בטעות, כמוshotz, בלי אזהרה, ורץ עם ערך ברירת המחדל. הצהירו על כל ארגומנט שה-workflow מקבל לפני שאתם מפעילים את ההגדרה הזו. -
סמנו ארגומנטים כנדרשים. הוסיפו ל-
requiredכל ארגומנט שה-workflow קורא בלי ערך ברירת מחדל.
אם הארגומנטים לא תואמים לסכמה, הודעת השגיאה ממנה את הכלל ואת מיקום הערך הפגום:
'type' validation failed, schema requires 'integer': rejected value '4096'
path: ['shots']
סכמה בודקת את הסוג, הצורה והטווח של כל ארגומנט. סכמה לא יכולה לבדוק אם שני ארגומנטים תקינים סותרים זה את זה, או אם Circuit מתאים ל-Backend. השאירו את הבדיקות האלה בקוד ה-workflow.
עדכון או הסרה של סכמה
-
כדי להחליף את הסכמה, הגדירו
arguments_schemaחדשה והעלו את ה-workflow שוב. -
כדי להסיר את הסכמה, העלו את ה-workflow עם
arguments_schema={}. -
אם מעלים את ה-workflow בלי
arguments_schema, ה-workflow שומר את הסכמה שנשמרה.
כדי לראות את הסכמה שבתוקף, קראו את my_workflow.arguments_schema. ערך None פירושו שלא workflow אין סכמה.
בדיקת ארגומנטים לפני ההרצה
קראו ל-validate_arguments() כדי לבדוק קבוצת ארגומנטים מול הסכמה בלי להתחיל משימה:
run_workflow_remotely.ipynb
my_workflow.validate_arguments({"circuits": [circuit], "shots": 1024})
# {'valid': True}
אם הארגומנטים אינם תקינים, validate_arguments() מעלה QiskitServerlessException עם אותה הודעה ש-run() מחזירה עבור הארגומנטים האלה. אם ל-workflow אין סכמה, כל ארגומנטים תקינים. תוצאה תקינה לא מבטיחה ש-run() תצליח, כי run() בודקת גם מגבלות אחרות, כמו מספר המשימות הפעילות.
כללי סכמה
workflow מנוהל דוחה את ההעלאה אם הסכמה מפרה אחד מהכללים הבאים:
-
הסכמה יכולה להגיע עד 64 KiB, עם עד 64 רמות קינון ועד 200 תת-סכמות.
-
הפניות חייבות להצביע לתוך אותה סכמה, כמו
#/$defs/circuit, וכל הפניה חייבת להיפתר. הפניות ל-URL או לקבצים אינן מותרות. -
הסכמה חייבת להיות אובייקט או ערך בוליאני.
הימנעו גם מהבעיות הבאות, שההעלאה לא תופסת:
-
כמתים מקוננים ב-
pattern. תבנית כמו^(a+)+$יכולה לקחת זמן רב מאוד להערכה. workflow מפסיק את האימות אחרי מגבלת זמן CPU ודוחה את ההרצה. כתבו תבניות בלי כמת סביב קבוצה שכבר מכילה כמת, כמו^ibm_[a-z0-9_]{1,40}$. -
falseכסכמה. הסכמהfalseדוחה כל הרצה. כדי להסיר אימות, השתמשו ב-{}.
פתרון בעיות בסכמה
| בעיה | סיבה |
|---|---|
| כל הרצה נדחית בגלל ארגומנט Circuit. | הסכמה מתארת את ה-Circuit כמחרוזת או כמערך. תארו אותו כאובייקט עם תג __type__. |
| הרצות תקינות נדחות. | additionalProperties הוא false, והסכמה לא מצהירה על ארגומנט שההרצה מעבירה. ה-path בשגיאה ממנה את הארגומנט. |
| הרצות לא תקינות לא נדחות. | ל-workflow אין סכמה. בדקו את my_workflow.arguments_schema. |
| שום הרצה לא נבדקת, למרות שהגדרתם סכמה. | הסכמה הועברה כמחרוזת JSON. העבירו מילון. |
ההעלאה נכשלת עם שגיאת 400. | הסכמה מפרה אחד מכללי הסכמה. |
| השגיאה אומרת שהאימות לקח יותר מדי זמן CPU. | ל-pattern יש כמתים מקוננים. כתבו את התבנית מחדש. |