Zum Hauptinhalt springen

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.

hinweis

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: Bei NoiseLearnerV3 basiert die Anzahl der zu lernenden Layer auf der Anzahl der übergebenen Layer.

  • twirling_strategy: Bei NoiseLearnerV3 wird die Twirling-Strategie dadurch definiert, wie die Anweisungen geboxt und annotiert werden (etwa bei Verwendung von 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, 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)

AttributNoiseLearnerNoiseLearnerV3
ErgebnistypNoiseLearnerResultNoiseLearnerV3Results, ein sequenzähnlicher Container von NoiseLearnerV3Result
Anzahl der gelernten Layerlen(learner_result.data)len(learner_result)
Daten für den ersten Layerlayer_error = learner_result.data[0]noise_map = learner_result[0].to_pauli_lindblad_map()
Ergebnistyp jedes LayersLayerError (type(layer_error))PauliLindbladMap (type(noise_map))
Generatoren für den Fehlerkanallayer_error.error.generatorsnoise_map.generators()
Fehlerratenlayer_error.error.ratesnoise_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()

Referenzen​