Přeskočit na hlavní obsah

Ladění úloh Qiskit Runtime

Package versions

Kód na této stránce byl vyvinut s použitím následujících požadavků. Doporučujeme používat tyto verze nebo novější.

qiskit[all]~=2.4.0
qiskit-ibm-runtime~=0.46.1
qiskit-aer~=0.17

Pomocí třídy Neat můžeš analyzovat dopad šumu na pracovní zátěž Estimatoru. Pro ověření syntaxe použij Místní testovací režim.

Použití třídy Neat

Před odesláním náročné úlohy Qiskit Runtime ke spuštění na hardwaru můžeš použít třídu Qiskit Runtime Neat (Noisy Estimator Analyzer Tool) k ověření, že je tvoje úloha Estimatoru správně nastavena, pravděpodobně vrátí přesné výsledky, používá nejvhodnější možnosti pro zadaný problém a podobně.

Neat Cliffordizuje vstupní Circuit pro efektivní simulaci, přičemž zachovává jeho strukturu a hloubku. Cliffordovy Circuit trpí podobnou mírou šumu a jsou dobrým přibližovadlem pro studium původního Circuit zájmu. Nejprve importuj příslušné balíčky a ověř svoji identitu ve službě Qiskit Runtime.

Příprava prostředí

# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-aer qiskit-ibm-runtime
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, EstimatorV2 as 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)

Inicializace cílového Circuit

Uvažuj šestiqubitový Circuit s následujícími vlastnostmi:

  • Střídá náhodné rotace RZ a vrstvy Gate CNOT.
  • Má zrcadlovou strukturu, tedy aplikuje unitární operaci U následovanou její inverzí.
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)

Výstup předchozí buňky kódu

Jako pozorovatelné veličiny zvol jednopauliové operátory Z a použij je k inicializaci primitiv unified blocs (PUBs).

# 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]
Observables: ['ZIIIII', 'IZIIII', 'IIZIII', 'IIIZII', 'IIIIZI', 'IIIIIZ']

Cliffordizace Circuit

Dříve definované PUB Circuit nejsou Cliffordovy, což je ztěžuje klasicky simulovat. Můžeš však použít metodu Neat to_clifford k jejich mapování na Cliffordovy Circuit pro efektivnější simulaci. Metoda to_clifford je obalová funkce kolem Transpiler průchodu ConvertISAToClifford, který lze také použít samostatně. Konkrétně nahrazuje nekliffordovy jednoqubitové Gate v původním Circuit Cliffordovými jednoqubitovými Gate, ale nemění dvoququbitové Gate, počet Qubitů ani hloubku Circuit.

Více informací o simulaci Cliffordových Circuit najdeš v části Efektivní simulace stabilizátorových Circuit s primitiv Qiskit Aer. Nejprve inicializuj 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)

Poté Cliffordizuj PUBs.

clifford_pubs = analyzer.to_clifford(pubs)

clifford_pubs[0].circuit.draw("mpl", idle_wires=0)

Výstup předchozí buňky kódu

Aplikace 1: Analýza dopadu šumu na výstupy Circuit

Tento příklad ukazuje, jak použít Neat ke studiu dopadu různých modelů šumu na PUBs v závislosti na hloubce Circuit spouštěním simulací v ideálních podmínkách (ideal_sim) i v podmínkách se šumem (noisy_sim). Toto může být užitečné pro nastavení očekávání ohledně kvality experimentálních výsledků před spuštěním úlohy na QPU. Více o modelech šumu se dozvíš v části Přesná a šumová simulace s primitiv Qiskit Aer.

Simulované výsledky podporují matematické operace, a proto je lze navzájem porovnávat (nebo s experimentálními výsledky) za účelem výpočtu ukazatelů kvality.

pozor

QPU může být ovlivněn různými druhy šumu. Model šumu Qiskit Aer použitý zde simuluje pouze některé z nich, a proto bude pravděpodobně méně závažný než šum na reálném QPU.

Podrobnosti o tom, jaké chyby jsou zahrnuty při inicializaci modelu šumu z QPU, najdeš v referenční dokumentaci Aer NoiseModel API.

Začni provedením ideálních a šumových klasických simulací.

# 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")
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.98242188, 0.984375 , 0.98828125, 0.99023438, 0.96484375,
0.97265625])), NeatPubResult(vals=array([0.96875 , 0.97070312, 0.98046875, 0.98828125, 0.96484375,
0.984375 ])), NeatPubResult(vals=array([0.94140625, 0.94726562, 0.92773438, 0.93164062, 0.93164062,
0.95703125])), NeatPubResult(vals=array([0.91015625, 0.90429688, 0.90039062, 0.93164062, 0.94140625,
0.953125 ])), NeatPubResult(vals=array([0.875 , 0.88476562, 0.88476562, 0.8984375 , 0.91601562,
0.91210938])), NeatPubResult(vals=array([0.88476562, 0.89453125, 0.86523438, 0.91015625, 0.86914062,
0.91992188]))])

Dále proveď matematické operace pro výpočet absolutního rozdílu. Zbytek průvodce používá absolutní rozdíl jako ukazatel kvality pro porovnání ideálních výsledků s šumovými nebo experimentálními výsledky, ale lze sestavit i podobné ukazatele kvality.

Absolutní rozdíl ukazuje, že dopad šumu roste s velikostí Circuit.

# Figure of merit: Absolute difference
def rdiff(res1, re2):
r"""The absolute difference between `res1` and re2`.

--> The closer to `0`, the better.
"""
d = abs(res1 - re2)
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"
)
Mean absolute difference between ideal and noisy results for circuits with 1 layers:
1.95%

Mean absolute difference between ideal and noisy results for circuits with 2 layers:
2.38%

Mean absolute difference between ideal and noisy results for circuits with 3 layers:
6.06%

Mean absolute difference between ideal and noisy results for circuits with 4 layers:
7.65%

Mean absolute difference between ideal and noisy results for circuits with 5 layers:
10.48%

Mean absolute difference between ideal and noisy results for circuits with 6 layers:
10.94%

Pro zlepšení Circuit tohoto typu můžeš dodržovat tato přibližná a zjednodušená pravidla:

  • Pokud je střední absolutní rozdíl větší než 90 %, mitigace pravděpodobně nepomůže.
  • Pokud je střední absolutní rozdíl menší než 90 %, Probabilistic Error Amplification (PEA) pravděpodobně dokáže zlepšit výsledky.
  • Pokud je střední absolutní rozdíl menší než 80 %, ZNE s Gate foldingem také pravděpodobně dokáže zlepšit výsledky.

Protože všechny výše uvedené absolutní rozdíly jsou menší než 90 %, použití PEA na původní Circuit by mělo zlepšit kvalitu jeho výsledků. V analyzátoru můžeš specifikovat různé modely šumu. Následující příklad provede stejný test, ale přidá vlastní model šumu.

# 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"], 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"
)
Mean absolute difference between ideal and noisy results for circuits with 1 layers:
0.0%

Mean absolute difference between ideal and noisy results for circuits with 2 layers:
0.0%

Mean absolute difference between ideal and noisy results for circuits with 3 layers:
0.0%

Mean absolute difference between ideal and noisy results for circuits with 4 layers:
0.0%

Mean absolute difference between ideal and noisy results for circuits with 5 layers:
0.0%

Mean absolute difference between ideal and noisy results for circuits with 6 layers:
0.0%

Jak je vidět, při daném modelu šumu můžeš před spuštěním PUBs na QPU zkusit kvantifikovat dopad šumu na (Cliffordizovanou verzi) PUBs zájmu.

Aplikace 2: Porovnání různých strategií

Tento příklad používá Neat k identifikaci nejlepších možností pro tvoje PUBs. K tomu zvažuj spuštění problému odhadování s PEA, který nelze simulovat pomocí qiskit_aer. Můžeš použít Neat k určení, které faktory zesílení šumu budou fungovat nejlépe, a poté tyto faktory použít při spuštění původního experimentu na QPU.

# 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"

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"
)
Mean absolute difference for factors [1, 1.1]:
2.42%

Mean absolute difference for factors [1, 1.1, 1.2]:
11.34%

Mean absolute difference for factors [1, 1.5, 2]:
3.68%

Mean absolute difference for factors [1, 1.5, 2, 2.5, 3]:
4.77%

Mean absolute difference for factors [1, 4]:
3.61%

Výsledek s nejmenším rozdílem naznačuje, které možnosti zvolit.

Další kroky

Doporučení