Міграція з NoiseLearner до NoiseLearnerV3
Цей посібник проведе тебе через міграцію з IBM Quantum® NoiseLearner до NoiseLearnerV3. Обидва
класи виконують експерименти, що характеризують процеси шуму на основі
моделі шуму Паулі-Ліндблада, але вхідні та
вихідні дані дещо відрізняються.
Передумови
Клас NoiseLearner
було створено, щоб дозволити користувачам виконувати явне вивчення шуму. Отриману
модель шуму потім можна передати до IBM Quantum Estimator для застосування технік пом'якшення помилок,
таких як PEA та PEC.
NoiseLearner було розроблено для роботи з Estimator, і тому він неявно використовує ту саму
стратегію пошуку шарів, що й Estimator. Цю стратегію не можна змінити; інакше наступні кроки
пом'якшення не працювали б правильно.
Починаючи з qiskit-ibm-runtime v0.47.0, з'явився новий клас
NoiseLearnerV3,
сумісний з примітивом Executor та
моделлю спрямованого виконання.
Ця нова модель забезпечує досвід білої скриньки, надаючи компоненти для фіксації намірів проєктування
на стороні клієнта, а єдиний серверний примітив (Executor) обробляє ці вхідні дані точно так, як
вказано — він не приймає жодних неявних рішень від твого імені. На відміну від оригінального NoiseLearner,
ти контролюєш, як стратифікувати свої схеми, коли використовуєш NoiseLearnerV3, а клас просто приймає список загорнутих у box інструкцій схеми
(наприклад, унікальних шарів) як вхідні дані.
NoiseLearnerV3 також підтримує вивчення шуму вимірювання. Для кожної інструкції у вхідному списку він запускає
протокол вивчення Паулі-Ліндблада, якщо box містить одно- та двокубітні вентилі, та
протокол TREX,
якщо box містить вимірювання.
Чи варто тобі мігрувати?
NoiseLearner працює лише зі застарілим серверним Estimator, а NoiseLearnerV3 працює лише з
Executor та клієнтським Estimator. Тобі потрібно мігрувати до NoiseLearnerV3, якщо ти використовуєш
Executor або клієнтський Estimator. Застарілий серверний Estimator вважається застарілим і замінюється клієнтським еквівалентом у qiskit-ibm-runtime v0.50.0.
Якщо ти використовуєш qiskit-ibm-runtime v0.50.0 або пізнішу версію, спочатку прочитай посібник Міграція з серверних на клієнтські Sampler та Estimator, щоб мігрувати до клієнтських примітивів.
Кроки міграції
Крок 1: Зміни імпорти
NoiseLearner:
from qiskit_ibm_runtime.noise_learner import NoiseLearner
NoiseLearnerV3:
from qiskit_ibm_runtime import NoiseLearnerV3
Крок 2: Онови вхідні дані
Метод run() NoiseLearner приймає список схем або PUB, тоді як метод run() NoiseLearnerV3 приймає список інструкцій, кожна з яких має бути анотованим twirling'ом BoxOp, що містить ISA-операції.
Доступні зручні методи для генерування анотованих box'ів, залежно від того,
який примітив ти плануєш використовувати.
NoiseLearner:
from qiskit_ibm_runtime.noise_learner import NoiseLearner
learner = NoiseLearner(mode=backend)
# `circuits_to_learn` is a list of ISA QuantumCircuit
learner_job = learner.run(circuits_to_learn)
NoiseLearnerV3, при роботі з клієнтським Estimator:
Якщо ти плануєш використовувати клієнтський Estimator для виконання схем, ти можеш використати метод find_unique_layers від Estimator для створення анотованих box'ів (шарів):
from qiskit_ibm_runtime.executor_estimator import Estimator
from qiskit_ibm_runtime import NoiseLearnerV3
pubs = [...] # Your PUBs
estimator = Estimator(backend)
estimator.options.resilience.pec_mitigation = True # or zne_mitigation + pea amplifier
# Identify the unique layers to learn.
layers = estimator.find_unique_layers(pubs)
# Learn the noise model for those layers (runs as a separate job).
learner = NoiseLearnerV3(backend)
learner_job = learner.run(layers)
NoiseLearnerV3, при роботі з Executor:
Якщо ти плануєш використовувати Executor для виконання схем, розглянь використання функції generate_boxing_pass_manager з Samplomatic для створення анотованих box'ів:
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
# Run the boxing pass manager to group instructions into annotated boxes.
# `isa_circuit` is an ISA QuantumCircuit.
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)
# Instantiate a NoiseLearnerV3 object and execute the noise learning program.
learner = NoiseLearnerV3(backend)
learner_job = learner.run(unique_box_instructions)
Крок 3: Перетвори опції
Більшість полів NoiseLearnerOptions напряму зіставляються з NoiseLearnerV3Options, за винятком наступного:
-
max_layers_to_learn: ЗNoiseLearnerV3кількість шарів для вивчення базується на кількості переданих шарів. -
twirling_strategy: ЗNoiseLearnerV3стратегія twirling визначається тим, як інструкції упаковано в box та анотовано (наприклад, при використанніgenerate_boxing_pass_manager()).
NoiseLearner:
from qiskit_ibm_runtime.noise_learner import NoiseLearner
from qiskit_ibm_runtime.options import NoiseLearnerOptions
# Instantiate a NoiseLearnerOptions object
learner_options = NoiseLearnerOptions(
max_layers_to_learn=3, num_randomizations=32, twirling_strategy="all"
)
learner = NoiseLearner(mode=backend, options=learner_options)
learner_job = learner.run(circuits_to_learn)
NoiseLearnerV3, при роботі з клієнтським Estimator:
Якщо ти плануєш використовувати клієнтський Estimator для виконання схем, ти можеш
встановити опцію Estimator twirling.strategy:
from qiskit_ibm_runtime.executor_estimator import Estimator
from qiskit_ibm_runtime import NoiseLearnerV3
from qiskit_ibm_runtime.options_models import NoiseLearnerV3Options
pubs = [...] # Your PUBs
estimator = Estimator(backend)
estimator.options.resilience.pec_mitigation = True # or zne_mitigation + pea amplifier
estimator.options.twirling.strategy = "all" # set twirling strategy here
# Identify the unique layers to learn.
layers = estimator.find_unique_layers(pubs)
# Instantiate a NoiseLearnerV3 object and execute the noise learning program
learner_options = NoiseLearnerV3Options(num_randomizations=32)
learner = NoiseLearnerV3(backend, options=learner_options)
# Learn just the first 3 layers.
learner_job = learner.run(layers[:3])
NoiseLearnerV3, при роботі з Executor:
Якщо ти плануєш використовувати Executor для виконання схем, ти можеш передати опцію twirling_strategy до функції generate_boxing_pass_manager.
Зверни увагу, що з generate_boxing_pass_manager() значення twirling_strategy використовують підкреслення
("active_accum", "active_circuit"), тоді як значення NoiseLearnerOptions.twirling_strategy використовують дефіси ("active-accum", "active-circuit").
from qiskit_ibm_runtime.noise_learner_v3 import NoiseLearnerV3
from qiskit_ibm_runtime.options_models import NoiseLearnerV3Options
from samplomatic.transpiler import generate_boxing_pass_manager
from samplomatic.utils import find_unique_box_instructions
# Run the boxing pass manager to group instructions into annotated boxes
# `isa_circuit` is an ISA QuantumCircuit
boxing_pm = generate_boxing_pass_manager(
enable_gates=True,
enable_measures=False,
twirling_strategy="all", # twirling strategy can be specified here
inject_noise_targets="gates",
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)
learner_options = NoiseLearnerV3Options(num_randomizations=32)
# Instantiate a NoiseLearnerV3 object and execute the noise learning program
learner = NoiseLearnerV3(backend, options=learner_options)
# Learn just the first 3 layers.
learner_job = learner.run(unique_box_instructions[:3])
Крок 4: Перевір результати
Виходи NoiseLearner та NoiseLearnerV3 містять подібну інформацію, але в різних форматах. Онови свій код, якщо він явно перевіряє вихід.
Зіставлення атрибутів результату:
(learner_result — це вихід завдання learner)
| Атрибут | NoiseLearner | NoiseLearnerV3 |
|---|---|---|
| Тип результату | NoiseLearnerResult | NoiseLearnerV3Results, контейнер типу послідовності з NoiseLearnerV3Result |
| Кількість вивчених шарів | len(learner_result.data) | len(learner_result) |
| Дані для першого шару | layer_error = learner_result.data[0] | noise_map = learner_result[0].to_pauli_lindblad_map() |
| Тип результату кожного шару | LayerError (type(layer_error)) | PauliLindbladMap (type(noise_map)) |
| Генератори для каналу помилки | layer_error.error.generators | noise_map.generators() |
| Коефіцієнти помилок | layer_error.error.rates | noise_map.rates |
Крок 5: Введи модель шуму в примітив
NoiseLearner працює лише зі застарілим серверним Estimator, а NoiseLearnerV3 працює лише з Executor та клієнтським Estimator. Спосіб вказання моделі шуму трохи відрізняється залежно від того, який примітив використовується.
NoiseLearner, при роботі зі застарілим серверним Estimator:
from qiskit_ibm_runtime import Estimator as LegacyEstimator
learner_result = learner_job.result()
# Pass the noise model to the `estimator.options` attribute directly
estimator = LegacyEstimator(mode=backend)
estimator.options.resilience.layer_noise_model = learner_result
job = estimator.run(pubs)
NoiseLearnerV3, при роботі з клієнтським Estimator:
Використай повторно той самий Estimator, що видав layers на кроці 2. Карти шуму, повернуті
learner'ом, позиційно зіставлені з цими шарами, тож їх потрібно призначити тому Estimator,
з якого вони походять. PEA/PEC вже було увімкнено на ньому на кроці 2.
Зверни увагу, що хоча NoiseLearnerV3 підтримує обидва протоколи — Паулі-Ліндблада та TREX — Estimator приймає моделі шуму лише для двокубітних шарів, вивчених за протоколом Паулі-Ліндблада.
learner_result = learner_job.result()
# Convert results to Pauli-Lindblad noise maps.
pauli_lindblad_maps = learner_result.to_pauli_lindblad_maps()
# Assign the learned noise maps so PEA/PEC uses them.
estimator.options.resilience.layer_noise_model = zip(layers, pauli_lindblad_maps)
# Now execute the target PUBs.
job = estimator.run(pubs)
NoiseLearnerV3, при роботі з Executor:
from qiskit_ibm_runtime import Executor
from qiskit_ibm_runtime.quantum_program import QuantumProgram
# Generate a quantum program
program = QuantumProgram(shots=1000)
# Convert the NoiseLearnerV3 result to a dictionary
learner_result = learner_job.result()
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 та клієнтський 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()
NoiseLearnerV3 та Executor
from qiskit import QuantumCircuit
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService, Executor, NoiseLearnerV3
from qiskit_ibm_runtime.quantum_program import QuantumProgram
from samplomatic import build
from samplomatic.transpiler import generate_boxing_pass_manager
from samplomatic.utils import find_unique_box_instructions
# 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)
circuit.measure_all()
# 3. Transpile to ISA
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(circuit)
# 4. 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)
# 5. Find unique boxed instructions (layers)
unique_box_instructions = find_unique_box_instructions(boxed_circuit.data)
# 6. Learn the noise model for those layers
learner = NoiseLearnerV3(backend)
learner_job = learner.run(unique_box_instructions)
learner_result = learner_job.result()
# 7. Convert the NoiseLearnerV3 result to a dictionary
noise_maps = learner_result.to_dict(
instructions=unique_box_instructions, require_refs=False
)
# 8. Build the template circuit and samplex pair
template_circuit, samplex = build(boxed_circuit)
# 9. Prepare a quantum program
program = QuantumProgram(shots=1000)
program.append_samplex_item(
template_circuit,
samplex=samplex,
samplex_arguments={
"pauli_lindblad_maps": noise_maps,
},
)
executor = Executor(backend)
job = executor.run(program)
result = job.result()