Помічник навчання шуму
Package versions
Код на цій сторінці розроблено з використанням наведених нижче вимог. Рекомендуємо використовувати ці або новіші версії.
qiskit[all]~=2.5.2
qiskit-ibm-runtime~=0.47.0
samplomatic~=0.21.0
Техніки пом'якшення помилок PEA та PEC обидві використовують компонент навчання шуму, що базується на моделі шуму Паулі-Ліндблада, яка зазвичай керується під час виконання після надсилання одного або кількох завдань через qiskit-ibm-runtime без локального доступу до підігнаної моделі шуму. Проте, починаючи з qiskit-ibm-runtime v0.27.1, створено класи NoiseLearner та пов'язаний NoiseLearnerOptions, щоб отримувати результати цих експериментів із навчання шуму. Ці результати можна зберігати локально як NoiseLearnerResult і використовувати як вхідні дані в подальших експериментах. Ця сторінка містить огляд його використання та доступних параметрів.
Крім того, починаючи з qiskit-ibm-runtime v0.47.0, є новий клас NoiseLearnerV3, сумісний з примітивом Executor. Ця нова версія, яка також є частиною моделі спрямованого виконання, дозволяє явно вказувати шари, які ти хочеш вивчати.
NoiseLearner працює лише з серверним EstimatorV2, а NoiseLearnerV3 — лише з Executor та новим клієнтським Estimator (представленим у qiskit-ibm-runtime v0.50.0).
NoiseLearner
Огляд
Клас NoiseLearner виконує експерименти, що характеризують процеси шуму на основі моделі шуму Паулі-Ліндблада для одного (або кількох) схем. Він має метод run(), який виконує навчальні експерименти і приймає на вхід або список схем, або PUB, та повертає NoiseLearnerResult, що містить вивчені канали шуму та метадані про надіслані завдання. Нижче наведено фрагмент коду, що демонструє використання помічника програми.
# 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, 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, що містять модель шуму для кожного окремого шару заплутування, який належить до цільових схем. Кожен LayerError зберігає інформацію про шар у вигляді схеми та набору міток кубітів, поряд із 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',
'IIIIIIIIIIIIIIIIIIIIIIIIXXI', 'IIIIIIIIIIIIIIIIIIIIIIIIXYI',
'IIIIIIIIIIIIIIIIIIIIIIIIXZI', 'IIIIIIIIIIIIIIIIIIIIIIIIYII',
'IIIIIIIIIIIIIIIIIIIIIIIIYXI', 'IIIIIIIIIIIIIIIIIIIIIIIIYYI',
'IIIIIIIIIIIIIIIIIIIIIIIIYZI', 'IIIIIIIIIIIIIIIIIIIIIIIIZII',
'IIIIIIIIIIIIIIIIIIIIIIIIZXI', 'IIIIIIIIIIIIIIIIIIIIIIIIZYI',
'IIIIIIIIIIIIIIIIIIIIIIIIZZI', 'IIIIIIIIIIIIIIIIIIIIIIIXIII',
'IIIIIIIIIIIIIIIIIIIIIIIXXII', 'IIIIIIIIIIIIIIIIIIIIIIIXYII',
'IIIIIIIIIIIIIIIIIIIIIIIXZII', 'IIIIIIIIIIIIIIIIIIIIIIIYIII',
'IIIIIIIIIIIIIIIIIIIIIIIYXII', 'IIIIIIIIIIIIIIIIIIIIIIIYYII',
'IIIIIIIIIIIIIIIIIIIIIIIYZII', 'IIIIIIIIIIIIIIIIIIIIIIIZIII',
'IIIIIIIIIIIIIIIIIIIIIIIZXII', 'IIIIIIIIIIIIIIIIIIIIIIIZYII',
'IIIIIIIIIIIIIIIIIIIIIIIZZII', 'IIIIIIIIIIIIIIIIIIIIIIXIIII',
'IIIIIIIIIIIIIIIIIIIIIIXXIII', 'IIIIIIIIIIIIIIIIIIIIIIXYIII',
'IIIIIIIIIIIIIIIIIIIIIIXZIII', 'IIIIIIIIIIIIIIIIIIIIIIYIIII',
'IIIIIIIIIIIIIIIIIIIIIIYXIII', 'IIIIIIIIIIIIIIIIIIIIIIYYIII',
'IIIIIIIIIIIIIIIIIIIIIIYZIII', 'IIIIIIIIIIIIIIIIIIIIIIZIIII',
'IIIIIIIIIIIIIIIIIIIIIIZXIII', 'IIIIIIIIIIIIIIIIIIIIIIZYIII',
'IIIIIIIIIIIIIIIIIIIIIIZZIII', 'IIIIIIIIIIIIIIIIIIIIIXIIIII',
'IIIIIIIIIIIIIIIIIIIIIXIIIIX', 'IIIIIIIIIIIIIIIIIIIIIXIIIIY',
'IIIIIIIIIIIIIIIIIIIIIXIIIIZ', 'IIIIIIIIIIIIIIIIIIIIIYIIIII',
'IIIIIIIIIIIIIIIIIIIIIYIIIIX', 'IIIIIIIIIIIIIIIIIIIIIYIIIIY',
'IIIIIIIIIIIIIIIIIIIIIYIIIIZ', 'IIIIIIIIIIIIIIIIIIIIIZIIIII',
'IIIIIIIIIIIIIIIIIIIIIZIIIIX', 'IIIIIIIIIIIIIIIIIIIIIZIIIIY',
'IIIIIIIIIIIIIIIIIIIIIZIIIIZ', 'IIIIIIIIIIIIIIIIIIIIXIIIIII',
'IIIIIIIIIIIIIIIIIIIIXIXIIII', 'IIIIIIIIIIIIIIIIIIIIXIYIIII',
'IIIIIIIIIIIIIIIIIIIIXIZIIII', 'IIIIIIIIIIIIIIIIIIIIYIIIIII',
'IIIIIIIIIIIIIIIIIIIIYIXIIII', 'IIIIIIIIIIIIIIIIIIIIYIYIIII',
'IIIIIIIIIIIIIIIIIIIIYIZIIII', 'IIIIIIIIIIIIIIIIIIIIZIIIIII',
'IIIIIIIIIIIIIIIIIIIIZIXIIII', 'IIIIIIIIIIIIIIIIIIIIZIYIIII', ...]
Along with the error rates:
[0.00037 0.00043 0.00032 ... 0.00031 0.00035 0.00017]
Атрибут LayerError.error результату навчання шуму містить генератори та частоти помилок підігнаної моделі Паулі-Ліндблада, яка має вигляд
де — це LayerError.rates, а — оператори Паулі, вказані в LayerError.generators.
Параметри навчання шуму
Ти можеш обрати серед кількох параметрів, які задаються під час створення екземпляра об'єкта NoiseLearner. Ці параметри інкапсульовано в класі qiskit_ibm_runtime.options.NoiseLearnerOptions; вони дають змогу вказати максимальну кількість шарів для навчання, кількість рандомізацій, стратегію твірлінгу тощо. Докладнішу інформацію дивись у документації 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()
Передача моделі шуму до примітива
Модель шуму, вивчена на схемі, також може використовуватися як вхідні дані для примітива IBM Quantum 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 виконує експерименти, що характеризують процеси шуму на основі моделі шуму Паулі-Ліндблада для одної або кількох схем. Його метод run() приймає список інструкцій, кожна з яких має бути анотованим твірлінгом BoxOp, що містить операції ISA.
Результат завдання 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='r223A', modifier_ref='', site='after')]
Результат завдання — це список об'єктів NoiseLearnerV3Result, по одному для кожного вхідного набору інструкцій у боксах. NoiseLearnerV3Result має метод to_pauli_lindblad_map(), який повертає об'єкт PauliLindbladMap, що має методи для вилучення генераторів, частот помилок тощо.
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]
Параметри навчання шуму
NoiseLearnerV3 підтримує кілька параметрів, включаючи кількість рандомізацій та глибину пар шарів, серед іншого. Подібно до примітивів, ти можеш задавати параметри під час або після створення екземпляра об'єкта NoiseLearnerV3. Попередній приклад коду демонструє, як встановити параметри shots_per_randomization та num_randomizations. Докладнішу інформацію дивись у документації API NoiseLearnerV3Options.
Передача моделі шуму до Executor
Executor дотримується намірів дизайну, заданих в анотаціях схеми (у формі семплексу) та параметрах. InjectNoise — це анотація для вказання місця введення шуму, а аргумент семплексу pauli_lindblad_maps визначає, яку карту шуму використовувати.
Circuit у попередньому прикладі проходить через менеджер проходів boxing, який групує інструкції в анотовані блоки (boxes). Відповідний код додано тут для зручності розуміння.
inject_noise_targets=”gates”вказує додати анотаціїInjectNoiseдо блоків, що містять entanglers.inject_noise_strategy="uniform_modification"вказує призначити однаковіrefіmodifier_refусім еквівалентним блокам з анотаціямиInjectNoise.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",
)
Схема з попереднього прикладу містить три бокси, два з яких мають анотації InjectNoise з різними атрибутами 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 потрібно перетворити на словник перед передачею до Executor. Ключами цього словника є атрибути InjectNoise.ref, а значеннями — відповідні карти шуму. Це відображення повідомляє Executor, які моделі шуму вводити і де.
Наступний код показує, як взяти схему та результат NoiseLearnerV3 з попереднього прикладу і передати їх до Executor, який генерує варіанти схеми з введеними моделями шуму та виконує їх на апаратному забезпеченні.
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 з клієнтським Estimator
Наведений нижче код показує, як використовувати програму-помічник з новим клієнтським 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()
Наступні кроки
- Переглянь довідник API EstimatorOptions та довідник API ResilienceOptionsV2.
- Дізнайся більше про доступні техніки пом'якшення та придушення помилок.
- Дізнайся, як реалізувати управління шумом Estimator.