샘플러에서 익스큐터로 마이그레이션
이 가이드에서는 양자 샘플링 워크로드를 ‘ IBM Quantum® ’ 샘플러 프리미티브에서 ‘Executor’ 프리미티브로 이동하는 방법을 설명합니다.
Executor 프리미티브는 방향성 실행 모델의 일부입니다. 지시형 실행 모델의 모든 구성 요소는 현재 베타 버전이며, 안정적이지 않을 수 있습니다. Samplomatic 또는 qiskit-ibm-runtime GitHub 저장소에서 이슈를 등록하여 직접 테스트해 보시고 피드백을 남겨 주시기 바랍니다.
이주해야 할까요?
모든 사용자가 Sampler에서 Executor로 전환해야 하는 것은 아닙니다. 기본 데이터형들 간에는 많은 차이점이 있지만, 다음 지침을 참고하면 마이그레이션 여부를 결정하는 데 도움이 될 수 있습니다:
유틸리티 규모의 실험을 수행하며, 파울리 트위링, 노이즈 모델 학습 및 주입, 기저 변환과 같은 기술에 대해 세밀하고 재현 가능한 제어가 필요한 양자 정보 과학자이거나, Executor가 제공하는 추가 기능 중 하나가 필요한 경우 Executor로 전환하십시오
간단하고 고수준의 인터페이스를 원하며, 오류 억제 및 완화를 프라이머리 측에서 자동으로 처리해 주기를 원한다면 Sampler를 계속 사용하십시오.
제한 사항 및 유의 사항
Executor와 지시형 실행 모델은 현재 베타 단계이므로, 마이그레이션을 결정하기 전에 다음 사항에 유의하시기 바랍니다:
- 아직 시뮬레이터 지원이 없습니다 : 로컬
시뮬레이션을 위한
qiskit-aer구현이 있는 Sampler와 달리,AerSampler현재 Executor용 시뮬레이터 백엔드는 없습니다. 시뮬레이터 지원 기능이 곧 제공될 예정입니다. 그동안에는 하드웨어로 제출하기 전에 로컬 환경에서 템플릿 회로를 검토하고 테스트하여 워크플로우를 검증할 수 있습니다. - 이 안내서는 에스티메이터(Estimator)가 아닌 샘플러(Sampler)에 대해서만 다룹니다. Estimator에서 Executor로 마이그레이션하는 것은 Sampler에서 마이그레이션하는 것보다 훨씬 더 복잡합니다. 이는 Estimator가 원시 샘플을 반환하는 대신 기대값을 계산하기 때문입니다. Executor를 사용하여 Estimator의 동작을 재현하려면 추가적인 후처리가 필요합니다. Estimator에서 Executor로 마이그레이션하는 데 도움이 되는 유틸리티 함수는 아직 개발 중이므로, 이 가이드에서는 의도적으로 Sampler 워크플로우에 대해서만 설명합니다.
Executor와 Sampler의 주요 차이점
샘플러와 익제큐터는 모두 양자 회로의 출력 레지스터를 샘플링하지만, 대상 사용자가 다릅니다:
- 샘플러는 고수준 추상화 개념입니다. 다음과 같은 특성을 가지고 있습니다.
- 오류 억제 기능(동적 디커플링 및 트와일링)이 내장되어 있습니다.
- 이 기능은 사용자를 대신해 암묵적으로 결정을 내립니다.
- 이 시스템은 알고리즘 개발자들이 데이터보다는 혁신에 집중할 수 있도록 설계되었습니다. 변환.
- Executor는 지시형 실행 모델 의 일부입니다. 이 기능은 샘플러와 여러 면에서 다르며 다음과 같은 특징을 가지고 있습니다:
-
이 기능에는 오류 억제 또는 완화 기능이 내장되어 있지 않습니다. 대신, 클라이언트 측에서 회로 주석과 샘플렉스를 사용하여 설계 의도를 반영하면, 비용이 많이 드는 회로 변형 생성은 서버 측으로 이전됩니다.
-
암묵적인 결정을 내리지 않습니다. 이 시스템은 귀하의 지시를 정확히 따르며, 완벽한 제어권과 투명성을 제공합니다.
-
Executor와 Samplomatic을 함께 사용하면 Sampler에서는 제공하지 않는 다음과 같은(이에 국한되지 않는) 추가 기능을 활용할 수 있습니다:
- 더 많은 트위링 그룹: Samplomatic을 사용하면 Sampler가 자동으로 적용하는 단일 전략에 국한되지 않고,
박스별로 적용할 트위링 그룹을 직접 선택할 수 있습니다. 또한 파울리 이외의 회전군, 예를 들어 회전
"local_c1"군 등을 지원합니다. - 커널 처리 및 분류된 측정값을 함께 포함: 이 설정
QuantumProgram.meas_level = "both"( v0.48.0qiskit-ibm-runtime에 추가됨)은 작업당 하나의 측정 유형만 선택하는 대신, 결과에 분류된 측정값과 커널 처리된 측정값이 모두 포함되도록 요청합니다. - 분수 게이트가 포함된 회로에 대한 트위링: Executor는 분수 게이트가 포함된 회로에 트위링을 적용할 수 있습니다.
- 세밀하고 조합 가능한 오류 완화: 예를 들어, 어떤 회로 계층에 대해 오류 완화를 적용할지 선택하고, 회로에 주입되는 노이즈 비율을 조정하는 것.
참고- 향후 추가될 새로운 기능들은 Executor에 먼저 출시될 예정이며, Sampler로 이식되지 않을 수도 있습니다. 최신 기능을 활용해야 한다면, Executor가 장래성을 고려했을 때 더 나은 선택입니다.
- 기본 Qiskit 패키지에는 아직
Executor 프리미티브에 대한 기본 클래스가 제공되지 않습니다(의 경우에는 제공됩니다
SamplerV2).
- 더 많은 트위링 그룹: Samplomatic을 사용하면 Sampler가 자동으로 적용하는 단일 전략에 국한되지 않고,
박스별로 적용할 트위링 그룹을 직접 선택할 수 있습니다. 또한 파울리 이외의 회전군, 예를 들어 회전
-
개념도
다음 표는 샘플러의 개념이 익스큐터에 어떻게 대응되는지 보여줍니다.
개념 | 샘플러 | 실행기 |
|---|---|---|
| 가져오기 | from qiskit_ibm_runtime import SamplerV2 | from qiskit_ibm_runtime import Executor |
| 입력 | PUB 목록 (튜플) | A개의 QuantumProgram 객체 QuantumProgramItem |
| 회로 및 매개변수 | (circuit, params, shots) 튜플(tuple) | program.append_circuit_item(circuit, circuit_arguments=...) |
| 휙 돌리기 | TwirlingOptions | 주석이 달린 상자와 샘플렉스(append_samplex_item)를 통해 명확하게 나타남 |
| 호출 실행 | sampler.run([pub, ...]) | executor.run(program) |
| 결과 유형 | PrimitiveResult/SamplerPubResult | QuantumProgramResult (반복 가능) |
| 데이터에 액세스 | result[0].data.<register> (BitArray) | result[0]["<register>"] (np.ndarray) |
| 소음 관리 | 내장 옵션 | 수동으로 작성해야 합니다(주석, samplex 등 NoiseLearnerV3) |
마이그레이션 단계 개요
- Samplomatic을 설치하세요.
- 임포트 문장을 수정하세요.
- PUB 의 튜플을 대체합니다.
- 샷의 표현 방식을 변경합니다.
- 필요에 따라 다른 옵션도 업데이트하십시오.
run명령을 업데이트하십시오.- 결과 파싱 기능을 업데이트합니다.
- 회전 취소.
1단계. 필요한 패키지를 설치하십시오
Executor와 지시형 실행 모델을 사용하려면 다음 samplomatic 패키지가 필요합니다:
pip install qiskit qiskit-ibm-runtime samplomatic
# For visualization support:
# pip install samplomatic[vis]qiskit-ibm-runtimev0.48.0 이meas_level = "both"옵션과 트위링local_c1그룹을 추가하기 때문에 권장됩니다.qiskit >= 2.3.0필수입니다.samplomatic >= 0.18.0필수입니다.
2단계. 임포트 문 변경
샘플러:
from qiskit_ibm_runtime import SamplerV2 as Sampler실행자:
from qiskit_ibm_runtime import Executor, QuantumProgram3단계. PUB 튜플을 a로 대체하십시오. QuantumProgram
Executor를 사용할 때는 튜플(PUB) 목록을 전달하는 대신, 를 생성한 QuantumProgram 다음 그 안에 항목을 추가합니다.
A는 회로 항목과 샘플렉스 항목을 QuantumProgram 허용합니다:
-
append_circuit_item: 회로인CircuitItem, 그리고 (선택적으로) 해당 매개변수 값을 추가합니다. 무작위화 과정 없이 있는 그대로 실행됩니다.이 옵션은 단순히 회로를 샘플링하고 싶을 때 사용하며, 이는 Sampler가 트위링( PUB )이 없는 회로를 처리할 때와 정확히 동일합니다. 예를 들어, 일반 샘플링 작업을 제출할 때나, 원하는 변형을 이미 수동으로 포함시킨 경우에 이 옵션을 사용하면 됩니다.
-
append_samplex_item: 템플릿 회로와 서버 측에서 무작위 매개변수 세트를 생성하는 샘플렉스를 결합한samplexItem,를 추가합니다.회로의 내용을 무작위로 배치하고 싶을 때 이 기능을 사용하세요. 주요 사례는 회전(게이트 또는 측정)이나 노이즈 주입과 관련된 경우입니다. 이 기능은 Sampler의 기본 제공 트위를링 기능을 대체합니다.
단일 은 두 가지 유형의 항목을 모두 수용할 QuantumProgram 수 있으며, 추가된 각 항목은
독립적인 작업으로 실행되어 결과에 자체 항목을 생성합니다. 일반적으로 회로에 무작위성이 필요하지 않을 때는 append_circuit_item 를 사용하십시오. 그렇지 않은 경우, append_samplex_item.을 사용하십시오.
다음 섹션에서는 각각을 차례로 살펴봅니다: 를 사용하는 매개변수화 회로와
append_circuit_item, 를 사용하여 트와일링을 이동시키는 방법입니다 append_samplex_item.
다음 코드 예시에서 는 대상 백엔드의 명령어 집합 아키텍처 (ISA)에 부합하도록 트랜스파일링된 회로를 의미합니다 isa_circuit . 여기에는 두 개의 매개변수가 포함되어 isa_circuit 있습니다.
3a 단계. 매개변수화된 회로 마이그레이션
Sampler의 경우, 매개변수 값은 PUB 튜플의 두 번째 요소입니다. Executor를 사용할 때는,
이들을 로 circuit_arguments 전달하십시오 append_circuit_item.
샘플러:
params = np.random.rand(10, circuit.num_parameters) # 10 parameter sets
pubs = (isa_circuit, params)실행기
program = QuantumProgram(shots=1024)
program.append_circuit_item(
isa_circuit,
circuit_arguments=np.random.rand(10, circuit.num_parameters), # 10 sets
)
# CircuitItem result shape: (parameter_sets, shots, register_bits) -> (10, 1024, 2)
result_0 = result[0]["meas"]3b 단계. 내장된 트위를링 기능을 명시적 어노테이션으로 전환
이것이 가장 큰 변화입니다. 샘플러는 옵션을 통해 사용자를 대신해 회전 효과를 적용합니다. Executor를 사용하면, 어노테이션이 적용된 박스와 ( Samplomatic의 ) samplex를 활용하여 해당 의도를 명시적으로 선언할 수 있습니다.
샘플러 (옵션을 사용하여 회전):
sampler = Sampler(mode=backend)
sampler.options.twirling.enable_gates = True
sampler.options.twirling.enable_measure = True연기자 (상자와 삼플렉스를 이용해 회전하는 동작):
from samplomatic import build
from samplomatic.transpiler import generate_boxing_pass_manager
# 1. Group gates and measurements into annotated boxes with twirling annotations
boxes_pm = generate_boxing_pass_manager(
enable_gates=True, # gate twirling
enable_measures=True, # measurement twirling
)
boxed_circuit = boxes_pm.run(isa_circuit)
# 2. Build the (template circuit, samplex) pair.
# The template circuit's single-qubit gates are replaced by parameterized gates;
# the samplex encodes how to generate the randomized parameters at runtime.
template_circuit, samplex = build(boxed_circuit)
# 3. Append as a samplex item, specifying the number of randomizations
program = QuantumProgram(shots=1024)
program.append_samplex_item(
template_circuit,
samplex=samplex,
samplex_arguments={
"parameter_values": np.random.rand(10, 2), # original circuit params
},
shape=(28, 10), # 28 randomizations x 10 parameter sets
)템플릿 회로와 샘플렉스는 클라이언트 측에서 구축되므로, 하드웨어로 어떤 데이터도 전송하기 전에 로컬에서 이를 확인하고 샘플링하여 출력을 검증할 수 있습니다.
검증: 템플릿 회로를 로컬에서 테스트해 봅니다
샘플렉스에서 무작위 값을 추출하여 템플릿 회로에 바인딩하면,
샘플렉스가 예상한 대로 매개변수 값을 생성하고 있는지 확인할 수 있습니다.
에서 반환되는 매개변수 값은
템플릿 회로의 매개변수와 직접 호환됩니다samplex.sample.
# Check which inputs the samplex requires (for the twirling example above,
# this is just the original circuit's parameter values).
print(samplex.inputs())
# Bind the required inputs, then draw a few randomizations locally.
inputs = samplex.inputs().bind(
parameter_values=np.random.rand(2), # one set of the original circuit's params
)
outputs = samplex.sample(inputs, num_randomizations=3)
# Assign one randomization's parameter values to the template circuit and inspect it.
bound_template = template_circuit.assign_parameters(outputs["parameter_values"][0])
bound_template.draw("mpl", idle_wires=False)더 나아가, 각 무작위화 과정이 원래 회로와 논리적으로 동등하다는 것을 확인할 수 있는데,
예를 들어 양쪽을 모두 Operator객체로 변환한 후 (측정 트위를링 효과를 제거하는 보정을outputs["measurement_flips.<register>"] 반영한 뒤)
그들의 유니터리 구현을 비교하거나, 국소 StatevectorEstimator실행 또는 전체 실행에서 얻은 기대값을 비교함으로써
StatevectorSampler확인할 수 있다. 자세한 단계별 안내는 Samplomatic
Samplex 입력 및 출력
가이드를 참조하십시오.
4단계. 촬영 요청 방식 변경
PUB 에 있는 샷을 로 이동합니다 QuantumProgram(shots=...). Executor에서는 전체 작업에 shots 적용됩니다. 샷 수가 다른 경우 여러 건의 작업을 제출하십시오.
샘플러:
# Run — shots are passed to run()
sampler = Sampler(mode=backend)
job = sampler.run([(isa_circuit, None, 25)])실행자:
# Build a QuantumProgram — shots are on the program
program = QuantumProgram(shots=25)
program.append_circuit_item(isa_circuit)5단계. 필요에 따라 옵션을 업데이트하십시오
Executor에는 Sampler보다 사용할 수 있는 옵션이 적습니다. 그 이유는 오류 완화 관련 선택 사항이 이제 옵션이 아닌 어노테이션과 samplex에 포함되어 있기 때문입니다.
설정이 저장되는 위치에도 구조적인 차이가 있습니다.
-
Sampler를 사용하면, 결과 후처리에 영향을 미치는 선택 사항을 포함하여 모든 설정이 프리미티브의 옵션이나 ‘ PUB ’에서 구성됩니다.
-
Executor를 사용하면 작업 결과물의 형성과 후처리 방식에 영향을 미치는 설정은 에서 이루어지며
QuantumProgram, 에서는 설정되지 않습니다ExecutorOptions.
예:
샘플러 | 실행기 |
|---|---|
shots | QuantumProgram(shots=...) |
meas_type | QuantumProgram(meas_level=...) |
ExecutorOptions 반환되는 데이터의 구조를 변경하지 않는
저수준 실행 및 환경 설정만 포함합니다. 다음과 같은 세 개의 최상위 그룹이 있습니다:
environment(EnvironmentOptions)execution(ExecutionOptions): Sampler에 비해 제공되는 옵션이 적습니다. 예를 들어,meas_type‘Executor’ 옵션은 없습니다.experimental
특히, 및 twirling dynamical_decoupling 옵션은 Sampler에는 있지만 Executor에는 없습니다. 대신, 이러한 옵션 값들은 방향성 실행 모델을 통해 표현됩니다.
예:
from qiskit_ibm_runtime import Executor, ExecutorOptions
options = ExecutorOptions(
environment={"log_level": "INFO"},
execution={"init_qubits": True},
)
# or mutate after construction:
options = ExecutorOptions()
options.environment.log_level = "INFO"
options.execution.init_qubits = True
executor = Executor(mode=backend, options=options)6단계. run 명령어 업데이트
Executor 작업의 입력은 PUB가 아닌 프로그램입니다.
샘플러:
# Submit a job
sampler.run([(isa_circuit, parameter_values)])실행자:
# Submit a job
executor.run(program)7단계. 결과를 확인하는 방법 변경하기
Executor에서는 결과가 객체가 BitArray 아니라 NumPy 형 배열입니다. 이름 문자열을 인덱스(result[0]["meas"])로 사용하여 결과를 np.ndarray 반환합니다. 속성 .data.<register> 경로를 기억할 필요는 없습니다.
Sampler에서 Executor로 업데이트하려면 를 로 result[i].data.<reg> (BitArray) 변경한 다음 result[i]["<reg>"] (np.ndarray), get_counts-기반 후처리를 NumPy 연산으로 다시 작성하십시오.
태스크 | 샘플러 | 실행기 |
|---|---|---|
| 등록 데이터 가져오기 | result[0].data.meas | result[0]["meas"] |
| 데이터 유형 | BitArray | np.ndarray |
| 카운트 사전 | result[0].data.meas.get_counts() | 배열을 수동으로 후처리합니다 |
| 여러 레지스터 | result[0].data.<name> 레지스터당 | result[0]["<name>"] 레지스터당 |
| CircuitItem 배열의 차원 | - | (parameter_sets, shots, register_bits) |
| SamplexItem 배열의 차원 | - | (randomizations, parameter_sets, shots, register_bits) |
| 측정값 회전 취소 | 자동 | result[i]["measurement_flips.<name>"] + XOR |
Sampler's는 헬퍼(get_counts, slice_bits, slice_shots, expectation_values, 및 선택 후 마스크)를 제공합니다 BitArray . Executor는 원시 NumPy 배열을 반환하므로, 표준 NumPy 연산을 사용하여 이 후처리를 수행할 수 있습니다.
8단계. 비트 반전으로 인한 결과 처리 (비트 반전 수정)
를 통해 측정값 트위를링(twirling)을 적용하면 SamplexItem, Executor는 원시
(트윌링된) 측정값과 트위를링 효과를 취소하는 데 필요한 비트 반전 보정값을 함께 반환합니다.
이 설정들은 수동으로 적용해야 하며, 자동으로 수정되는 부분은 없습니다.
Executor를 사용할 때는 다음 예제와 같이 수정 measurement_flips.<reg> 연산과 XOR 연산을 사용하여 트위를링 효과를 명시적으로 취소하십시오:
# SamplexItem result shape: (randomizations, parameter_sets, shots, register_bits)
result_1 = result[1]["meas"] # example: (28, 10, 1024, 2)
# Bit-flip corrections to undo measurement twirling
flips_1 = result[1]["measurement_flips.meas"] # example: (28, 10, 1, 2)
# Undo the twirling through classical XOR (broadcasts over the shots axis)
unflipped_result_1 = result_1 ^ flips_1Sampler에는 이에 상응하는 단계가 없는데, 이는 트와일링 효과를 자동으로 취소해 주기 때문입니다.
전체 예시: 기본 샘플링 작업 마이그레이션
샘플러
import numpy as np
from qiskit.circuit import QuantumCircuit
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler
# 1. Account + backend
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
# 2. Circuit
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.h(1)
circuit.cz(0, 1)
circuit.h(1)
circuit.measure_all()
# 3. Transpile to ISA
pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_circuit = pm.run(circuit)
# 4. Run — shots are passed to run()
sampler = Sampler(mode=backend)
job = sampler.run([(isa_circuit,)], shots=25)
result = job.result()
# 5. Access results: a BitArray keyed by register name
counts = result[0].data.meas.get_counts()실행기
import numpy as np
from qiskit.circuit import QuantumCircuit
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService, Executor
from qiskit_ibm_runtime.quantum_program import QuantumProgram
# 1. Account + backend (unchanged)
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
# 2. Circuit (unchanged)
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.h(1)
circuit.cz(0, 1)
circuit.h(1)
circuit.measure_all()
# 3. Transpile to ISA (unchanged)
pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_circuit = pm.run(circuit)
# 4. Build a QuantumProgram — shots are on the program
program = QuantumProgram(shots=25)
program.append_circuit_item(isa_circuit)
# 5. Run
executor = Executor(mode=backend)
job = executor.run(program)
result = job.result()
# 6. Access results: a plain np.ndarray keyed by register name
# shape = (shots, register_bits)
meas = result[0]["meas"]