Перейти до основного вмісту

Міграція з 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)

АтрибутNoiseLearnerNoiseLearnerV3
Тип результатуNoiseLearnerResultNoiseLearnerV3Results, контейнер типу послідовності з 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.generatorsnoise_map.generators()
Коефіцієнти помилокlayer_error.error.ratesnoise_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()

Посилання​