פרימיטיבים עם REST API
השלבים בנושא זה מתארים איך להריץ ולהגדיר עומסי עבודה של פרימיטיבים עם REST API, ומדגימים איך לקרוא להם מכל תוכנית שתרצה.
תיעוד זה משתמש במודול Python requests כדי להדגים את Qiskit Runtime REST API. עם זאת, תהליך עבודה זה ניתן לביצוע בכל שפה או מסגרת שתומכת בעבודה עם REST APIs. ראה את תיעוד ה-API reference לפרטים נוספים.
פרימיטיב Estimator עם REST API
1. אתחול החשבון
מכיוון ש-Qiskit Runtime Estimator הוא שירות מנוהל, תחילה עליך לאתחל את החשבון שלך. לאחר מכן תוכל לבחור את המכשיר שבו ברצונך להשתמש לחישוב ערך הציפייה.
פרטים על איך לאתחל את החשבון, לצפות ב-Backend-ים זמינים, ולבטל טוקנים ניתן למ צוא בנושא זה כאן.
2. יצירת Circuit בפורמט QASM
אתה צריך לפחות Circuit אחד כקלט לפרימיטיב Estimator.
הגדר Circuit קוונטי בפורמט QASM. לדוגמה:
qasm_string='''
OPENQASM 3;
include "stdgates.inc";
qreg q[2];
creg c[2];
x q[0];
cx q[0], q[1];
c[0] = measure q[0];
c[1] = measure q[1];
'''
קטעי הקוד הבאים מניחים שה-qasm_string עבר Transpiler לסטרינג חדש resulting_qasm.
3. הרצת ה-Circuit הקוונטי באמצעות Estimator V2 API
המשימות הבאות משתמשות ב-Qiskit Runtime V2 primitives. גם SamplerV2 וגם EstimatorV2 מקבלים PUB אחד או יותר (primitive unified blocs) כקלט. כל PUB הוא tuple שמכיל Circuit אחד והנתונים המשודרים אליו, שיכולים לכלול מספר observables ופרמטרים. כל PUB מחזיר תוצאה.
import requests
url = 'https://quantum.cloud.ibm.com/api/v1/jobs'
auth_id = "Bearer <YOUR_BEARER_TOKEN>"
crn = "<SERVICE-CRN>"
backend = "<BACKEND_NAME>"
headers = {
'Content-Type': 'application/json',
'Authorization':auth_id,
'Service-CRN': crn
}
job_input = {
'program_id': 'estimator',
"backend": backend,
"params": {
"pubs": [ #primitive unified blocs (PUBs) containing one circuit each.
[resulting_qasm, # QASM circuit
{"IIZII": 1, "XIZZZ": 2.3}, # Observable
None # parameter values
]]
}}
response = requests.post(url, headers=headers, json=job_input)
if response.status_code == 200:
job_id = response.json().get('id')
print("Job created:",response.text)
else:
print(f"Error: {response.status_code}")
4. בדיקת סטטוס המשימה וקבלת תוצאות
לאחר מכן, העבר את ה-job_id ל-API:
response_status_singlejob= requests.get(url+'/'+job_id, headers=headers)
response_status_singlejob.json().get('state')
פלט
>>> Job ID: 58223448-5100-4dec-a47a-942fb30edcad
>>> Job Status: JobStatus.RUNNING
קבל תוצאות המשימה:
response_result= requests.get(url+'/'+job_id+'/results', headers=headers)
res_dict=response_result.json()
estimator_result=res_dict['results']
print(estimator_result)
פלט
[{'data': {'evs': 0.7428980350102542, 'stds': 0.029884014518789213, 'ensemble_standard_error': 0.03261147170624149}, 'metadata': {'shots': 10016, 'target_precision': 0.01, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32}}]
5. עבודה עם אפשרויות Runtime
טכניקות צמצום שגיאות מאפשרות למשתמשים לצמצם שגיאות Circuit על ידי מידול הרעש של המכשיר בזמן הביצוע. בדרך כלל הדבר גורם לתקורת עיבוד מוקדמת קוונטית הקשורה לאימון המודל, ותקורת עיבוד מאוחרת קלאסית לצמצום שגיאות בתוצאות הגולמיות באמצעות המודל שנוצר.
טכניקות צמצום השגיאות המובנות בפרימיטיבים הן אפשרויות resilience מתקדמות. כדי לציין אפשרויות אלו, השתמש באפשרות resilience_level בעת שליחת המשימה.
הדוגמאות הבאות מדגימות את אפשרויות ברירת המחדל עבור dynamical decoupling, twirling, ו-TREX + ZNE. מצא אפשרויות נוספות ופרטים נוספים בנושא Error mitigation and suppression techniques.
- TREX + ZNE
- Dynamical Decoupling
- Twirling
import requests
url = 'https://quantum.cloud.ibm.com/api/v1/jobs'
auth_id = "Bearer <YOUR_BEARER_TOKEN>"
crn = "<SERVICE-CRN>"
backend = "BACKEND_NAME"
headers = {
'Content-Type': 'application/json',
'Authorization':auth_id,
'Service-CRN': crn
}
job_input = {
'program_id': 'estimator',
"backend": backend,
"params": {
"pubs": [ #primitive unified blocs (PUBs) containing one circuit each
[resulting_qasm, # QASM circuit
{"IIZII": 1, "XIZZZ": 2.3}, # Observable
None # parameter values
]]
"options": {
"resilience": {
"measure_mitigation": True,
"zne_mitigation": True,
"zne": {
"extrapolator":["exponential", "linear"],
"noise_factors":[1, 3, 5],
},
},
},
}
}
response = requests.post(url, headers=headers, json=job_input)
if response.status_code == 200:
job_id = response.json().get('id')
print("Job created:",response.text)
else:
print(f"Error: {response.status_code}")
import requests
url = 'https://quantum.cloud.ibm.com/api/v1/jobs'
auth_id = "Bearer <YOUR_BEARER_TOKEN>"
crn = "<SERVICE-CRN>"
backend = "BACKEND_NAME"
headers = {
'Content-Type': 'application/json',
'Authorization':auth_id,
'Service-CRN': crn
}
job_input = {
'program_id': 'estimator',
"backend": backend,
"params": {
"pubs": [ #primitive unified blocs (PUBs) containing one circuit each
[resulting_qasm, # QASM circuit
{"IIZII": 1, "XIZZZ": 2.3}, # Observable
None # parameter values
]]
"options": {
"dynamical_decoupling": {
"enable": True,
"sequence_type": 'XpXm',
"extra_slack_distribution": 'middle',
"scheduling_method": 'alap',
},
},
}
}
response = requests.post(url, headers=headers, json=job_input)
if response.status_code == 200:
job_id = response.json().get('id')
print("Job created:",response.text)
else:
print(f"Error: {response.status_code}")
import requests
url = 'https://quantum.cloud.ibm.com/api/v1/jobs'
auth_id = "Bearer <YOUR_BEARER_TOKEN>"
crn = "<SERVICE-CRN>"
backend = "BACKEND_NAME"
headers = {
'Content-Type': 'application/json',
'Authorization':auth_id,
'Service-CRN': crn
}
job_input = {
'program_id': 'estimator',
"backend": backend,
"params": {
"pubs": [ #primitive unified blocs (PUBs) containing one circuit each
[resulting_qasm, # QASM circuit
{"IIZII": 1, "XIZZZ": 2.3}, # Observable
None # parameter values
]]
"options": {
"twirling": {
"enable_gates": True,
"enable_measure": True,
"num_randomizations": "auto",
"shots_per_randomization": "auto",
"strategy": "active-accum",
},
},
}
}
response = requests.post(url, headers=headers, json=job_input)
if response.status_code == 200:
job_id = response.json().get('id')
print("Job created:",response.text)
else:
print(f"Error: {response.status_code}")
Sampler primitive עם REST API
1. אתחול החשבון
מכיוון ש-Qiskit Runtime Sampler הוא שירות מנוהל, קודם כול צריך לאתחל את החשבון שלך. אחרי זה אפשר לבחור את המכשיר שעליו תרצה להריץ את החישובים.
פרטים על אתחול החשבון, צפייה ב-Backend-ים זמינים וביטול טוקנים נמצאים בנושא הזה.
2. יצירת Circuit בפורמט QASM
נדרש לפחות Circuit אחד כקלט ל-Sampler primitive.
הגדר Circuit קוונטי בפורמט QASM:
qasm_string='''
OPENQASM 3;
include "stdgates.inc";
qreg q[2];
creg c[2];
x q[0];
cx q[0], q[1];
c[0] = measure q[0];
c[1] = measure q[1];
'''
קטעי הקוד הבאים מניחים שה-qasm_string עבר transpilation למחרוזת חדשה resulting_qasm.
3. הרצת ה-Circuit הקוונטי באמצעות Sampler V2 API
העבודות הבאות משתמשות ב-Qiskit Runtime V2 primitives. גם SamplerV2 וגם EstimatorV2 מקבלים PUB אחד או יותר (primitive unified blocs) כקלט. כל PUB הוא tuple שמכיל Circuit אחד והנתונים המשודרים אליו, שיכולים להיות observable-ים ופרמטרים מרובים. כל PUB מחזיר תוצאה.
import requests
url = 'https://quantum.cloud.ibm.com/api/v1/jobs'
auth_id = "Bearer <YOUR_BEARER_TOKEN>"
crn = "<SERVICE-CRN>"
backend = "<BACKEND_NAME>"
headers = {
'Content-Type': 'application/json',
'Authorization':auth_id,
'Service-CRN': crn
}
job_input = {
'program_id': 'sampler',
"backend": backend,
"params": {
"pubs": [[resulting_qasm],[resulting_qasm,None,500]] # primitive unified blocs (PUBs) containing one circuit each.
}}
response = requests.post(url, headers=headers, json=job_input)
if response.status_code == 200:
job_id = response.json().get('id')
print("Job created:",response.text)
else:
print(f"Error: {response.status_code}")
4. בדיקת סטטוס העבודה וקבלת תוצאות
עכשיו, העבר את job_id ל-API:
response_status_singlejob= requests.get(url+'/'+job_id, headers=headers)
response_status_singlejob.json().get('state')
פלט
>>> Job ID: 58223448-5100-4dec-a47a-942fb30edced
>>> Job Status: JobStatus.RUNNING
קבל את תוצאות העבודה:
response_result= requests.get(url+'/'+job_id+'/results', headers=headers)
res_dict=response_result.json()
# Get results for the first PUB
counts=res_dict['results'][0]['data']['c']['samples']
print(counts[:20])
פלט
['0x3', '0x0', '0x2', '0x1', '0x0', '0x3', '0x0', '0x3', '0x1', '0x2', '0x2', '0x0', '0x2', '0x0', '0x3', '0x3', '0x2', '0x0', '0x1', '0x0']
5. עבודה עם אפשרויות Runtime
טכניקות הפחתת שגיאות מאפשרות למשתמשים להפחית שגיאות ב-Circuit על ידי מידול רעש המכשיר בזמן הביצוע. הדבר בדרך כלל מוביל לעלות עיבוד מוקדמת (pre-processing) הקשורה לאימון המודל, ועלות עיבוד קלאסי (post-processing) להפחתת שגיאות בתוצאות הגולמיות באמצעות המודל שנוצר.
טכניקות הפחתת השגיאות המובנות ב-primitives הן אפשרויות resilience מתקדמות. כדי לציין אפשרויות אלה, השתמש באפשרות resilience_level בעת שליחת העבודה.
Sampler V2 אינו תומך בציון רמות resilience. עם זאת, ניתן להפעיל או לכבות שיטות הפחתה/דיכוי שגיאות בנפרד.
הדוגמאות הבאות מציגות את ברירות המחדל עבור dynamical decoupling ו-twirling. אפשרויות נוספות ופרטים מלאים נמצאים בנושא טכניקות הפחתה ודיכוי שגיאות.
- Dynamical Decoupling
- Twirling
import requests
url = 'https://quantum.cloud.ibm.com/api/v1/jobs'
auth_id = "Bearer <YOUR_BEARER_TOKEN>"
crn = "<SERVICE-CRN>"
backend = "<BACKEND_NAME>"
headers = {
'Content-Type': 'application/json',
'Authorization':auth_id,
'Service-CRN': crn
}
job_input = {
'program_id': 'sampler',
"backend": backend,
"params": {
"pubs": [[resulting_qasm]], # primitive unified blocs (PUBs) containing one circuit each.
"options": {
"dynamical_decoupling": {
"enable": True,
"sequence_type": 'XpXm',
"extra_slack_distribution": 'middle',
"scheduling_method": 'alap',
},
},
}
}
response = requests.post(url, headers=headers, json=job_input)
if response.status_code == 200:
job_id = response.json().get('id')
print("Job created:",response.text)
else:
print(f"Error: {response.status_code}")
import requests
url = 'https://quantum.cloud.ibm.com/api/v1/jobs'
auth_id = "Bearer <YOUR_BEARER_TOKEN>"
crn = "<SERVICE-CRN>"
backend = "<BACKEND_NAME>"
headers = {
'Content-Type': 'application/json',
'Authorization':auth_id,
'Service-CRN': crn
}
job_input = {
'program_id': 'sampler',
"backend": backend,
"params": {
"pubs": [[resulting_qasm]], # primitive unified blocs (PUBs) containing one circuit each.
"options": {
"twirling": {
"enable_gates": True,
"enable_measure": True,
"num_randomizations": "auto",
"shots_per_randomization": "auto",
"strategy": "active-accum",
},
},
}
}
response = requests.post(url, headers=headers, json=job_input)
if response.status_code == 200:
job_id = response.json().get('id')
print("Job created:",response.text)
else:
print(f"Error: {response.status_code}")
פרימיטיב Sampler עם REST API ומעגלים פרמטריים
1. אתחול החשבון
מכיוון ש-Qiskit Runtime הוא שירות מנוהל, קודם כל צריך לאתחל את החשבון שלך. אחר כך אפשר לבחור את המכשיר שעליו רוצים להריץ את החישובים.
פרטים על אתחול החשבון, צפייה ב-Backends זמינים וביטול טוקנים אפשר למצוא בנושא הזה.
2. הגדרת פרמטרים
import requests
import qiskit_ibm_runtime
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit.transpiler import generate_preset_pass_manager
from qiskit.qasm3 import dumps
from qiskit import QuantumCircuit
from qiskit.circuit import Parameter
from qiskit import transpile
service = QiskitRuntimeService(channel='ibm_quantum')
backend = service.backend("<SPECIFY BACKEND>")
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
theta = Parameter('theta')
phi = Parameter('phi')
parameter_values = {'theta': 1.57, 'phi': 3.14} # In case we want to pass a dictionary
3. יצירת Circuit קוונטי והוספת Gates פרמטריים
qc = QuantumCircuit(2)
# Add parameterized gates
qc.rx(theta, 0)
qc.ry(phi, 1)
qc.cx(0, 1)
qc.measure_all()
# Draw the original circuit
qc.draw('mpl')
# Get an ISA circuit
isa_circuit = pm.run(qc)
4. יצירת קוד QASM 3
qasm_str = dumps(isa_circuit)
print("Generated QASM 3 code:")
print(qasm_str)
5. הרצת ה-Circuit הקוונטי באמצעות Sampler V2 API
משימות ה-Job הבאות משתמשות ב-פרימיטיבים של Qiskit Runtime V2. גם SamplerV2 וגם EstimatorV2 מקבלים PUB אחד או יותר (primitive unified blocs) כקלט. כל PUB הוא tuple שמכיל Circuit אחד ונתונים שמשודרים אליו, שיכולים להיות כמה observables ופרמטרים. כל PUB מחזיר תוצאה.
import requests
url = 'https://quantum.cloud.ibm.com/api/v1/jobs'
auth_id = "Bearer <YOUR_BEARER_TOKEN>"
crn = "<SERVICE-CRN>"
backend = "<BACKEND_NAME>"
headers = {
'Content-Type': 'application/json',
'Authorization':auth_id,
'Service-CRN': crn
}
job_input = {
'program_id': 'sampler',
"backend": backend,
"params": {
# Choose one option: direct parameter transfer or through a dictionary
#"pubs": [[qasm_str,[1,2],500]], # primitive unified blocs (PUBs) containing one circuit each.
"pubs": [[qasm_str,parameter_values,500]], # primitive unified blocs (PUBs) containing one circuit each.
}}
response = requests.post(url, headers=headers, json=job_input)
if response.status_code == 200:
job_id = response.json().get('id')
print(f"Job created: {response.text}")
else:
print(f"Error: {response.status_code}")
print(response.text)
6. בדיקת סטטוס ה-Job וקבלת תוצאות
עכשיו צריך להעביר את ה-job_id ל-API:
response_status_singlejob = requests.get(f"{url}/{job_id}", headers=headers)
response_status_singlejob.json().get('state')
פלט
{'status': 'Completed'}
קבלת תוצאות ה-Job:
response_result = requests.get(f"{url}/{job_id}/results", headers=headers)
res_dict=response_result.json()
# Get results for the first PUB
counts=res_dict['results'][0]['data']['c']['samples']
print(counts[:20])
פלט
['0x1', '0x2', '0x1', '0x2', '0x1', '0x2', '0x0', '0x2', '0x1', '0x1', '0x2', '0x2', '0x1', '0x1', '0x1', '0x1', '0x1', '0x1', '0x1', '0x1']
צעדים הבאים
- יש כמה דרכים להריץ workloads, בהתאם לצרכים שלך: מצב Job, מצב Session ומצב batch. למד איך לעבוד עם מצב Session ומצב batch בנושא מצבי ביצוע. שים לב שמשתמשי Open Plan לא יכולים להגיש משימות Session.
- למד איך לאתחל את החשבון שלך עם REST API.
- קרא את מעבר לפרימיטיבים V2.
- תרגל עם פרימיטיבים דרך שיעור פונקציית העלות ב-IBM Quantum Learning.
- למד איך לבצע Transpile מקומי בסעיף Transpile.
- עבור לפרימיטיבים V2 של Qiskit Runtime.