Noise learning helper
Package versions
The code on this page was developed using the following requirements. We recommend using these versions or newer.
qiskit[all]~=2.4.1
qiskit-ibm-runtime~=0.47.0
samplomatic~=0.18.0
เทคนิค error mitigation PEA และ PEC ต่างใช้ noise learning component ที่อาศัย Pauli-Lindblad noise model ซึ่งโดยทั่วไปจัดการระหว่าง execution หลังจากส่ง job ผ่าน qiskit-ibm-runtime โดยไม่มีการเข้าถึง fitted noise model ในเครื่อง อย่างไรก็ตาม ตั้งแต่ qiskit-ibm-runtime v0.27.1 เป็นต้นมา ได้มีการสร้าง NoiseLearner และ class NoiseLearnerOptions ที่เกี่ยวข้อง เพื่อรับผลลัพธ์ของการทดลอง noise learning เหล่านี้ ผลลัพธ์เหล่านี้สามารถเก็บไว้ในเครื่องเป็น NoiseLearnerResult และใช้เป็น input ในการทดลองครั้งต่อไป หน้านี้ให้ภาพรวมของการใช้งานและตัวเลือกที่มี
นอกจากนี้ ตั้งแต่ qiskit-ibm-runtime v0.47.0 เป็นต้นมา มี class NoiseLearnerV3 ใหม่ที่รองรับการทำงานร่วมกับ Executor primitive เวอร์ชันใหม่นี้ ซึ่งเป็นส่วนหนึ่งของ directed execution model ด้วย ช่วยให้คุณสามารถระบุ layer ที่ต้องการเรียนรู้ได้อย่างชัดเจน
NoiseLearner ใช้งานได้กับ EstimatorV2 เท่านั้น และ NoiseLearnerV3 ใช้งานได้กับ Executor เท่านั้น
NoiseLearner
ภาพรวม
class NoiseLearner ทำการทดลองที่ characterize กระบวนการ noise ตาม Pauli-Lindblad noise model สำหรับ Circuit หนึ่งตัว (หรือมากกว่า) มี method run() ที่ execute การทดลอง learning และรับ input เป็นรายการ Circuit หรือ PUB และคืน NoiseLearnerResult ที่มี noise channel ที่เรียนรู้แล้วและ metadata เกี่ยวกับ job ที่ส่ง ด้านล่างคือ code snippet ที่แสดงการใช้งาน helper program
# 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 ที่ได้คือรายการของ LayerError object ที่มี noise model สำหรับแต่ละ entangling layer ที่เป็นส่วนหนึ่งของ Circuit เป้าหมาย แต่ละ LayerError เก็บข้อมูล layer ในรูปแบบของ Circuit และชุด qubit label ควบคู่กับ PauliLindbladError สำหรับ noise model ที่เรียนรู้สำหรับ layer นั้น
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]
attribute LayerError.error ของผลลัพธ์ noise learning มี generator และ error rate ของ fitted Pauli Lindblad model ซึ่งมีรูปแบบ
โดยที่ คือ LayerError.rates และ คือ Pauli operator ที่ระบุใน LayerError.generators
ตัวเลือก noise learning
คุณสามารถเลือกตัวเลือกหลายอย่างเพื่อใส่เมื่อสร้าง NoiseLearner object ตัวเลือกเหล่านี้ถูก encapsulate โดย class qiskit_ibm_runtime.options.NoiseLearnerOptions และรวมถึงความสามารถในการระบุจำนวน layer สูงสุดที่จะเรียนรู้ จำนวน randomization และ twirling strategy เป็นต้น ดูเอกสาร API ของ NoiseLearnerOptions สำหรับข้อมูลโดยละเอียด
ต่อไปนี้คือตัวอย่างง่ายๆ ที่แสดงวิธีใช้ NoiseLearnerOptions ในการทดลอง NoiseLearner:
# 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()
ส่ง noise model ให้กับ primitive
noise model ที่เรียนรู้บน Circuit ยังสามารถใช้เป็น input ให้กับ EstimatorV2 primitive ที่ implement ใน Qiskit Runtime ซึ่งสามารถส่งเข้า primitive ได้หลายวิธี ตัวอย่างสามตัวถัดไปแสดงวิธีที่คุณสามารถส่ง noise model ไปยัง attribute estimator.options โดยตรง โดยใช้ ResilienceOptionsV2 object ก่อนสร้าง Estimator primitive และโดยการส่ง dictionary ที่จัดรูปแบบอย่างเหมาะสม
# 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)
หลังจากส่ง noise model เข้าไปใน EstimatorV2 object แล้ว สามารถใช้รัน workload และทำ error mitigation ได้ตามปกติ
NoiseLearnerV3
ภาพรวม
คล้ายกับ NoiseLearner class NoiseLearnerV3 ทำการทดลองที่ characterize กระบวนการ noise ตาม Pauli-Lindblad noise model สำหรับ Circuit หนึ่งตัวหรือมากกว่า method run() รับรายการคำสั่ง แต่ละคำสั่งต้องเป็น BoxOp ที่มี twirl annotation ซึ่งบรรจุ ISA operation
ผลลัพธ์ของ NoiseLearnerV3 job ประกอบด้วยรายการของ NoiseLearnerV3Result หนึ่งชุดต่อคำสั่ง input
code ต่อไปนี้แสดงวิธีใช้ helper program
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')]
ผลลัพธ์ของ job คือรายการของ NoiseLearnerV3Result หนึ่งชุดต่อชุดคำสั่ง box input NoiseLearnerV3Result มี method to_pauli_lindblad_map() ที่คืน object PauliLindbladMap ซึ่งมี method สำหรับดึง generator, error rate และอื่นๆ
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]
ตัวเลือก noise learning
NoiseLearnerV3 รองรับตัวเลือกหลายอย่าง รวมถึงจำนวน randomization และ layer pair depth เป็นต้น คล้ายกับ primitive คุณสามารถระบุตัวเลือกระหว่างหรือหลังจากสร้าง NoiseLearnerV3 object ตัวอย่าง code ก่อนหน้าแสดงวิธีตั้งค่า shots_per_randomization และ num_randomizations ดูเอกสาร API ของ NoiseLearnerV3Options สำหรับข้อมูลโดยละเอียด
ส่ง noise model ให้กับ Executor
Executor ปฏิบัติตาม design intent ที่ระบุใน circuit annotation (ในรูปแบบ samplex) และ option InjectNoise คือ annotation สำหรับระบุตำแหน่งที่จะ inject noise และ argument pauli_lindblad_maps ของ samplex ระบุ noise map ที่จะใช้
Circuit ในตัวอย่างก่อนหน้าถูกรันผ่าน boxing pass manager ซึ่งจัดกลุ่มคำสั่งเป็น box ที่มี annotation code ที่เกี่ยวข้องถูกเพิ่มไว้ที่นี่เพื่อความเข้าใจ
inject_noise_targets="gates"ระบุให้เพิ่มInjectNoiseannotation ให้กับ box ที่มี entanglerinject_noise_strategy="uniform_modification"ระบุให้กำหนดrefและmodifier_refเดียวกันให้กับ box ที่เทียบเท่าทั้งหมดที่มีInjectNoiseannotationInjectNoise.refคือ identifier เฉพาะที่ใช้กำหนด noise model ให้กับ box นั้นInjectNoise.modifier_refช่วยให้ scale noise model ที่กำหนดให้กับ box ด้วยตัวคูณ
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 จากตัวอย่างก่อนหน้ามี box สามชุด สองชุดในนั้นมี InjectNoise annotation ที่มี attribute ref ต่างกัน (เนื่องจากไม่เทียบเท่ากัน)
# 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 job ต้องแปลงเป็น dictionary ก่อนส่งให้ Executor key ของ dictionary นี้คือ attribute InjectNoise.ref และ value คือ noise map ที่สอดคล้องกัน การ mapping นี้บอก Executor ว่าจะ inject noise model ใดที่ตำแหน่งใด
code ต่อไปนี้แสดงวิธีนำ Circuit และผลลัพธ์ NoiseLearnerV3 จากตัวอย่างก่อนหน้าส่งให้ Executor ซึ่งจะสร้าง circuit variant ที่มี noise model ที่ inject แล้วและรันบน hardware
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 reference และ ResilienceOptionsV2 API reference
- เรียนรู้เพิ่มเติมเกี่ยวกับ Error mitigation and suppression techniques ที่มีผ่าน Qiskit Runtime
- เรียนรู้วิธี implement Estimator noise management
- อ่าน Migrate to V2 primitives