Migration von NoiseLearner zu NoiseLearnerV3
Dieser Leitfaden führt dich durch die Migration von IBM Quantum® NoiseLearner zu NoiseLearnerV3. Beide
Klassen führen Experimente durch, die Rauschprozesse basierend auf einem
Pauli-Lindblad-Rauschmodell charakterisieren, aber die Eingaben und
Ausgaben sind leicht unterschiedlich.
Hintergrund
Die Klasse NoiseLearner
wurde erstellt, um Benutzern die Durchführung von explizitem Rauschlernen zu ermöglichen. Das resultierende
Rauschmodell kann dann an den IBM Quantum Estimator übergeben werden, um Fehlerminderungstechniken
wie PEA und PEC anzuwenden.
NoiseLearner wurde entwickelt, um mit Estimator zusammenzuarbeiten, und verwendet daher implizit dieselbe
Layer-Findungsstrategie wie Estimator. Diese Strategie kann nicht geändert werden; andernfalls würden die anschließenden
Minderungsschritte nicht korrekt funktionieren.
Ab qiskit-ibm-runtime v0.47.0 gibt es eine neue
NoiseLearnerV3-
Klasse, die mit dem Executor-Primitive und dem
direkten Ausführungsmodell kompatibel ist.
Dieses neue Modell bietet eine White-Box-Erfahrung, indem es die Bausteine bereitstellt, um Designabsichten
auf der Client-Seite zu erfassen, und ein einzelnes serverseitiges Primitive (Executor) verarbeitet diese Eingaben genau so, wie
angewiesen — es trifft keine impliziten Entscheidungen in deinem Namen. Anders als der ursprüngliche NoiseLearner
kontrollierst du, wie deine Circuits aufgeteilt werden, wenn du NoiseLearnerV3 verwendest, und die Klasse nimmt einfach eine Liste von geboxten Circuit-Anweisungen
(zum Beispiel eindeutige Layer) als Eingabe.
NoiseLearnerV3 unterstützt auch das Messrauschlernen. Für jede Anweisung in der Eingabeliste führt es das
Pauli-Lindblad-Lernprotokoll aus, wenn die Box Ein- und Zwei-Qubit-Gates enthält, und das
TREX-
Protokoll, wenn die Box Messungen enthält.
Solltest du migrieren?
NoiseLearner funktioniert nur mit dem alten serverseitigen Estimator, und NoiseLearnerV3 funktioniert nur mit
Executor und dem clientseitigen Estimator. Du musst zu NoiseLearnerV3 migrieren, wenn du
Executor oder den clientseitigen Estimator verwendest. Der alte serverseitige Estimator ist veraltet und wird in qiskit-ibm-runtime v0.50.0 durch das clientseitige Äquivalent ersetzt.
Wenn du qiskit-ibm-runtime v0.50.0 oder höher verwendest, lies zuerst den Leitfaden Migration von serverseitigen zu clientseitigen Sampler und Estimator, um zu clientseitigen Primitives zu migrieren.
Migrationsschritte
Schritt 1: Ändere die Imports
NoiseLearner:
from qiskit_ibm_runtime.noise_learner import NoiseLearner
NoiseLearnerV3:
from qiskit_ibm_runtime import NoiseLearnerV3
Schritt 2: Aktualisiere die Eingaben
Die run()-Methode von NoiseLearner nimmt eine Liste von Circuits oder PUBs entgegen, während die run()-Methode von NoiseLearnerV3 eine Liste von Anweisungen entgegennimmt, von denen jede eine twirling-annotierte BoxOp sein muss, die ISA-Operationen enthält.
Es stehen Komfortmethoden zum Erstellen der annotierten Boxen zur Verfügung, abhängig davon, welches
Primitive du verwenden möchtest.
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, bei der Arbeit mit clientseitigem Estimator:
Wenn du planst, den clientseitigen Estimator für die Circuit-Ausführung zu verwenden, kannst du die Methode find_unique_layers von Estimator verwenden, um annotierte Boxen (Layer) zu erstellen:
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, bei der Arbeit mit Executor:
Wenn du planst, Executor für die Circuit-Ausführung zu verwenden, ziehe in Betracht, die Funktion generate_boxing_pass_manager aus Samplomatic zu verwenden, um annotierte Boxen zu erstellen:
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)
Schritt 3: Konvertiere die Optionen
Die meisten Felder von NoiseLearnerOptions werden direkt auf NoiseLearnerV3Options abgebildet, mit Ausnahme der folgenden:
-
max_layers_to_learn: BeiNoiseLearnerV3basiert die Anzahl der zu lernenden Layer auf der Anzahl der übergebenen Layer. -
twirling_strategy: BeiNoiseLearnerV3wird die Twirling-Strategie dadurch definiert, wie die Anweisungen geboxt und annotiert werden (etwa bei Verwendung vongenerate_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, bei der Arbeit mit clientseitigem Estimator:
Wenn du planst, den clientseitigen Estimator für die Circuit-Ausführung zu verwenden, kannst du
die Estimator-Option twirling.strategy festlegen:
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, bei der Arbeit mit Executor:
Wenn du planst, Executor für die Circuit-Ausführung zu verwenden, kannst du die Option twirling_strategy an die Funktion generate_boxing_pass_manager übergeben.
Beachte, dass bei generate_boxing_pass_manager() die twirling_strategy-Werte Unterstriche verwenden
("active_accum", "active_circuit"), während die Werte von NoiseLearnerOptions.twirling_strategy Bindestriche verwenden ("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])
Schritt 4: Überprüfe die Ergebnisse
Die Ausgaben von NoiseLearner und NoiseLearnerV3 enthalten ähnliche Informationen, liegen aber in unterschiedlichen Formaten. Aktualisiere deinen Code, wenn er die Ausgabe explizit überprüft.
Zuordnung der Ergebnisattribute:
(learner_result ist die Ausgabe des Lern-Jobs)
| Attribut | NoiseLearner | NoiseLearnerV3 |
|---|---|---|
| Ergebnistyp | NoiseLearnerResult | NoiseLearnerV3Results, ein sequenzähnlicher Container von NoiseLearnerV3Result |
| Anzahl der gelernten Layer | len(learner_result.data) | len(learner_result) |
| Daten für den ersten Layer | layer_error = learner_result.data[0] | noise_map = learner_result[0].to_pauli_lindblad_map() |
| Ergebnistyp jedes Layers | LayerError (type(layer_error)) | PauliLindbladMap (type(noise_map)) |
| Generatoren für den Fehlerkanal | layer_error.error.generators | noise_map.generators() |
| Fehlerraten | layer_error.error.rates | noise_map.rates |
Schritt 5: Rauschmodell an ein Primitive übergeben
NoiseLearner funktioniert nur mit dem alten serverseitigen Estimator, und NoiseLearnerV3 funktioniert nur mit Executor und dem clientseitigen Estimator. Wie ein Rauschmodell angegeben wird, variiert leicht je nachdem, welches Primitive verwendet wird.
NoiseLearner, bei der Arbeit mit dem alten serverseitigen 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, bei der Arbeit mit clientseitigem Estimator:
Verwende denselben Estimator wieder, der layers in Schritt 2 erzeugt hat. Die vom Learner zurückgegebenen
Rauschkarten werden positionsbezogen diesen Layern zugeordnet, daher müssen sie dem Estimator zugewiesen werden,
von dem sie stammen. PEA/PEC wurde bereits in Schritt 2 darauf aktiviert.
Beachte, dass NoiseLearnerV3 zwar sowohl Pauli-Lindblad- als auch TREX-Protokolle unterstützt, Estimator jedoch nur Rauschmodelle für Zwei-Qubit-Layer akzeptiert, die mit dem Pauli-Lindblad-Protokoll gelernt wurden.
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, bei der Arbeit mit 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)
Vollständige Beispiele
NoiseLearnerV3 und client-seitiger 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 und 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()