노이즈 학습 도우미
패키지 버전
이 페이지의 코드는 다음 요구 사항을 사용하여 개발되었습니다. 이 버전 이상을 사용하시는 것을 권장합니다.
qiskit[all]~=2.4.1
qiskit-ibm-runtime~=0.47.0
samplomatic~=0.18.0
오류 완화 기법인 PEA와 PEC는 모두 Pauli-Lindblad 노이즈 모델을 기반으로 한 노이즈 학습 구성 요소를 활용합니다. 이 노이즈 학습 구성 요소는 일반적으로 qiskit-ibm-runtime을 통해 하나 이상의 작업을 제출한 후 실행 중에 관리되며, 피팅된 노이즈 모델에 로컬로 접근할 수 없습니다. 그러나 qiskit-ibm-runtime v0.27.1부터는 NoiseLearner와 관련된 NoiseLearnerOptions 클래스가 생성되어 이러한 노이즈 학습 실험의 결과를 얻을 수 있게 되었습니다. 이 결과는 NoiseLearnerResult로 로컬에 저장하고 이후 실험의 입력으로 사용할 수 있습니다. 이 페이지에서는 사용법과 관련 옵션에 대한 개요를 제공합니다.
또한, qiskit-ibm-runtime v0.47.0부터는 Executor 프리미티브와 호환되는 새로운 NoiseLearnerV3 클래스가 추가되었습니다. 지시된 실행 모델의 일부이기도 한 이 새 버전을 통해 학습할 레이어를 명시적으로 지정할 수 있습니다.
NoiseLearner는 EstimatorV2에서만 작동하며, NoiseLearnerV3는 Executor에서만 작동합니다.
NoiseLearner
개요
NoiseLearner 클래스는 하나 이상의 Circuit에 대해 Pauli-Lindblad 노이즈 모델을 기반으로 노이즈 프로세스를 특성화하는 실험을 수행합니다. 이 클래스는 학습 실험을 실행하는 run() 메서드를 가지고 있으며, Circuit 목록 또는 PUB을 입력으로 받아 학습된 노이즈 채널과 제출된 작업에 대한 메타데이터를 포함하는 NoiseLearnerResult를 반환합니다. 아래는 도우미 프로그램의 사용법을 보여주는 코드 예시입니다.
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime samplomatic
from qiskit import QuantumCircuit
from qiskit.transpiler import CouplingMap
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService, EstimatorV2
from qiskit_ibm_runtime.noise_learner import NoiseLearner
from qiskit_ibm_runtime.options import (
NoiseLearnerOptions,
ResilienceOptionsV2,
EstimatorOptions,
)
# Build a circuit with two entangling layers
num_qubits = 27
edges = list(CouplingMap.from_line(num_qubits, bidirectional=False))
even_edges = edges[::2]
odd_edges = edges[1::2]
circuit = QuantumCircuit(num_qubits)
for pair in even_edges:
circuit.cx(pair[0], pair[1])
for pair in odd_edges:
circuit.cx(pair[0], pair[1])
# Choose a backend to run on
service = QiskitRuntimeService()
backend = service.least_busy()
# Transpile the circuit for execution
pm = generate_preset_pass_manager(backend=backend, optimization_level=3)
circuit_to_learn = pm.run(circuit)
# Instantiate a NoiseLearner object and execute the noise learning program
learner = NoiseLearner(mode=backend)
job = learner.run([circuit_to_learn])
noise_model = job.result()
결과로 반환되는 NoiseLearnerResult.data는 대상 Circuit에 속하는 각 개별 얽힘 레이어에 대한 노이즈 모델을 포함하는 LayerError 객체의 목록입니다. 각 LayerError는 Circuit 및 qubit 레이블 집합의 형태로 레이어 정보와 함께, 주어진 레이어에 대해 학습된 노이즈 모델의 PauliLindbladError를 저장합니다.
import numpy
print(
f"Noise learner result contains {len(noise_model.data)} entries"
f" and has the following type:\n {type(noise_model)}\n"
)
print(
f"Each element of `NoiseLearnerResult` then contains"
f" an object of type:\n {type(noise_model.data[0])}\n"
)
# Results are truncated
with numpy.printoptions(threshold=200):
print(
f"And each of these `LayerError` objects possess"
f" data on the generators for the error channel: \n"
f"{noise_model.data[0].error.generators}\n"
)
# Results are truncated
with numpy.printoptions(threshold=200):
print(
f"Along with the error rates: \n{noise_model.data[0].error.rates}\n"
)
Noise learner result contains 2 entries and has the following type:
<class 'qiskit_ibm_runtime.utils.noise_learner_result.NoiseLearnerResult'>
Each element of `NoiseLearnerResult` then contains an object of type:
<class 'qiskit_ibm_runtime.utils.noise_learner_result.LayerError'>
And each of these `LayerError` objects possess data on the generators for the error channel:
['IIIIIIIIIIIIIIIIIIIIIIIIIIX', 'IIIIIIIIIIIIIIIIIIIIIIIIIIY',
'IIIIIIIIIIIIIIIIIIIIIIIIIIZ', 'IIIIIIIIIIIIIIIIIIIIIIIIIXI',
'IIIIIIIIIIIIIIIIIIIIIIIIIXX', 'IIIIIIIIIIIIIIIIIIIIIIIIIXY',
'IIIIIIIIIIIIIIIIIIIIIIIIIXZ', 'IIIIIIIIIIIIIIIIIIIIIIIIIYI',
'IIIIIIIIIIIIIIIIIIIIIIIIIYX', 'IIIIIIIIIIIIIIIIIIIIIIIIIYY',
'IIIIIIIIIIIIIIIIIIIIIIIIIYZ', 'IIIIIIIIIIIIIIIIIIIIIIIIIZI',
'IIIIIIIIIIIIIIIIIIIIIIIIIZX', 'IIIIIIIIIIIIIIIIIIIIIIIIIZY',
'IIIIIIIIIIIIIIIIIIIIIIIIIZZ', 'IIIIIIIIIIIIIIIIIIIIIIIIXII',
'IIIIIIIIIIIIIIIIIIIIIIIIXIX', 'IIIIIIIIIIIIIIIIIIIIIIIIXIY',
'IIIIIIIIIIIIIIIIIIIIIIIIXIZ', 'IIIIIIIIIIIIIIIIIIIIIIIIYII',
'IIIIIIIIIIIIIIIIIIIIIIIIYIX', 'IIIIIIIIIIIIIIIIIIIIIIIIYIY',
'IIIIIIIIIIIIIIIIIIIIIIIIYIZ', 'IIIIIIIIIIIIIIIIIIIIIIIIZII',
'IIIIIIIIIIIIIIIIIIIIIIIIZIX', 'IIIIIIIIIIIIIIIIIIIIIIIIZIY',
'IIIIIIIIIIIIIIIIIIIIIIIIZIZ', 'IIIIIIIIIIIIIIIIIIIIIIIXIII',
'IIIIIIIIIIIIIIIIIIIIIIIYIII', 'IIIIIIIIIIIIIIIIIIIIIIIZIII',
'IIIIIIIIIIIIIIIIIIIIIIXIIII', 'IIIIIIIIIIIIIIIIIIIIIIXXIII',
'IIIIIIIIIIIIIIIIIIIIIIXYIII', 'IIIIIIIIIIIIIIIIIIIIIIXZIII',
'IIIIIIIIIIIIIIIIIIIIIIYIIII', 'IIIIIIIIIIIIIIIIIIIIIIYXIII',
'IIIIIIIIIIIIIIIIIIIIIIYYIII', 'IIIIIIIIIIIIIIIIIIIIIIYZIII',
'IIIIIIIIIIIIIIIIIIIIIIZIIII', 'IIIIIIIIIIIIIIIIIIIIIIZXIII',
'IIIIIIIIIIIIIIIIIIIIIIZYIII', 'IIIIIIIIIIIIIIIIIIIIIIZZIII',
'IIIIIIIIIIIIIIIIIIIIIXIIIII', 'IIIIIIIIIIIIIIIIIIIIIXXIIII',
'IIIIIIIIIIIIIIIIIIIIIXYIIII', 'IIIIIIIIIIIIIIIIIIIIIXZIIII',
'IIIIIIIIIIIIIIIIIIIIIYIIIII', 'IIIIIIIIIIIIIIIIIIIIIYXIIII',
'IIIIIIIIIIIIIIIIIIIIIYYIIII', 'IIIIIIIIIIIIIIIIIIIIIYZIIII',
'IIIIIIIIIIIIIIIIIIIIIZIIIII', 'IIIIIIIIIIIIIIIIIIIIIZXIIII',
'IIIIIIIIIIIIIIIIIIIIIZYIIII', 'IIIIIIIIIIIIIIIIIIIIIZZIIII',
'IIIIIIIIIIIIIIIIIIIIXIIIIII', 'IIIIIIIIIIIIIIIIIIIIXXIIIII',
'IIIIIIIIIIIIIIIIIIIIXYIIIII', 'IIIIIIIIIIIIIIIIIIIIXZIIIII',
'IIIIIIIIIIIIIIIIIIIIYIIIIII', 'IIIIIIIIIIIIIIIIIIIIYXIIIII',
'IIIIIIIIIIIIIIIIIIIIYYIIIII', 'IIIIIIIIIIIIIIIIIIIIYZIIIII',
'IIIIIIIIIIIIIIIIIIIIZIIIIII', 'IIIIIIIIIIIIIIIIIIIIZXIIIII',
'IIIIIIIIIIIIIIIIIIIIZYIIIII', 'IIIIIIIIIIIIIIIIIIIIZZIIIII',
'IIIIIIIIIIIIIIIIIIIXIIIIIII', 'IIIIIIIIIIIIIIIIIIIXXIIIIII',
'IIIIIIIIIIIIIIIIIIIXYIIIIII', 'IIIIIIIIIIIIIIIIIIIXZIIIIII',
'IIIIIIIIIIIIIIIIIIIYIIIIIII', 'IIIIIIIIIIIIIIIIIIIYXIIIIII',
'IIIIIIIIIIIIIIIIIIIYYIIIIII', 'IIIIIIIIIIIIIIIIIIIYZIIIIII', ...]
Along with the error rates:
[5.9e-04 5.3e-04 5.7e-04 ... 0.0e+00 1.0e-05 0.0e+00]
노이즈 학습 결과의 LayerError.error 속성에는 피팅된 Pauli Lindblad 모델의 생성자와 오류율이 포함되어 있으며, 다음과 같은 형태를 가집니다.
여기서 는 LayerError.rates이고, 는 LayerError.generators에 지정된 Pauli 연산자입니다.
노이즈 학습 옵션
NoiseLearner 객체를 인스턴스화할 때 여러 옵션을 입력으로 선택할 수 있습니다. 이 옵션들은 qiskit_ibm_runtime.options.NoiseLearnerOptions 클래스로 캡슐화되어 있으며, 학습할 최대 레이어 수, 무작위화 횟수, 트월링 전략 등을 지정하는 기능을 포함합니다. 더 자세한 내용은 NoiseLearnerOptions API 문서를 참조하세요.
다음은 NoiseLearner 실험에서 NoiseLearnerOptions를 사용하는 방법을 보여주는 간단한 예시입니다.
# Build a GHZ circuit
circuit = QuantumCircuit(10)
circuit.h(0)
circuit.cx(range(0, 9), range(1, 10))
# Choose a backend to run on
service = QiskitRuntimeService()
backend = service.least_busy()
# Transpile the circuit for execution
pm = generate_preset_pass_manager(backend=backend, optimization_level=3)
circuit_to_run = pm.run(circuit_to_learn)
# Instantiate a NoiseLearnerOptions object
learner_options = NoiseLearnerOptions(
max_layers_to_learn=3, num_randomizations=32, twirling_strategy="all"
)
# Instantiate a NoiseLearner object and execute the noise learning program
learner = NoiseLearner(mode=backend, options=learner_options)
job = learner.run([circuit_to_run])
noise_model = job.result()
프리미티브에 노이즈 모델 입력하기
Circuit에서 학습된 노이즈 모델은 Qiskit Runtime에서 구현된 EstimatorV2 프리미티브의 입력으로도 사용할 수 있습니다. 이는 몇 가지 다른 방법으로 프리미티브에 전달할 수 있습니다. 다음 세 가지 예시는 estimator.options 속성에 직접, ResilienceOptionsV2 객체를 사용하여 Estimator 프리미티브를 인스턴스화하기 전에, 그리고 적절히 형식화된 딕셔너리를 전달하여 노이즈 모델을 전달하는 방법을 보여줍니다.
# Pass the noise model to the `estimator.options` attribute directly
estimator = EstimatorV2(mode=backend)
estimator.options.resilience.layer_noise_model = noise_model
# Specify options through a ResilienceOptionsV2 object
resilience_options = ResilienceOptionsV2(layer_noise_model=noise_model)
estimator_options = EstimatorOptions(resilience=resilience_options)
estimator = EstimatorV2(mode=backend, options=estimator_options)
# Specify options by using a dictionary
options_dict = {
"resilience_level": 2,
"resilience": {"layer_noise_model": noise_model},
}
estimator = EstimatorV2(mode=backend, options=options_dict)
노이즈 모델이 EstimatorV2 객체에 전달되면, 평소와 같이 워크로드를 실행하고 오류 완화를 수행하는 데 사용할 수 있습니다.
NoiseLearnerV3
개요
NoiseLearner와 유사하게, NoiseLearnerV3 클래스는 하나 이상의 Circuit에 대해 Pauli-Lindblad 노이즈 모델을 기반으로 노이즈 프로세스를 특성화하는 실험을 수행합니다. 이 클래스의 run() 메서드는 각각이 ISA 연산을 포함하는 트월링 어노테이션된 BoxOp인 명령어 목록을 받습니다.
NoiseLearnerV3 작업의 결과에는 각 입력 명령어에 대해 하나씩 NoiseLearnerV3Result 객체의 목록이 포함됩니다.
다음 코드는 도우미 프로그램을 사용하는 방법을 보여줍니다.
from qiskit import QuantumCircuit
from qiskit.transpiler import CouplingMap
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService, Executor
from qiskit_ibm_runtime.noise_learner_v3 import NoiseLearnerV3
from samplomatic.transpiler import generate_boxing_pass_manager
from samplomatic.utils import find_unique_box_instructions
# Build a circuit with two entangling layers
num_qubits = 27
edges = list(CouplingMap.from_line(num_qubits, bidirectional=False))
even_edges = edges[::2]
odd_edges = edges[1::2]
circuit = QuantumCircuit(num_qubits)
for pair in even_edges:
circuit.cx(pair[0], pair[1])
for pair in odd_edges:
circuit.cx(pair[0], pair[1])
# Choose a backend to run on
service = QiskitRuntimeService()
backend = service.least_busy()
# Transpile the circuit for execution
pm = generate_preset_pass_manager(backend=backend, optimization_level=3)
isa_circuit = pm.run(circuit)
# Run the boxing pass manager to group instructions into annotated boxes
boxing_pm = generate_boxing_pass_manager(
enable_gates=True,
enable_measures=False,
inject_noise_targets="gates", # no measurement mitigation
inject_noise_strategy="uniform_modification",
)
boxed_circuit = boxing_pm.run(isa_circuit)
# Find unique boxed instructions
unique_box_instructions = find_unique_box_instructions(boxed_circuit.data)
print(f"Found {len(unique_box_instructions)} unique layers")
print(
f"Each instruction is of type {type(unique_box_instructions[0].operation)}"
)
print(
f"And has annotations: {unique_box_instructions[0].operation.annotations}"
)
# Instantiate a NoiseLearnerV3 object and execute the noise learning program
learner = NoiseLearnerV3(backend)
learner.options.shots_per_randomization = 128
learner.options.num_randomizations = 32
learner_job = learner.run(unique_box_instructions)
learner_result = learner_job.result()
Found 3 unique layers
Each instruction is of type <class 'qiskit.circuit.controlflow.box.BoxOp'>
And has annotations: [Twirl(group='pauli', dressing='left', decomposition='rzsx'), InjectNoise(ref='r789B', modifier_ref='', site='before')]
작업 결과는 입력된 박스형 명령어 집합 각각에 대한 NoiseLearnerV3Result 객체의 목록입니다. NoiseLearnerV3Result에는 생성자, 오류율 등을 추출하는 메서드를 가진 PauliLindbladMap 객체를 반환하는 to_pauli_lindblad_map() 메서드가 있습니다.
print(
f"The Noise learner V3 result contains {len(learner_result)} entries"
f" and each has the following type:\n {type(learner_result[0])}\n"
)
noise_map = learner_result[0].to_pauli_lindblad_map()
print(
f"After converting to PauliLindbladMap, you can extract data "
f" on the generators for the error channel "
f"(truncated to 3): \n{noise_map.generators()[:3]}\n"
)
with numpy.printoptions(threshold=20):
print(
f"Along with the error rates "
f"(truncated to 3): \n{noise_map.rates[:3]}\n"
)
The Noise learner V3 result contains 3 entries and each has the following type:
<class 'qiskit_ibm_runtime.results.noise_learner_v3.NoiseLearnerV3Result'>
After converting to PauliLindbladMap, you can extract data on the generators for the error channel (truncated to 3):
<QubitSparsePauliList with 3 elements on 27 qubits: [X_0, Y_0, Z_0]>
Along with the error rates (truncated to 3):
[0.00026 0.00032 0.00023]
노이즈 학습 옵션
NoiseLearnerV3는 무작위화 횟수 및 레이어 쌍 깊이 등 여러 옵션을 지원합니다. 프리미티브와 유사하게, NoiseLearnerV3 객체를 인스턴스화하는 동안 또는 이후에 옵션을 지정할 수 있습니다. 이전 코드 예시에서는 shots_per_randomization과 num_randomizations 옵션을 설정하는 방법을 보여줬습니다. 자세한 내용은 NoiseLearnerV3Options API 문서를 참조하세요.
Executor에 노이즈 모델 입력하기
Executor는 Circuit 어노테이션(samplex 형태)과 옵션에 지정된 설계 의도를 따릅니다. InjectNoise는 노이즈를 주입할 위치를 지정하는 어노테이션이며, pauli_lindblad_maps samplex 인수는 사용할 노이즈 맵을 지정합니다.
이전 예시의 Circuit은 명령어를 어노테이션된 박스로 그룹화하는 박싱 패스 매니저를 통해 실행됩니다. 이해를 돕기 위해 관련 코드를 여기에 추가합니다.
inject_noise_targets="gates"는 얽힘 게이트를 포함하는 박스에InjectNoise어노테이션을 추가하도록 지정합니다.inject_noise_strategy="uniform_modification"은InjectNoise어노테이션이 있는 동일한 모든 박스에 동일한ref와modifier_ref를 할당하도록 지정합니다.InjectNoise.ref는 해당 박스에 노이즈 모델을 할당하는 데 사용되는 고유 식별자입니다.InjectNoise.modifier_ref는 박스에 할당된 노이즈 모델을 곱셈 인수로 스케일링할 수 있게 합니다.
boxing_pm = generate_boxing_pass_manager(
enable_gates=True,
enable_measures=False,
inject_noise_targets="gates", # no measurement mitigation
inject_noise_strategy="uniform_modification",
)
이전 예시의 Circuit에는 세 개의 박스가 있으며, 그 중 두 개는 서로 다른 ref 속성을 가진 InjectNoise 어노테이션을 포함합니다(동일하지 않기 때문입니다).
# box_circuit comes from the example above
for idx, instruction in enumerate(boxed_circuit):
# The `InjectNoise` annotation defines which boxes to inject noise.
print(f"Annotations of box #{idx}: {instruction.operation.annotations}\n")
Annotations of box #0: [Twirl(group='pauli', dressing='left', decomposition='rzsx'), InjectNoise(ref='r789B', modifier_ref='r789B', site='before')]
Annotations of box #1: [Twirl(group='pauli', dressing='left', decomposition='rzsx'), InjectNoise(ref='r054B', modifier_ref='r054B', site='before')]
Annotations of box #2: [Twirl(group='pauli', dressing='right', decomposition='rzsx')]
NoiseLearnerV3 작업의 결과는 Executor에 전달하기 전에 딕셔너리로 변환해야 합니다. 이 딕셔너리의 키는 InjectNoise.ref 속성이고 값은 해당 노이즈 맵입니다. 이 매핑은 Executor에 어떤 노이즈 모델을 어디에 주입할지 알려줍니다.
다음 코드는 이전 예시의 Circuit과 NoiseLearnerV3 결과를 가져와 Executor에 전달하는 방법을 보여줍니다. Executor는 주입된 노이즈 모델로 Circuit 변형을 생성하고 하드웨어에서 실행합니다.
from qiskit_ibm_runtime.quantum_program import QuantumProgram
from samplomatic import build
# Generate a quantum program
program = QuantumProgram(shots=1000)
# Build the template circuit and samplex pair
template_circuit, samplex = build(boxed_circuit)
# Convert the NoiseLearnerV3 result to a dictionary
noise_maps = learner_result.to_dict(
instructions=unique_box_instructions, require_refs=False
)
# Append the samplex item and execute
program.append_samplex_item(
template_circuit,
samplex=samplex,
samplex_arguments={
"pauli_lindblad_maps": noise_maps,
},
)
executor = Executor(backend)
executor_job = executor.run(program)
다음 단계
- EstimatorOptions API 참조와 ResilienceOptionsV2 API 참조를 검토하세요.
- Qiskit Runtime을 통해 사용할 수 있는 오류 완화 및 억제 기법에 대해 더 알아보세요.
- Estimator 노이즈 관리 구현 방법을 알아보세요.
- V2 프리미티브로 마이그레이션을 읽어보세요.