Sari la conținutul principal
Acest proiect este în versiune beta. Ai găsit o eroare? Deschide un issue pe GitHub. Ai o întrebare sau o idee? Întreabă în Discussions — ne-ar plăcea să aflăm părerea ta!
Cum este calitatea traducerii pe această pagină?

Programul auxiliar 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.5.2
qiskit-ibm-runtime~=0.47.0
samplomatic~=0.21.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.

notă

NoiseLearner funcționează doar cu EstimatorV2 pe partea de server, iar NoiseLearnerV3 funcționează doar cu Executor și cu noul Estimator pe partea de client (introdus în qiskit-ibm-runtime v0.50.0).

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.

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"numpy": "numpy", "qiskit": "qiskit", "qiskit_ibm_runtime": "qiskit-ibm-runtime", "samplomatic": "samplomatic"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
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='r223A', modifier_ref='', site='after')]

Rezultatul job-ului este o listă de obiecte NoiseLearnerV3Result, câte unul pentru fiecare set de instrucțiuni încapsulat într-o cutie 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.

import numpy

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_5, Y_5, Z_5]>

Along with the error rates (truncated to 3):
[2.3e-04 9.0e-05 1.1e-04]

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 care specifică unde se injectează zgomotul, iar argumentul samplex pauli_lindblad_maps specifică ce hartă de zgomot să fie utilizată.

Circuitul din exemplul anterior trece prin pass manager-ul de 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ărilor InjectNoise la cutiile care conțin entangleri.
  • inject_noise_strategy="uniform_modification" specifică atribuirea acelorași ref și modifier_ref tuturor cutiilor echivalente cu adnotări InjectNoise.
    • InjectNoise.ref este un identificator unic folosit pentru a atribui un model de zgomot acelei cutii.
    • InjectNoise.modifier_ref permite 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='r223A', modifier_ref='r223A', site='after')]

Annotations of box #1: [Twirl(group='pauli', dressing='left', decomposition='rzsx'), InjectNoise(ref='r621A', modifier_ref='r621A', site='after')]

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-ului. 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)

Utilizarea NoiseLearnerV3 cu Estimator pe partea de client​

Următorul cod arată cum să folosești programul ajutor cu noul Estimator pe partea de 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()

NoiseLearner​

Începând cu qiskit_ibm_runtime v0.51.0, NoiseLearner a fost depreciat. Consultă Migrarea la NoiseLearnerV3 pentru instrucțiuni de migrare.

Dă clic pentru a afla mai multe.

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-urile trimise. Mai jos este un fragment de cod care demonstrează utilizarea programului ajutor.

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 circuitelor ț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"
)

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

Λ(ρ)=exp⁡∑jrj(PjρPj†−ρ),\Lambda(\rho) = \exp{\sum_j r_j \left(P_j \rho P_j^\dagger - \rho\right)},

unde rjr_j sunt LayerError.rates, iar PjP_j 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()

Transmiterea modelului de zgomot către o primitivă​

Modelul de zgomot învățat pe Circuit poate fi folosit și ca intrare pentru primitiva IBM Quantum EstimatorV2. 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.

# Option 1: Pass the noise model to the `estimator.options` attribute directly
estimator = EstimatorV2(mode=backend)
estimator.options.resilience.layer_noise_model = noise_model

# Option 2: 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)

# Option 3: 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.

Pașii următori​