REST API를 사용한 Primitives
이 주제의 단계에서는 REST API를 사용하여 primitive 워크로드를 실행하고 구성하는 방법을 설명하며, 원하는 프로그램에서 이를 호출하는 방법을 시연합니다.
이 문서는 Qiskit Runtime REST API를 시연하기 위해 Python requests 모듈을 활용합니다. 그러나 이 워크플로우는 REST API 작업을 지원하는 모든 언어나 프레임워크를 사용하여 실행할 수 있습니다. 자세한 내용은 API 참조 문서를 참조하세요.
REST API를 사용한 Estimator Primitive
1. 계정 초기화
Qiskit Runtime Estimator는 관리형 서비스이므로, 먼저 계정을 초기화해야 합니다. 그런 다음 기댓값 계산에 사용할 디바이스를 선택할 수 있습니다.
계정 초기화, 사용 가능한 Backend 조회, 토큰 무효화 방법에 대한 자세한 내용은 이 주제를 참조하세요.
2. QASM Circuit 생성
Estimator Primitive의 입력으로 최소 하나의 Circuit이 필요합니다.
QASM 양자 Circuit을 정의합니다. 예시:
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이 새 문자열 resulting_qasm으로 트랜스파일된 것으로 가정합니다.
3. Estimator V2 API를 사용하여 양자 Circuit 실행
다음 작업은 Qiskit Runtime V2 primitives를 사용합니다. SamplerV2와 EstimatorV2 모두 하나 이상의 primitive unified bloc(PUB)을 입력으로 받습니다. 각 PUB는 하나의 Circuit과 해당 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': '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 오류를 완화할 수 있습니다. 이는 일반적으로 모델 훈련과 관련된 양자 전처리 오버헤드와, 생성된 모델을 사용하여 원시 결과의 오류를 완화하는 고전적 후처리 오버헤드를 수반합니다.
Primitives에 내장된 오류 완화 기법은 고급 복원력 옵션입니다. 이러한 옵션을 지정하려면 작업 제출 시 resilience_level 옵션을 사용하세요.
다음 예시는 동적 디커플링(dynamical decoupling), 트월링(twirling), TREX + ZNE의 기본 옵션을 시연합니다. 더 많은 옵션과 자세한 내용은 오류 완화 및 억제 기법 주제에서 확인하세요.
- 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}")
REST API를 사용한 Sampler Primitive
1. 계정 초기화
Qiskit Runtime Sampler는 관리형 서비스이므로, 먼저 계정을 초기화해야 합니다. 그런 다음 계산을 실행할 디바이스를 선택할 수 있습니다.
계정 초기화, 사용 가능한 Backend 조회, 토큰 무효화 방법에 대한 자세한 내용은 이 주제를 참조하세요.
2. QASM Circuit 생성
Sampler Primitive의 입력으로 최소 하나의 Circuit이 필요합니다.
QASM 양자 Circuit을 정의합니다:
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이 새 문자열 resulting_qasm으로 트랜스파일된 것으로 가정합니다.
3. Sampler V2 API를 사용하여 양자 Circuit 실행
아래 작업은 Qiskit Runtime V2 primitives를 사용합니다. SamplerV2와 EstimatorV2 모두 하나 이상의 PUB(primitive unified bloc)을 입력으로 받습니다. 각 PUB는 하나의 Circuit과 해당 Circuit에 브로드캐스트되는 데이터(여러 개의 관측값 및 매개변수 포함)로 구성된 튜플입니다. 각 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 오류를 줄일 수 있습니다. 이 기법은 일반적으로 모델 훈련과 관련된 양자 전처리 오버헤드와, 생성된 모델을 이용해 원시 결과의 오류를 완화하는 고전적 후처리 오버헤드를 수반합니다.
primitives에 내장된 오류 완화 기법은 고급 복원력 옵션입니다. 이러한 옵션을 지정하려면 작업 제출 시 resilience_level 옵션을 사용하세요.
Sampler V2는 복원력 수준 지정을 지원하지 않습니다. 단, 개별 오류 완화/억제 방법을 개별적으로 켜거나 끌 수 있습니다.
다음 예시는 동적 디커플링(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}")
REST API 및 매개변수화된 Circuit을 사용하는 Sampler primitive
1. 계정 초기화
Qiskit Runtime은 관리형 서비스이므로 먼저 계정을 초기화해야 합니다. 그런 다음 계산을 실행할 장치를 선택할 수 있습니다.
계정 초기화 방법, 사용 가능한 Backend 확인, 토큰 무효화에 대한 자세한 내용은 이 항목을 참고하세요.
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 생성 및 매개변수화된 Gate 추가
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. Sampler V2 API를 사용하여 양자 Circuit 실행
다음 작업은 Qiskit Runtime V2 primitives를 사용합니다. SamplerV2와 EstimatorV2 모두 하나 이상의 PUB(primitive unified bloc)을 입력으로 받습니다. 각 PUB는 하나의 Circuit과 해당 Circuit에 브로드캐스트되는 데이터(여러 개의 관측값 및 매개변수 포함)로 구성된 튜플입니다. 각 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_id를 API에 전달합니다.
response_status_singlejob = requests.get(f"{url}/{job_id}", headers=headers)
response_status_singlejob.json().get('state')
출력
{'status': 'Completed'}
작업 결과 가져오기:
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']
다음 단계
- 필요에 따라 워크로드를 실행하는 방법은 여러 가지가 있습니다: 작업 모드, Session 모드, 배치 모드. Session 모드와 배치 모드로 작업하는 방법은 실행 모드 항목에서 확인하세요. Open Plan 사용자는 Session 작업을 제출할 수 없습니다.
- REST API로 계정을 초기화하는 방법을 알아보세요.
- V2 primitives로 마이그레이션을 읽어보세요.
- IBM Quantum Learning의 비용 함수 레슨을 통해 primitives를 연습해 보세요.
- Transpile 섹션에서 로컬 Transpiler 방법을 알아보세요.
- Qiskit Runtime V2 primitives로 마이그레이션하세요.