Jobs mit NEAT debuggen
Der Code auf dieser Seite wurde unter Berücksichtigung der folgenden Anforderungen entwickelt. Wir empfehlen die Verwendung dieser oder neuerer Versionen.
qiskit[all]~=2.5.2 qiskit-ibm-runtime~=0.47.0 qiskit-aer~=0.17
Sie können die Neat Klasse verwenden, um die Auswirkungen von Rauschen auf eine Estimator-Workload zu analysieren. Verwenden Sie zur Syntaxprüfung den lokalen Testmodus.
Neat Verwendung der Klasse
Bevor Sie eine ressourcenintensive Arbeitslast zur Ausführung auf der Hardware übermitteln, können Sie mithilfe der NEAT-Klasse (Noisy Estimator Analyzer Tool) von „ IBM Quantum “ Compute überprüfen, ob Ihre Estimator-Arbeitslast korrekt eingerichtet ist, voraussichtlich genaue Ergebnisse liefert, die für das jeweilige Problem am besten geeigneten Optionen verwendet und vieles mehr.
Neat Die Eingangsschaltungen werden für eine effiziente Simulation cliffordisiert, wobei ihre Struktur und Tiefe erhalten bleiben. Clifford-Schaltungen weisen ein ähnliches Maß an Rauschen auf und sind ein guter Ersatz für die Untersuchung der ursprünglichen Schaltung von Interesse.
Importieren Sie zunächst die entsprechenden Pakete und authentifizieren Sie sich beim IBM Quantum Compute Service.
Vorbereitung der Umgebung
import numpy as np
import random
from qiskit.circuit import QuantumCircuit
from qiskit.transpiler import generate_preset_pass_manager
from qiskit.quantum_info import SparsePauliOp
from qiskit_ibm_runtime import QiskitRuntimeService, NoiseLearnerV3
# Legacy server-side primitive before qiskit-ibm-runtime 0.50.0
# from qiskit_ibm_runtime import Estimator
# Client-side primitive introduced in qiskit-ibm-runtime 0.50.0
from qiskit_ibm_runtime.executor_estimator import Estimator
from qiskit_ibm_runtime.debug_tools import Neat
from qiskit_aer.noise import NoiseModel, depolarizing_error# Choose the least busy backend
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
# Generate a preset pass manager
# This will be used to convert the abstract circuit to an equivalent
# Instruction Set Architecture (ISA) circuit.
pm = generate_preset_pass_manager(backend=backend, optimization_level=0)
# Set the random seed
random.seed(10)Initialisieren Sie eine Zielschaltung
Betrachten Sie eine Sechs-Qubit-Schaltung, die die folgenden Eigenschaften hat:
- Wechselt zwischen zufälligen "RZ"-Drehungen und Schichten von "CNOT"-Toren.
- Hat eine spiegelbildliche Struktur, d. h. sie wendet eine einheitliche
Ugefolgt von ihrer Umkehrung an.
def generate_circuit(n_qubits, n_layers):
r"""
A function to generate a pseudo-random a circuit with ``n_qubits`` qubits
and ``2*n_layers`` entangling layers of the type used in this notebook.
"""
# An array of random angles
angles = [
[random.random() for q in range(n_qubits)] for s in range(n_layers)
]
qc = QuantumCircuit(n_qubits)
qubits = list(range(n_qubits))
# do random circuit
for layer in range(n_layers):
# rotations
for q_idx, qubit in enumerate(qubits):
qc.rz(angles[layer][q_idx], qubit)
# cx gates
control_qubits = (
qubits[::2] if layer % 2 == 0 else qubits[1 : n_qubits - 1 : 2]
)
for qubit in control_qubits:
qc.cx(qubit, qubit + 1)
# undo random circuit
for layer in range(n_layers)[::-1]:
# cx gates
control_qubits = (
qubits[::2] if layer % 2 == 0 else qubits[1 : n_qubits - 1 : 2]
)
for qubit in control_qubits:
qc.cx(qubit, qubit + 1)
# rotations
for q_idx, qubit in enumerate(qubits):
qc.rz(-angles[layer][q_idx], qubit)
return qc
# Generate a random circuit
qc = generate_circuit(6, 3)
# Convert the abstract circuit to an equivalent ISA circuit.
isa_qc = pm.run(qc)
qc.draw("mpl", idle_wires=0)Output:
Wählen Sie Einzel-Pauli Z Operatoren als Observablen und verwenden Sie sie, um die primitiven vereinheitlichten Blöcke (PUBs) zu initialisieren.
# Initialize the observables
obs = ["ZIIIII", "IZIIII", "IIZIII", "IIIZII", "IIIIZI", "IIIIIZ"]
print(f"Observables: {obs}")
# Map the observables to the backend's layout
isa_obs = [SparsePauliOp(o).apply_layout(isa_qc.layout) for o in obs]
# Initialize the PUBs, which consist of six-qubit circuits
# with `n_layers` 1, ..., 6
all_n_layers = [1, 2, 3, 4, 5, 6]
pubs = [(pm.run(generate_circuit(6, n)), isa_obs) for n in all_n_layers]Output:
Observables: ['ZIIIII', 'IZIIII', 'IIZIII', 'IIIZII', 'IIIIZI', 'IIIIIZ']
Die Schaltkreise cliffordisieren
Die zuvor definierten PUB Schaltungen sind nicht Clifford, was ihre klassische Simulation erschwert. Sie können jedoch mit der Methode Neat to_clifford verwenden, um sie für eine effizientere Simulation auf Clifford-Schaltungen abzubilden. Die Methode to_clifford methode ist ein Wrapper um den ConvertISAToClifford transpiler-Pass, der auch unabhängig davon verwendet werden kann. Insbesondere werden nicht-Clifford-Ein-Qubit-Gatter in der ursprünglichen Schaltung durch Clifford-Ein-Qubit-Gatter ersetzt, aber die Zwei-Qubit-Gatter, die Anzahl der Qubits oder die Schaltungstiefe werden nicht verändert.
Weitere Informationen über die Simulation von Clifford-Schaltungen finden Sie unter Effiziente Simulation von Stabilisierungsschaltungen mit Qiskit Aer-Primitiven.
Initialisieren Sie zunächst Neat.
# You could specify a custom `NoiseModel` here. If `None`, `Neat`
# pulls the noise model from the given backend
noise_model = None
# Initialize `Neat`
analyzer = Neat(backend, noise_model)Als Nächstes müssen Sie die PUBs cliffordisieren.
clifford_pubs = analyzer.to_clifford(pubs)
clifford_pubs[0].circuit.draw("mpl", idle_wires=0)Output:
Anwendung 1: Analyse der Auswirkungen von Störgeräuschen auf die Schaltungsausgänge
Dieses Beispiel zeigt, wie man mit Hilfe Neat von die Auswirkungen verschiedener Rauschmodelle auf PUBs als Funktion der Schaltungstiefe untersuchen kann, indem Simulationen sowohl unter idealen (ideal_sim) als auch unter verrauschten (noisy_sim) Bedingungen durchgeführt werden. Dies kann nützlich sein, um Erwartungen an die Qualität der Versuchsergebnisse zu formulieren, bevor ein Auftrag auf einer QPU ausgeführt wird. Weitere Informationen zu Rauschmodellen finden Sie unter Exakte und verrauschte Simulation mit Qiskit Aer-Primitiven.
Die simulierten Ergebnisse unterstützen mathematische Operationen und können daher miteinander (oder mit experimentellen Ergebnissen) verglichen werden, um Leistungskennzahlen zu berechnen.
Ein QPU kann durch verschiedene Arten von Lärm beeinträchtigt werden. Das hier verwendete Qiskit-Aer-Rauschmodell simuliert nur einige davon und ist daher wahrscheinlich weniger stark als das Rauschen auf einer echten QPU.
Einzelheiten darüber, welche Fehler bei der Initialisierung eines Rauschmodells von einer QPU enthalten sind, finden Sie in der Aer NoiseModel API-Referenz.
Beginnen Sie mit der Durchführung idealer und verrauschter klassischer Simulationen.
# Perform a noiseless simulation
ideal_results = analyzer.ideal_sim(clifford_pubs)
print(f"Ideal results:\n {ideal_results}\n")
# Perform a noisy simulation with the backend's noise model
noisy_results = analyzer.noisy_sim(clifford_pubs)
print(f"Noisy results:\n {noisy_results}\n")Output:
Ideal results:
NeatResult([NeatPubResult(vals=array([1., 1., 1., 1., 1., 1.])), NeatPubResult(vals=array([1., 1., 1., 1., 1., 1.])), NeatPubResult(vals=array([1., 1., 1., 1., 1., 1.])), NeatPubResult(vals=array([1., 1., 1., 1., 1., 1.])), NeatPubResult(vals=array([1., 1., 1., 1., 1., 1.])), NeatPubResult(vals=array([1., 1., 1., 1., 1., 1.]))])
Noisy results:
NeatResult([NeatPubResult(vals=array([0.99609375, 0.99414062, 0.98632812, 0.9921875 , 0.97460938,
0.97851562])), NeatPubResult(vals=array([0.984375 , 0.98828125, 0.98046875, 0.98632812, 0.96679688,
0.98828125])), NeatPubResult(vals=array([0.9609375 , 0.9765625 , 0.953125 , 0.95898438, 0.95703125,
0.96679688])), NeatPubResult(vals=array([0.96875 , 0.97070312, 0.93164062, 0.94335938, 0.93164062,
0.97460938])), NeatPubResult(vals=array([0.9140625 , 0.9296875 , 0.91796875, 0.92382812, 0.90429688,
0.91992188])), NeatPubResult(vals=array([0.89648438, 0.9140625 , 0.921875 , 0.94921875, 0.92773438,
0.95117188]))])
Wenden Sie anschließend mathematische Operationen an, um die absolute Differenz zu berechnen. Im weiteren Verlauf des Leitfadens wird die absolute Differenz als Leistungskennzahl verwendet, um ideale Ergebnisse mit verrauschten oder experimentellen Ergebnissen zu vergleichen, aber es können ähnliche Leistungskennzahlen aufgestellt werden.
Die absolute Differenz zeigt, dass die Auswirkungen des Rauschens mit der Größe der Schaltkreise zunehmen.
# Figure of merit: Absolute difference
def rdiff(res1, res2):
r"""The absolute difference between `res1` and res2`.
--> The closer to `0`, the better.
"""
d = abs(res1 - res2)
return np.round(d.vals * 100, 2)
for idx, (ideal_res, noisy_res) in enumerate(
zip(ideal_results, noisy_results)
):
vals = rdiff(ideal_res, noisy_res)
# Print the mean absolute difference for the observables
mean_vals = np.round(np.mean(vals), 2)
print(
f"Mean absolute difference between ideal and noisy results "
f"for circuits with {all_n_layers[idx]} layers:\n {mean_vals}%\n"
)Output:
Mean absolute difference between ideal and noisy results for circuits with 1 layers:
1.3%
Mean absolute difference between ideal and noisy results for circuits with 2 layers:
1.76%
Mean absolute difference between ideal and noisy results for circuits with 3 layers:
3.78%
Mean absolute difference between ideal and noisy results for circuits with 4 layers:
4.66%
Mean absolute difference between ideal and noisy results for circuits with 5 layers:
8.17%
Mean absolute difference between ideal and noisy results for circuits with 6 layers:
7.32%
Sie können diese groben und vereinfachten Richtlinien befolgen, um Schaltungen dieser Art zu verbessern:
- Wenn die mittlere absolute Differenz mehr als 90 % beträgt, ist eine Milderung wahrscheinlich nicht sinnvoll.
- Wenn die mittlere absolute Differenz weniger als 90 % beträgt, kann die probabilistische Fehlerverstärkung (PEA ) die Ergebnisse wahrscheinlich verbessern.
- Wenn die mittlere absolute Differenz weniger als 80 % beträgt, können die Ergebnisse wahrscheinlich auch durch ZNE mit Gate-Faltung verbessert werden.
Da alle oben genannten absoluten Unterschiede weniger als 90 % betragen, wird die Anwendung der PEA auf den ursprünglichen Schaltkreis hoffentlich die Qualität der Ergebnisse verbessern.
Sie können im Analysator verschiedene Rauschmodelle angeben. Das folgende Beispiel führt denselben Test durch, fügt aber ein benutzerdefiniertes Rauschmodell hinzu.
# Set up a noise model with strength 0.02 on every two-qubit gate
noise_model = NoiseModel()
for qubits in backend.coupling_map:
noise_model.add_quantum_error(
depolarizing_error(0.02, 2), ["ecr", "cx", "cz"], qubits
)
# Update the analyzer's noise model
analyzer.noise_model = noise_model
# Perform a noiseless simulation
ideal_results = analyzer.ideal_sim(clifford_pubs)
# Perform a noisy simulation with the backend's noise model
noisy_results = analyzer.noisy_sim(clifford_pubs)
# Compare the results
for idx, (ideal_res, noisy_res) in enumerate(
zip(ideal_results, noisy_results)
):
values = rdiff(ideal_res, noisy_res)
# Print the mean absolute difference for the observables
mean_values = np.round(np.mean(values), 2)
print(
f"Mean absolute difference between ideal and noisy results "
f"for circuits with {all_n_layers[idx]} layers:\n {mean_values}%\n"
)Output:
Mean absolute difference between ideal and noisy results for circuits with 1 layers:
4.16%
Mean absolute difference between ideal and noisy results for circuits with 2 layers:
8.92%
Mean absolute difference between ideal and noisy results for circuits with 3 layers:
12.86%
Mean absolute difference between ideal and noisy results for circuits with 4 layers:
17.45%
Mean absolute difference between ideal and noisy results for circuits with 5 layers:
25.82%
Mean absolute difference between ideal and noisy results for circuits with 6 layers:
27.96%
Wie gezeigt, kann man mit einem Rauschmodell versuchen, die Auswirkungen des Rauschens auf die (Clifford'sche Version der) PUBs von Interesse zu quantifizieren, bevor man sie auf einer QPU laufen lässt.
Anwendung 2: Vergleich verschiedener Strategien
Dieses Beispiel verwendet Neat , um die besten Optionen für Ihre PUBs zu ermitteln. Betrachten Sie dazu ein Schätzungsproblem mit PEA, das nicht mit qiskit_aer simuliert werden kann. Sie können Neat verwenden, um zu bestimmen, welche Rauschverstärkungsfaktoren am besten funktionieren, und diese Faktoren dann bei der Durchführung des ursprünglichen Experiments auf einer QPU verwenden.
# Generate a circuit with six qubits and six layers
isa_qc = pm.run(generate_circuit(6, 3))
# Use the same observables as previously
pubs = [(isa_qc, isa_obs)]
clifford_pubs = analyzer.to_clifford(pubs)noise_factors = [
[1, 1.1],
[1, 1.1, 1.2],
[1, 1.5, 2],
[1, 1.5, 2, 2.5, 3],
[1, 4],
]# Run the PUBs on a QPU
estimator = Estimator(backend)
estimator.options.default_shots = 100000
estimator.options.twirling.enable_gates = True
estimator.options.twirling.enable_measure = True
estimator.options.twirling.shots_per_randomization = 100
estimator.options.resilience.measure_mitigation = True
estimator.options.resilience.zne_mitigation = True
estimator.options.resilience.zne.amplifier = "pea"
# Learn noise model
layers = estimator.find_unique_layers(clifford_pubs)
learner = NoiseLearnerV3(backend)
learner_job = learner.run(layers)
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 uses them.
estimator.options.resilience.layer_noise_model = zip(
layers, pauli_lindblad_maps
)
jobs = []
for factors in noise_factors:
estimator.options.resilience.zne.noise_factors = factors
jobs.append(estimator.run(clifford_pubs))
results = [job.result() for job in jobs]# Perform a noiseless simulation
ideal_results = analyzer.ideal_sim(clifford_pubs)# Look at the mean absolute difference to quickly determine
# the best choice for your options
for factors, res in zip(noise_factors, results):
d = rdiff(ideal_results[0], res[0])
print(
f"Mean absolute difference for factors "
f"{factors}:\n {np.round(np.mean(d), 2)}%\n"
)Output:
Mean absolute difference for factors [1, 1.1]:
10.9%
Mean absolute difference for factors [1, 1.1, 1.2]:
4.64%
Mean absolute difference for factors [1, 1.5, 2]:
4.33%
Mean absolute difference for factors [1, 1.5, 2, 2.5, 3]:
5.66%
Mean absolute difference for factors [1, 4]:
4.53%
Das Ergebnis mit der geringsten Differenz zeigt an, welche Optionen zu wählen sind.
Nächste Schritte
- Lesen Sie eine Übersicht über die Debugging-Tools von Qiskit.
- Erfahren Sie mehr über exakte und verrauschte Simulationen mit Qiskit Aer-Primitiven.
- Erfahren Sie mehr über die verfügbaren „ IBM Quantum “-Rechenoptionen.
- Erfahren Sie mehr über Techniken zur Fehlerminderung und -unterdrückung.
- Besuchen Sie das Thema Transpile mit Passmanagern.
- Erfahren Sie, wie Sie Schaltkreise im Rahmen von Qiskit-Patterns-Workflows transpilieren können.
- Lesen Sie die Dokumentation zur Debugging-Tools-API.