Migracja z NoiseLearner do NoiseLearnerV3
Ten przewodnik prowadzi cię przez proces migracji z NoiseLearner IBM Quantum® do NoiseLearnerV3. Obie
klasy wykonują eksperymenty charakteryzujące procesy szumu na podstawie
modelu szumu Pauliego-Lindblada, ale dane wejściowe i
wyjściowe są nieco inne.
Kontekst
Klasa NoiseLearner
została utworzona, aby umożliwić użytkownikom wykonywanie jawnego uczenia się szumu. Wynikowy
model szumu można następnie przekazać do Estimator IBM Quantum w celu zastosowania technik łagodzenia błędów,
takich jak PEA i PEC.
NoiseLearner został zaprojektowany do współpracy z Estimator, dlatego niejawnie stosuje tę samą
strategię znajdowania warstw co Estimator. Tej strategii nie można zmienić; w przeciwnym razie kolejne
kroki łagodzenia błędów nie działałyby poprawnie.
Począwszy od qiskit-ibm-runtime v0.47.0, dostępna jest nowa
klasa NoiseLearnerV3,
która jest kompatybilna z prymitywem Executor oraz
modelem wykonania kierowanego.
Ten nowy model zapewnia doświadczenie typu white-box, dostarczając elementy do przechwytywania intencji projektowej
po stronie klienta, a pojedynczy prymityw po stronie serwera (Executor) przetwarza te dane wejściowe dokładnie tak, jak
zostało to zlecone — nie podejmuje żadnych ukrytych decyzji w twoim imieniu. W przeciwieństwie do oryginalnego NoiseLearner,
kontrolujesz sposób stratyfikacji obwodów podczas korzystania zNoiseLearnerV3, a klasa po prostu przyjmuje jako dane wejściowe listę opakowanych instrukcji obwodu
(na przykład unikalnych warstw).
NoiseLearnerV3 obsługuje również uczenie się szumu pomiarowego. Dla każdej instrukcji na liście wejściowej uruchamia
protokół uczenia się Pauliego-Lindblada, jeśli pudełko zawiera bramki jedno- i dwukubitowe, oraz protokół
TREX,
jeśli pudełko zawiera pomiary.
Czy powinieneś migrować?
NoiseLearner działa tylko ze starszym Estimator po stronie serwera, a NoiseLearnerV3 działa tylko z
Executor i Estimator po stronie klienta. Musisz migrować do NoiseLearnerV3, jeśli używasz
Executor lub Estimator po stronie klienta. Starszy Estimator po stronie serwera jest przestarzały i zastąpiony odpowiednikiem po stronie klienta w qiskit-ibm-runtime v0.50.0.
Jeśli używasz qiskit-ibm-runtime v0.50.0 lub nowszej, przeczytaj najpierw przewodnik Migracja z Sampler i Estimator po stronie serwera na wersje po stronie klienta, aby zmigrować do prymitywów po stronie klienta.
Kroki migracji
Krok 1: Zmiana importów
NoiseLearner:
from qiskit_ibm_runtime.noise_learner import NoiseLearner
NoiseLearnerV3:
from qiskit_ibm_runtime import NoiseLearnerV3
Krok 2: Aktualizacja danych wejściowych
Metoda run() klasy NoiseLearner przyjmuje listę obwodów lub PUB-ów, natomiast metoda run() klasy NoiseLearnerV3 przyjmuje listę instrukcji, z których każda musi być oznaczoną adnotacją twirling BoxOp zawierającą operacje ISA.
Dostępne są metody pomocnicze do generowania oznaczonych pudełek, w zależności od tego, który
prymityw planujesz użyć.
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 podczas pracy z Estimatorem po stronie klienta:
Jeśli planujesz używać Estimatora po stronie klienta do wykonywania obwodów, możesz użyć metody find_unique_layers z Estimatora, aby utworzyć oznaczone pudełka (warstwy):
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 podczas pracy z Executorem:
Jeśli planujesz używać Executora do wykonywania obwodów, rozważ użycie funkcji generate_boxing_pass_manager z Samplomatic, aby utworzyć oznaczone pudełka:
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)
Krok 3: Konwersja opcji
Większość pól NoiseLearnerOptions mapuje się bezpośrednio na NoiseLearnerV3Options, z wyjątkiem następujących:
-
max_layers_to_learn: W przypadkuNoiseLearnerV3liczba warstw do nauczenia jest oparta na liczbie przekazanych warstw. -
twirling_strategy: W przypadkuNoiseLearnerV3strategia twirling jest definiowana przez sposób opakowania i oznaczenia instrukcji (na przykład podczas używaniagenerate_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 podczas pracy z Estimatorem po stronie klienta:
Jeśli planujesz używać Estimatora po stronie klienta do wykonywania obwodów, możesz
ustawić opcję Estimatora 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 podczas pracy z Executorem:
Jeśli planujesz używać Executora do wykonywania obwodów, możesz przekazać opcję twirling_strategy do funkcji generate_boxing_pass_manager.
Zwróć uwagę, że w przypadku generate_boxing_pass_manager() wartości twirling_strategy używają podkreśleń
("active_accum", "active_circuit"), natomiast wartości NoiseLearnerOptions.twirling_strategy używają łączników ("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])
Krok 4: Analiza wyników
Dane wyjściowe NoiseLearner i NoiseLearnerV3 zawierają podobne informacje, ale mają różne formaty. Zaktualizuj kod, jeśli jawnie analizuje on dane wyjściowe.
Mapowanie atrybutów wyniku:
(learner_result to wynik zadania learner)
| Attribute | NoiseLearner | NoiseLearnerV3 |
|---|---|---|
| Typ wyniku | NoiseLearnerResult | NoiseLearnerV3Results, kontener podobny do sekwencji zawierający NoiseLearnerV3Result |
| Liczba nauczonych warstw | len(learner_result.data) | len(learner_result) |
| Dane dla pierwszej warstwy | layer_error = learner_result.data[0] | noise_map = learner_result[0].to_pauli_lindblad_map() |
| Typ wyniku każdej warstwy | LayerError (type(layer_error)) | PauliLindbladMap (type(noise_map)) |
| Generatory kanału błędu | layer_error.error.generators | noise_map.generators() |
| Współczynniki błędu | layer_error.error.rates | noise_map.rates |
Krok 5: Przekazanie modelu szumu do prymitywu
NoiseLearner działa tylko ze starszym Estimator po stronie serwera, a NoiseLearnerV3 działa tylko z Executor i Estimator po stronie klienta. Sposób określania modelu szumu różni się nieznacznie w zależności od tego, który prymityw jest używany.
NoiseLearner podczas pracy ze starszym Estimatorem po stronie serwera:
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 podczas pracy z Estimatorem po stronie klienta:
Ponownie użyj tego samego Estimator, który wyprodukował layers w kroku 2. Mapy szumu zwrócone przez
learner są dopasowane pozycyjnie do tych warstw, więc muszą zostać przypisane do Estimatora,
z którego pochodzą. PEA/PEC zostało już na nim włączone w kroku 2.
Zwróć uwagę, że chociaż NoiseLearnerV3 obsługuje zarówno protokół Pauliego-Lindblada, jak i TREX, Estimator akceptuje tylko modele szumu dla warstw dwukubitowych nauczonych za pomocą protokołu Pauliego-Lindblada.
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 podczas pracy z Executorem:
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)
Pełne przykłady
NoiseLearnerV3 i 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()
NoiseLearnerV3 i 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()