ข้ามไปยังเนื้อหาหลัก
โครงการนี้อยู่ในช่วงเบต้า พบข้อผิดพลาด? สร้าง GitHub Issue มีคำถามหรือไอเดีย? ถามใน Discussions — ยินดีรับฟังความคิดเห็น!
คุณภาพการแปลในหน้านี้เป็นอย่างไร?

Noise learning helper

Package versions

โค้ดในหน้านี้พัฒนาโดยใช้ข้อกำหนดต่อไปนี้ เราแนะนำให้ใช้เวอร์ชันเหล่านี้หรือใหม่กว่า

qiskit[all]~=2.5.2
qiskit-ibm-runtime~=0.47.0
samplomatic~=0.21.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 ใช้งานได้กับ server-side EstimatorV2 เท่านั้น และ NoiseLearnerV3 ใช้งานได้กับ Executor และ client-side Estimator ใหม่ (เปิดตัวใน qiskit-ibm-runtime v0.50.0) เท่านั้น

NoiseLearnerV3​

ภาพรวม​

คล้ายกับ NoiseLearner class NoiseLearnerV3 ทำการทดลองที่ characterize กระบวนการ noise ตาม Pauli-Lindblad noise model สำหรับ Circuit หนึ่งตัวหรือมากกว่า method run() รับรายการคำสั่ง แต่ละคำสั่งต้องเป็น BoxOp ที่มี twirl annotation ซึ่งบรรจุ ISA operation

ผลลัพธ์ของ NoiseLearnerV3 job ประกอบด้วยรายการของ NoiseLearnerV3Result หนึ่งชุดต่อคำสั่ง input โค้ดต่อไปนี้แสดงวิธีใช้ helper program

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"numpy": "numpy", "qiskit": "qiskit", "qiskit_ibm_runtime": "qiskit-ibm-runtime", "samplomatic": "samplomatic"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
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='r223A', modifier_ref='', site='after')]

ผลลัพธ์ของ job คือรายการของ NoiseLearnerV3Result หนึ่งรายการต่อชุดคำสั่งที่อยู่ใน box แต่ละ box ที่ป้อนเข้าไป NoiseLearnerV3Result มี method to_pauli_lindblad_map() ที่คืน object PauliLindbladMap ซึ่งมี method สำหรับดึง generator, error rate และอื่นๆ

import numpy

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_5, Y_5, Z_5]>

Along with the error rates (truncated to 3):
[2.3e-04 9.0e-05 1.1e-04]

ตัวเลือก 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 โค้ดที่เกี่ยวข้องถูกเพิ่มไว้ที่นี่เพื่อความเข้าใจง่าย

  • inject_noise_targets=”gates” ระบุให้เพิ่ม annotation InjectNoise ลงใน box ที่มี entangler
  • inject_noise_strategy="uniform_modification" ระบุให้กำหนด ref และ modifier_ref เดียวกันให้กับ box ที่เทียบเท่ากันทั้งหมดที่มี annotation InjectNoise
    • InjectNoise.ref เป็นตัวระบุที่ไม่ซ้ำกันซึ่งใช้เพื่อกำหนด noise model ให้กับ box นั้น
    • InjectNoise.modifier_ref ช่วยให้สามารถปรับขนาด 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 โดยสอง 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='r223A', modifier_ref='r223A', site='after')]

Annotations of box #1: [Twirl(group='pauli', dressing='left', decomposition='rzsx'), InjectNoise(ref='r621A', modifier_ref='r621A', site='after')]

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)

การใช้ NoiseLearnerV3 กับ client-side Estimator​

โค้ดต่อไปนี้แสดงวิธีใช้ helper program กับ client-side Estimator ตัวใหม่

from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

from qiskit_ibm_runtime import QiskitRuntimeService, NoiseLearnerV3
from qiskit_ibm_runtime.executor_estimator import Estimator

# 1. Account + backend
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

# 2. Circuit + observable
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.cx(0, 1)

observable = SparsePauliOp("ZZ")

# 3. Transpile to ISA
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(circuit)
isa_observable = observable.apply_layout(isa_circuit.layout)
pubs = [(isa_circuit, isa_observable)]

# 4. Initialize Estimator with options
estimator = Estimator(backend)
estimator.options.resilience.pec_mitigation = True

# 5. Extract the unique boxed layers from PUBs
layers = estimator.find_unique_layers(pubs)

# 6. Learn the noise model for those layers.
learner = NoiseLearnerV3(backend)
learner_job = learner.run(layers)
learner_result = learner_job.result()

# 7. Convert the result to Pauli-Lindblad maps and pass them to Estimator.
pauli_lindblad_maps = learner_result.to_pauli_lindblad_maps()
estimator.options.resilience.layer_noise_model = zip(
layers, pauli_lindblad_maps
)

# 8. Execute the target PUBs.
job = estimator.run(pubs)
result = job.result()

NoiseLearner​

ตั้งแต่ qiskit_ibm_runtime v0.51.0 เป็นต้นไป NoiseLearner เลิกใช้แล้ว (deprecated) ดู Migrate to NoiseLearnerV3 สำหรับวิธีการย้าย

คลิกเพื่ออ่านเพิ่มเติม

ภาพรวม​

คลาส NoiseLearner ทำการทดลองที่หาลักษณะเฉพาะของกระบวนการ noise ตาม Pauli-Lindblad noise model สำหรับ Circuit หนึ่งตัว (หรือมากกว่า) มี method run() ที่ใช้รันการทดลอง noise learning และรับ input เป็นรายการ Circuit หรือ PUB และคืน NoiseLearnerResult ที่มี noise channel ที่เรียนรู้แล้วและ metadata เกี่ยวกับ jobs ที่ส่งไป ด้านล่างคือโค้ดตัวอย่างที่แสดงการใช้งาน 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, 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 objects ที่มี noise model สำหรับแต่ละ entangling layer ที่เป็นส่วนหนึ่งของ target circuits แต่ละ LayerError เก็บข้อมูล layer ในรูปแบบของ Circuit และชุด qubit labels ควบคู่กับ 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"
)

attribute LayerError.error ของผลลัพธ์ noise learning มี generator และ error rate ของ fitted Pauli Lindblad model ซึ่งมีรูปแบบ

Λ(ρ)=exp⁡∑jrj(PjρPj†−ρ),\Lambda(\rho) = \exp{\sum_j r_j \left(P_j \rho P_j^\dagger - \rho\right)},

โดยที่ rjr_j คือ LayerError.rates และ PjP_j คือ Pauli operator ที่ระบุใน LayerError.generators

ตัวเลือก Noise learning​

เมื่อสร้าง object NoiseLearner คุณสามารถกำหนดตัวเลือกได้หลายอย่าง ตัวเลือกเหล่านี้ถูก 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 ให้กับ IBM Quantum EstimatorV2 primitive ซึ่งสามารถส่งเข้า primitive ได้หลายวิธี ตัวอย่างสามตัวถัดไปแสดงวิธีที่คุณสามารถส่ง noise model ไปยัง attribute estimator.options โดยตรง โดยใช้ ResilienceOptionsV2 object ก่อนสร้าง Estimator primitive และโดยการส่ง dictionary ที่จัดรูปแบบอย่างเหมาะสม

# Option 1: Pass the noise model to the `estimator.options` attribute directly
estimator = EstimatorV2(mode=backend)
estimator.options.resilience.layer_noise_model = noise_model

# Option 2: 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)

# Option 3: 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 แล้ว สามารถใช้รัน workloads และทำ error mitigation ได้ตามปกติ

ขั้นตอนถัดไป​

Recommendations