Przejdź do głównej treści
Ten projekt jest w wersji beta. Znalazłeś błąd? Otwórz zgłoszenie na GitHub. Masz pytanie lub pomysł? Zapytaj w Discussions — chętnie poznamy Twoją opinię!
Jak oceniasz jakość tłumaczenia tej strony?

Pomocnik uczenia szumu

Wersje pakietów

Kod na tej stronie został opracowany przy użyciu poniższych wymagań. Zalecamy korzystanie z tych wersji lub nowszych.

qiskit[all]~=2.5.2
qiskit-ibm-runtime~=0.47.0
samplomatic~=0.21.0

Techniki mitygacji błędów PEA i PEC wykorzystują komponent uczenia szumu oparty na modelu szumu Pauli-Lindblad, który jest zazwyczaj zarządzany podczas wykonywania po przesłaniu jednego lub więcej zadań przez qiskit-ibm-runtime bez lokalnego dostępu do dopasowanego modelu szumu. Jednak począwszy od qiskit-ibm-runtime v0.27.1 udostępniono klasę NoiseLearner oraz powiązaną klasę NoiseLearnerOptions, które umożliwiają uzyskanie wyników tych eksperymentów uczenia szumu. Wyniki te można następnie przechowywać lokalnie jako NoiseLearnerResult i używać jako danych wejściowych w późniejszych eksperymentach. Ta strona zawiera przegląd sposobu użycia oraz dostępnych opcji.

Ponadto, począwszy od qiskit-ibm-runtime v0.47.0, dostępna jest nowa klasa NoiseLearnerV3 zgodna z prymitywem Executor. Ta nowa wersja, również będąca częścią modelu wykonania kierowanego, daje możliwość jawnego określenia warstw, których szum chcesz wyuczyć.

uwaga

NoiseLearner działa tylko z serwerową wersją EstimatorV2, a NoiseLearnerV3 działa tylko z Executor oraz nowym Estimatorem po stronie klienta (wprowadzonym w qiskit-ibm-runtime v0.50.0).

NoiseLearnerV3​

Przegląd​

Podobnie jak NoiseLearner, klasa NoiseLearnerV3 przeprowadza eksperymenty charakteryzujące procesy szumu w oparciu o model szumu Pauli-Lindblad dla jednego lub więcej Circuit. Metoda run() przyjmuje listę instrukcji, z których każda musi być twirled-annotated BoxOp zawierającym operacje ISA.

Wynik zadania NoiseLearnerV3 zawiera listę obiektów NoiseLearnerV3Result, po jednym dla każdej instrukcji wejściowej. Poniższy kod pokazuje, jak używać pomocnika.

# 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')]

Wynik zadania to lista obiektów NoiseLearnerV3Result, po jednym dla każdego wejściowego zestawu instrukcji w boksach. NoiseLearnerV3Result posiada metodę to_pauli_lindblad_map(), która zwraca obiekt PauliLindbladMap, który ma metody do wyodrębniania generatorów, współczynników błędów i nie tylko.

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]

Opcje uczenia szumu​

NoiseLearnerV3 obsługuje kilka opcji, w tym m.in. liczbę losowań i głębokość par warstw. Podobnie jak w przypadku prymitywów, możesz określić opcje podczas lub po utworzeniu instancji obiektu NoiseLearnerV3. Poprzedni przykład kodu demonstruje, jak ustawić opcje shots_per_randomization i num_randomizations. Szczegółowe informacje znajdziesz w dokumentacji API NoiseLearnerV3Options.

Przekazywanie modelu szumu do Executor​

Executor stosuje się do intencji projektowych określonych w adnotacjach Circuit (w postaci samplex) i opcjach. InjectNoise to adnotacja służąca do określania miejsca wstrzykiwania szumu, a argument samplex pauli_lindblad_maps określa, której mapy szumu użyć.

Obwód z poprzedniego przykładu przechodzi przez menedżera przebiegów typu boxing, który grupuje instrukcje w boksy z adnotacjami. Odpowiedni kod został dodany tutaj dla ułatwienia zrozumienia.

  • inject_noise_targets=”gates” określa dodanie adnotacji InjectNoise do boksów zawierających entanglery.
  • inject_noise_strategy="uniform_modification" określa przypisanie tych samych ref i modifier_ref do wszystkich równoważnych boksów z adnotacjami InjectNoise.
    • InjectNoise.ref to unikalny identyfikator używany do przypisania modelu szumu do tego boksu.
    • InjectNoise.modifier_ref umożliwia skalowanie modelu szumu przypisanego do boksu za pomocą czynników mnożących.
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 z poprzedniego przykładu zawiera trzy boksy, z których dwa zawierają adnotacje InjectNoise z różnymi atrybutami ref (ponieważ nie są równoważne).

# 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')]

Wynik zadania NoiseLearnerV3 musi być przekonwertowany na słownik przed przekazaniem do Executor. Klucze tego słownika to atrybuty InjectNoise.ref, a wartości to odpowiadające im mapy szumu. To odwzorowanie informuje Executor, które modele szumu wstrzyknąć i gdzie.

Poniższy kod pokazuje, jak wziąć Circuit i wynik NoiseLearnerV3 z poprzedniego przykładu i przekazać je do Executor, który wygeneruje warianty Circuit ze wstrzykniętymi modelami szumu i wykona je na sprzęcie.

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)

Używanie NoiseLearnerV3 z Estimator po stronie klienta​

Poniższy kod pokazuje, jak używać programu pomocniczego z nowym Estimator po stronie klienta

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​

Od wersji qiskit_ibm_runtime v0.51.0 NoiseLearner jest przestarzały. Instrukcje migracji znajdziesz w Migrate to NoiseLearnerV3.

Kliknij, aby dowiedzieć się więcej.

Przegląd​

Klasa NoiseLearner przeprowadza eksperymenty charakteryzujące procesy szumu w oparciu o model szumu Pauli-Lindblad dla jednego lub więcej Circuit. Posiada metodę run(), która wykonuje eksperymenty uczenia i przyjmuje jako dane wejściowe listę Circuit lub PUB, a następnie zwraca NoiseLearnerResult zawierający nauczone kanały szumu oraz metadane dotyczące przesłanych zadań. Poniżej znajduje się fragment kodu demonstrujący użycie pomocnika.

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()

Wynikowy NoiseLearnerResult.data jest listą obiektów LayerError zawierających model szumu dla każdej pojedynczej warstwy splątującej należącej do docelowych obwodów. Każdy LayerError przechowuje informacje o warstwie w postaci obwodu i zestawu etykiet kubitów, wraz z PauliLindbladError dla modelu szumu nauczonego dla danej warstwy.

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"
)

Atrybut LayerError.error wyniku uczenia szumu zawiera generatory i współczynniki błędów dopasowanego modelu Pauli Lindblad, który ma postać

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

gdzie rjr_j to LayerError.rates, a PjP_j to operatory Pauliego określone w LayerError.generators.

Opcje uczenia szumu​

Możesz wybrać spośród kilku opcji, które podajesz podczas tworzenia instancji obiektu NoiseLearner. Opcje te są ujęte w klasie qiskit_ibm_runtime.options.NoiseLearnerOptions i obejmują możliwość określenia maksymalnej liczby warstw do nauczenia, liczby losowań oraz strategii twirling, wśród innych. Szczegółowe informacje znajdziesz w dokumentacji API NoiseLearnerOptions.

Poniżej znajduje się prosty przykład pokazujący, jak używać NoiseLearnerOptions w eksperymencie 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()

Przekazanie modelu szumu do prymitywu​

Model szumu wyuczony na obwodzie może być również używany jako dane wejściowe dla prymitywu IBM Quantum EstimatorV2. Można go przekazać do prymitywu na kilka różnych sposobów. Kolejne trzy przykłady pokazują, jak możesz przekazać model szumu bezpośrednio do atrybutu estimator.options, używając obiektu ResilienceOptionsV2 przed utworzeniem instancji prymitywu Estimator, oraz przez przekazanie odpowiednio sformatowanego słownika.

# 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)

Po przekazaniu modelu szumu do obiektu EstimatorV2 można go używać do uruchamiania zadań i przeprowadzania mitygacji błędów w normalny sposób.

Następne kroki​

Zalecenia