Migra da NoiseLearner a NoiseLearnerV3
Questa guida ti accompagna nella migrazione da IBM Quantum® NoiseLearner a NoiseLearnerV3. Entrambe
le classi eseguono esperimenti che caratterizzano i processi di rumore basati su un
modello di rumore Pauli-Lindblad, ma gli input e gli
output sono leggermente diversi.
Contesto
La classe NoiseLearner
è stata creata per consentire agli utenti di eseguire l'apprendimento esplicito del rumore. Il modello
di rumore risultante può quindi essere passato a Estimator di IBM Quantum per applicare tecniche di mitigazione degli errori
come PEA e PEC.
NoiseLearner è stato progettato per funzionare con Estimator, e pertanto impiega implicitamente la stessa
strategia di individuazione dei livelli di Estimator. Questa strategia non può essere modificata; altrimenti, i successivi
passaggi di mitigazione non funzionerebbero correttamente.
A partire da qiskit-ibm-runtime v0.47.0, è disponibile una nuova classe
NoiseLearnerV3
compatibile con la primitiva Executor e il
modello di esecuzione diretta.
Questo nuovo modello offre un'esperienza white-box fornendo gli elementi per catturare l'intenzione progettuale
lato client, e un'unica primitiva lato server (Executor) elabora tali input esattamente come
indicato — non prende decisioni implicite per tuo conto. A differenza dell'originale NoiseLearner,
controlli tu come stratificare i tuoi circuiti quando usi NoiseLearnerV3, e la classe accetta semplicemente una lista di istruzioni di circuito boxed
(per esempio, livelli unici) come suo input.
NoiseLearnerV3 supporta anche l'apprendimento del rumore di misurazione. Per ogni istruzione nella lista di input, esegue il
protocollo di apprendimento Pauli-Lindblad se il box contiene gate a uno e due qubit, e il
protocollo TREX
se il box contiene misurazioni.
Devi eseguire la migrazione?
NoiseLearner funziona solo con il vecchio Estimator lato server, e NoiseLearnerV3 funziona solo con
Executor e l'Estimator lato client. Devi eseguire la migrazione a NoiseLearnerV3 se stai usando
Executor o l'Estimator lato client. Il vecchio Estimator lato server è deprecato e sostituito dall'equivalente lato client in qiskit-ibm-runtime v0.50.0.
Se stai usando qiskit-ibm-runtime v0.50.0 o versioni successive, leggi prima la guida Migra da Sampler ed Estimator lato server a lato client per eseguire la migrazione alle primitive lato client.
Passaggi di migrazione
Passaggio 1: modifica gli import
NoiseLearner:
from qiskit_ibm_runtime.noise_learner import NoiseLearner
NoiseLearnerV3:
from qiskit_ibm_runtime import NoiseLearnerV3
Passaggio 2: aggiorna gli input
Il metodo run() di NoiseLearner accetta una lista di circuiti o PUB, mentre il metodo run() di NoiseLearnerV3 accetta una lista di istruzioni, ognuna delle quali deve essere un BoxOp annotato con twirling che contiene operazioni ISA.
Sono disponibili metodi di convenienza per generare i box annotati, a seconda di quale
primitiva prevedi di usare.
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, quando si lavora con Estimator lato client:
Se prevedi di usare l'Estimator lato client per l'esecuzione dei circuiti, puoi usare il metodo find_unique_layers di Estimator per creare box annotati (livelli):
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, quando si lavora con Executor:
Se prevedi di usare Executor per l'esecuzione dei circuiti, valuta di usare la funzione generate_boxing_pass_manager di Samplomatic per creare box annotati:
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)
Passaggio 3: converti le opzioni
La maggior parte dei campi di NoiseLearnerOptions si mappa direttamente su NoiseLearnerV3Options, ad eccezione dei seguenti:
-
max_layers_to_learn: ConNoiseLearnerV3, il numero di livelli da apprendere si basa sul numero di livelli passati in ingresso. -
twirling_strategy: ConNoiseLearnerV3, la strategia di twirling è definita dal modo in cui le istruzioni vengono racchiuse in box e annotate (ad esempio quando si usagenerate_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, quando si lavora con Estimator lato client:
Se prevedi di usare l'Estimator lato client per l'esecuzione dei circuiti, puoi
impostare l'opzione twirling.strategy di Estimator:
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, quando si lavora con Executor:
Se prevedi di usare Executor per l'esecuzione dei circuiti, puoi passare l'opzione twirling_strategy alla funzione generate_boxing_pass_manager.
Nota che con generate_boxing_pass_manager(), i valori di twirling_strategy usano underscore
("active_accum", "active_circuit"), mentre i valori di NoiseLearnerOptions.twirling_strategy usano trattini ("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])
Passaggio 4: esamina i risultati
Gli output di NoiseLearner e NoiseLearnerV3 contengono informazioni simili ma in formati diversi. Aggiorna il tuo codice se esamina esplicitamente l'output.
Mappatura degli attributi del risultato:
(learner_result è l'output del job del learner)
| Attributo | NoiseLearner | NoiseLearnerV3 |
|---|---|---|
| Tipo di risultato | NoiseLearnerResult | NoiseLearnerV3Results, un contenitore simile a una sequenza di NoiseLearnerV3Result |
| Numero di livelli appresi | len(learner_result.data) | len(learner_result) |
| Dati per il primo livello | layer_error = learner_result.data[0] | noise_map = learner_result[0].to_pauli_lindblad_map() |
| Tipo di risultato di ogni livello | LayerError (type(layer_error)) | PauliLindbladMap (type(noise_map)) |
| Generatori per il canale di errore | layer_error.error.generators | noise_map.generators() |
| Tassi di errore | layer_error.error.rates | noise_map.rates |
Passaggio 5: inserisci il modello di rumore in una primitiva
NoiseLearner funziona solo con il vecchio Estimator lato server, e NoiseLearnerV3 funziona solo con Executor e l'Estimator lato client. Il modo in cui viene specificato un modello di rumore varia leggermente a seconda di quale primitiva viene usata.
NoiseLearner, quando si lavora con il vecchio Estimator lato server:
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, quando si lavora con Estimator lato client:
Riusa lo stesso Estimator che ha prodotto layers nel passaggio 2. Le mappe di rumore restituite dal
learner sono associate posizionalmente a quei livelli, quindi devono essere assegnate all'Estimator
da cui provengono. PEA/PEC era già stato abilitato su di esso nel passaggio 2.
Nota che mentre NoiseLearnerV3 supporta sia il protocollo Pauli-Lindblad sia quello TREX, Estimator accetta solo modelli di rumore per livelli a due qubit appresi con il protocollo Pauli-Lindblad.
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, quando si lavora con 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)
Esempi completi
NoiseLearnerV3 e Estimator lato client
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 ed 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()