Ajutor pentru învățarea zgomotului
Versiuni de pachete
Codul de pe această pagină a fost dezvoltat folosind cerințele de mai jos. Recomandăm să folosești aceste versiuni sau unele mai noi.
qiskit[all]~=2.4.1
qiskit-ibm-runtime~=0.47.0
samplomatic~=0.18.0
Tehnicile de atenuare a erorilor PEA și PEC utilizează ambele o componentă de învățare a zgomotului bazată pe un model de zgomot Pauli-Lindblad, care este gestionat de obicei în timpul execuției după trimiterea unuia sau mai multor job-uri prin qiskit-ibm-runtime, fără acces local la modelul de zgomot ajustat. Cu toate acestea, începând cu qiskit-ibm-runtime v0.27.1, au fost create clasele NoiseLearner și NoiseLearnerOptions pentru a obține rezultatele acestor experimente de învățare a zgomotului. Aceste rezultate pot fi stocate local ca NoiseLearnerResult și utilizate ca intrare în experimente ulterioare. Această pagină oferă o prezentare generală a utilizării sale și a opțiunilor disponibile.
În plus, începând cu qiskit-ibm-runtime v0.47.0, există o nouă clasă NoiseLearnerV3 compatibilă cu primitiva Executor. Această nouă versiune, parte din modelul de execuție direcționată, îți oferă posibilitatea de a specifica explicit straturile pe care dorești să le înveți.
NoiseLearner funcționează doar cu EstimatorV2, iar NoiseLearnerV3 funcționează doar cu Executor.
NoiseLearner
Prezentare generală
Clasa NoiseLearner efectuează experimente care caracterizează procesele de zgomot pe baza unui model de zgomot Pauli-Lindblad pentru unul sau mai multe Circuit-uri. Aceasta dispune de o metodă run() care execută experimentele de învățare și acceptă ca intrare fie o listă de circuit-uri, fie un PUB, returnând un NoiseLearnerResult ce conține canalele de zgomot învățate și metadatele despre job-ul/job-urile trimise. Mai jos este un fragment de cod care demonstrează utilizarea programului ajutor.
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime samplomatic
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()
Rezultatul NoiseLearnerResult.data este o listă de obiecte LayerError care conțin modelul de zgomot pentru fiecare strat de entanglare individual ce aparține Circuit-ului (Circuit-urilor) țintă. Fiecare LayerError stochează informațiile despre strat, sub forma unui Circuit și a unui set de etichete de qubit, alături de PauliLindbladError pentru modelul de zgomot care a fost învățat pentru stratul respectiv.
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"
)
Noise learner result contains 2 entries and has the following type:
<class 'qiskit_ibm_runtime.utils.noise_learner_result.NoiseLearnerResult'>
Each element of `NoiseLearnerResult` then contains an object of type:
<class 'qiskit_ibm_runtime.utils.noise_learner_result.LayerError'>
And each of these `LayerError` objects possess data on the generators for the error channel:
['IIIIIIIIIIIIIIIIIIIIIIIIIIX', 'IIIIIIIIIIIIIIIIIIIIIIIIIIY',
'IIIIIIIIIIIIIIIIIIIIIIIIIIZ', 'IIIIIIIIIIIIIIIIIIIIIIIIIXI',
'IIIIIIIIIIIIIIIIIIIIIIIIIXX', 'IIIIIIIIIIIIIIIIIIIIIIIIIXY',
'IIIIIIIIIIIIIIIIIIIIIIIIIXZ', 'IIIIIIIIIIIIIIIIIIIIIIIIIYI',
'IIIIIIIIIIIIIIIIIIIIIIIIIYX', 'IIIIIIIIIIIIIIIIIIIIIIIIIYY',
'IIIIIIIIIIIIIIIIIIIIIIIIIYZ', 'IIIIIIIIIIIIIIIIIIIIIIIIIZI',
'IIIIIIIIIIIIIIIIIIIIIIIIIZX', 'IIIIIIIIIIIIIIIIIIIIIIIIIZY',
'IIIIIIIIIIIIIIIIIIIIIIIIIZZ', 'IIIIIIIIIIIIIIIIIIIIIIIIXII',
'IIIIIIIIIIIIIIIIIIIIIIIIXIX', 'IIIIIIIIIIIIIIIIIIIIIIIIXIY',
'IIIIIIIIIIIIIIIIIIIIIIIIXIZ', 'IIIIIIIIIIIIIIIIIIIIIIIIYII',
'IIIIIIIIIIIIIIIIIIIIIIIIYIX', 'IIIIIIIIIIIIIIIIIIIIIIIIYIY',
'IIIIIIIIIIIIIIIIIIIIIIIIYIZ', 'IIIIIIIIIIIIIIIIIIIIIIIIZII',
'IIIIIIIIIIIIIIIIIIIIIIIIZIX', 'IIIIIIIIIIIIIIIIIIIIIIIIZIY',
'IIIIIIIIIIIIIIIIIIIIIIIIZIZ', 'IIIIIIIIIIIIIIIIIIIIIIIXIII',
'IIIIIIIIIIIIIIIIIIIIIIIYIII', 'IIIIIIIIIIIIIIIIIIIIIIIZIII',
'IIIIIIIIIIIIIIIIIIIIIIXIIII', 'IIIIIIIIIIIIIIIIIIIIIIXXIII',
'IIIIIIIIIIIIIIIIIIIIIIXYIII', 'IIIIIIIIIIIIIIIIIIIIIIXZIII',
'IIIIIIIIIIIIIIIIIIIIIIYIIII', 'IIIIIIIIIIIIIIIIIIIIIIYXIII',
'IIIIIIIIIIIIIIIIIIIIIIYYIII', 'IIIIIIIIIIIIIIIIIIIIIIYZIII',
'IIIIIIIIIIIIIIIIIIIIIIZIIII', 'IIIIIIIIIIIIIIIIIIIIIIZXIII',
'IIIIIIIIIIIIIIIIIIIIIIZYIII', 'IIIIIIIIIIIIIIIIIIIIIIZZIII',
'IIIIIIIIIIIIIIIIIIIIIXIIIII', 'IIIIIIIIIIIIIIIIIIIIIXXIIII',
'IIIIIIIIIIIIIIIIIIIIIXYIIII', 'IIIIIIIIIIIIIIIIIIIIIXZIIII',
'IIIIIIIIIIIIIIIIIIIIIYIIIII', 'IIIIIIIIIIIIIIIIIIIIIYXIIII',
'IIIIIIIIIIIIIIIIIIIIIYYIIII', 'IIIIIIIIIIIIIIIIIIIIIYZIIII',
'IIIIIIIIIIIIIIIIIIIIIZIIIII', 'IIIIIIIIIIIIIIIIIIIIIZXIIII',
'IIIIIIIIIIIIIIIIIIIIIZYIIII', 'IIIIIIIIIIIIIIIIIIIIIZZIIII',
'IIIIIIIIIIIIIIIIIIIIXIIIIII', 'IIIIIIIIIIIIIIIIIIIIXXIIIII',
'IIIIIIIIIIIIIIIIIIIIXYIIIII', 'IIIIIIIIIIIIIIIIIIIIXZIIIII',
'IIIIIIIIIIIIIIIIIIIIYIIIIII', 'IIIIIIIIIIIIIIIIIIIIYXIIIII',
'IIIIIIIIIIIIIIIIIIIIYYIIIII', 'IIIIIIIIIIIIIIIIIIIIYZIIIII',
'IIIIIIIIIIIIIIIIIIIIZIIIIII', 'IIIIIIIIIIIIIIIIIIIIZXIIIII',
'IIIIIIIIIIIIIIIIIIIIZYIIIII', 'IIIIIIIIIIIIIIIIIIIIZZIIIII',
'IIIIIIIIIIIIIIIIIIIXIIIIIII', 'IIIIIIIIIIIIIIIIIIIXXIIIIII',
'IIIIIIIIIIIIIIIIIIIXYIIIIII', 'IIIIIIIIIIIIIIIIIIIXZIIIIII',
'IIIIIIIIIIIIIIIIIIIYIIIIIII', 'IIIIIIIIIIIIIIIIIIIYXIIIIII',
'IIIIIIIIIIIIIIIIIIIYYIIIIII', 'IIIIIIIIIIIIIIIIIIIYZIIIIII', ...]
Along with the error rates:
[5.9e-04 5.3e-04 5.7e-04 ... 0.0e+00 1.0e-05 0.0e+00]
Atributul LayerError.error al rezultatului de învățare a zgomotului conține generatorii și ratele de eroare ale modelului Pauli Lindblad ajustat, care are forma
unde sunt LayerError.rates, iar sunt operatorii Pauli specificați în LayerError.generators.
Opțiuni pentru învățarea zgomotului
Poți alege dintre mai multe opțiuni pe care să le introduci atunci când instanțiezi un obiect NoiseLearner. Aceste opțiuni sunt încapsulate de clasa qiskit_ibm_runtime.options.NoiseLearnerOptions și includ posibilitatea de a specifica numărul maxim de straturi de învățat, numărul de randomizări și strategia de twirling, printre altele. Consultă documentația API NoiseLearnerOptions pentru informații detaliate.
Urmează un exemplu simplu care arată cum să folosești NoiseLearnerOptions într-un experiment 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()
Introducerea modelului de zgomot într-o primitivă
Modelul de zgomot învățat pe Circuit poate fi folosit și ca intrare pentru primitiva EstimatorV2 implementată în Qiskit Runtime. Acesta poate fi transmis primitivei în câteva moduri diferite. Următoarele trei exemple arată cum poți transmite modelul de zgomot atributului estimator.options direct, folosind un obiect ResilienceOptionsV2 înainte de a instanția o primitivă Estimator, și prin transmiterea unui dicționar formatat corespunzător.
# Pass the noise model to the `estimator.options` attribute directly
estimator = EstimatorV2(mode=backend)
estimator.options.resilience.layer_noise_model = noise_model
# 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)
# Specify options by using a dictionary
options_dict = {
"resilience_level": 2,
"resilience": {"layer_noise_model": noise_model},
}
estimator = EstimatorV2(mode=backend, options=options_dict)
După ce modelul de zgomot este transmis obiectului EstimatorV2, acesta poate fi utilizat pentru a rula sarcini de lucru și pentru a efectua atenuarea erorilor în mod normal.
NoiseLearnerV3
Prezentare generală
Similar cu NoiseLearner, clasa NoiseLearnerV3 efectuează experimente care caracterizează procesele de zgomot pe baza unui model de zgomot Pauli-Lindblad pentru unul sau mai multe circuite. Metoda sa run() acceptă o listă de instrucțiuni, fiecare dintre acestea trebuind să fie un BoxOp adnotat cu twirling și conținând operații ISA.
Rezultatul unui job NoiseLearnerV3 conține o listă de obiecte NoiseLearnerV3Result, câte unul pentru fiecare instrucțiune de intrare.
Următorul cod arată cum să folosești programul ajutor.
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='r789B', modifier_ref='', site='before')]
Rezultatul job-ului este o listă de obiecte NoiseLearnerV3Result, câte unul pentru fiecare set de instrucțiuni în cutie de la intrare. NoiseLearnerV3Result dispune de o metodă to_pauli_lindblad_map() care returnează un obiect PauliLindbladMap, care oferă metode pentru extragerea generatorilor, ratelor de eroare și altele.
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_0, Y_0, Z_0]>
Along with the error rates (truncated to 3):
[0.00026 0.00032 0.00023]
Opțiuni pentru învățarea zgomotului
NoiseLearnerV3 suportă mai multe opțiuni, inclusiv numărul de randomizări și adâncimea perechilor de straturi, printre altele. Similar cu primitivele, poți specifica opțiunile în timpul sau după instanțierea obiectului NoiseLearnerV3. Exemplul de cod anterior a demonstrat cum să setezi opțiunile shots_per_randomization și num_randomizations. Consultă documentația API NoiseLearnerV3Options pentru informații detaliate.
Introducerea unui model de zgomot în Executor
Executor urmează intențiile de design specificate în adnotările circuitului (sub forma unui samplex) și opțiuni. InjectNoise este adnotarea pentru specificarea unde să se injecteze zgomotul, iar argumentul samplex pauli_lindblad_maps specifică ce hartă de zgomot să fie utilizată.
Circuitul din exemplul anterior trece prin managerul de treceri boxing, care grupează instrucțiunile în cutii adnotate. Codul relevant este adăugat aici pentru ușurința înțelegerii.
inject_noise_targets="gates"specifică adăugarea adnotărilorInjectNoisela cutiile ce conțin poarte de entanglare.inject_noise_strategy="uniform_modification"specifică atribuirea aceluiașirefșimodifier_reftuturor cutiilor echivalente cu adnotăriInjectNoise.InjectNoise.refeste un identificator unic folosit pentru a atribui un model de zgomot acelei cutii.InjectNoise.modifier_refpermite scalarea modelului de zgomot atribuit unei cutii prin factori multiplicativi.
boxing_pm = generate_boxing_pass_manager(
enable_gates=True,
enable_measures=False,
inject_noise_targets="gates", # no measurement mitigation
inject_noise_strategy="uniform_modification",
)
Circuitul din exemplul anterior conține trei cutii, dintre care două conțin adnotări InjectNoise cu atribute ref diferite (deoarece nu sunt echivalente).
# 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='r789B', modifier_ref='r789B', site='before')]
Annotations of box #1: [Twirl(group='pauli', dressing='left', decomposition='rzsx'), InjectNoise(ref='r054B', modifier_ref='r054B', site='before')]
Annotations of box #2: [Twirl(group='pauli', dressing='right', decomposition='rzsx')]
Rezultatul job-ului NoiseLearnerV3 trebuie convertit într-un dicționar înainte de a fi transmis Executor. Cheile acestui dicționar sunt atributele InjectNoise.ref, iar valorile sunt hărțile de zgomot corespunzătoare. Această mapare îi spune Executor-ului ce modele de zgomot să injecteze și unde.
Următorul cod arată cum să iei circuitul și rezultatul NoiseLearnerV3 din exemplul anterior și să le transmiți Executor-ului, care va genera variantele de circuit cu modelele de zgomot injectate și le va executa pe hardware.
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)
Pașii următori
- Consultă referința API EstimatorOptions și referința API ResilienceOptionsV2.
- Află mai multe despre tehnicile de atenuare și suprimare a erorilor disponibile prin Qiskit Runtime.
- Află cum să implementezi gestionarea zgomotului cu Estimator.
- Citește Migrează la primitivele V2.