تصحيح أخطاء مهام Qiskit Runtime
إصدارات الحزم
الكود في هذه الصفحة طُوِّر باستخدام المتطلبات التالية. ننصح باستخدام هذه الإصدارات أو ما هو أحدث منها.
qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1
qiskit-aer~=0.17
قبل إرسال حِمل عمل Qiskit Runtime الذي يستهلك موارد كبيرة لتنفيذه على العتاد الفعلي، يمكنك استخدام كلاس Neat (أداة تحليل المُقدِّر الصاخب) في Qiskit Runtime للتحقق من أن حِمل عمل Estimator لديك مُعَدٌّ بالشكل الصحيح، ومن المرجح أن يُعيد نتائج دقيقة، ويستخدم الخيارات الأنسب للمسألة المحددة، وغير ذلك.
تقوم Neat بتحويل الدوائر الكمية المُدخَلة إلى دوائر كليفورد (Clifford) لمحاكاة أكثر كفاءة، مع الحفاظ على بنيتها وعمقها. تتعرض دوائر كليفورد لمستويات مشابهة من الضوضاء، وتُعدّ وسيلة جيدة لدراسة الدائرة الأصلية موضع الاهتمام.
تُوضّح الأمثلة التالية حالات يمكن فيها لـNeat أن تكون مورداً مفيداً.
أولاً، استورد الحزم ذات الصلة واحصل على مصادقة خدمة Qiskit Runtime.
تجهيز البيئة
# 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)
تهيئة دائرة هدف
تأمّل دائرة كمية من ستة كيوبتات تمتلك الخصائص التالية:
- تتناوب بين دورات
RZعشوائية وطبقات من بواباتCNOT. - تمتلك بنية مرآة؛ أي إنها تُطبّق وحدة
Uيتبعها معكوسها.
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)
اختر مؤثرات Z أحادية الباولي كمشاهدات، واستخدمها لتهيئة كتل الوحدات الأولية الموحدة (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']
تحويل الدوائر إلى كليفورد
دوائر PUB المُعرَّفة مسبقاً ليست دوائر كليفورد، مما يجعل محاكاتها كلاسيكياً أمراً صعباً. غير أنه يمكنك استخدام طريقة to_clifford في Neat لتحويلها إلى دوائر كليفورد لمحاكاة أكثر كفاءة. طريقة to_clifford هي غلّاف حول تمريرة الـTranspiler ConvertISAToClifford، التي يمكن استخدامها بشكل مستقل أيضاً. تحديداً، تستبدل هذه الطريقة بوابات الكيوبت الواحد غير الكليفوردية في الدائرة الأصلية ببوابات كيوبت واحد كليفوردية، لكنها لا تُعدّل بوابات الكيوبتين، ولا عدد الكيوبتات، ولا عمق الدائرة.
راجع المحاكاة الفعّالة للدوائر المُثبِّتة مع Qiskit Aer primitives لمزيد من المعلومات حول محاكاة دوائر كليفورد.
أولاً، هيّئ 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)
بعد ذلك، حوّل الـPUBs إلى دوائر كليفورد.
clifford_pubs = analyzer.to_clifford(pubs)
clifford_pubs[0].circuit.draw("mpl", idle_wires=0)
التطبيق 1: تحليل تأثير الضوضاء على مخرجات الدائرة
يوضّح هذا المثال كيفية استخدام Neat لدراسة تأثير نماذج الضوضاء المختلفة على PUBs بوصفها دالةً لعمق الدائرة، وذلك عبر تشغيل محاكاتٍ في ظروف مثالية (ideal_sim) وأخرى بضوضاء (noisy_sim). يمكن أن يكون ذلك مفيداً لوضع توقعات حول جودة النتائج التجريبية قبل تشغيل المهمة على وحدة معالجة الكم (QPU). لمزيد من المعلومات حول نماذج الضوضاء، راجع المحاكاة الدقيقة والمحاكاة بالضوضاء مع Qiskit Aer primitives.
تدعم النتائج المحاكاة العمليات الرياضية، وبالتالي يمكن مقارنتها مع بعضها (أو مع النتائج التجريبية) لحساب مقاييس الجودة.
قد تتأثر وحدة QPU بأنواع مختلف ة من الضوضاء. نموذج ضوضاء Qiskit Aer المستخدم هنا لا يحاكي سوى بعضها، وبالتالي فمن المرجح أن يكون أقل حدةً من الضوضاء الموجودة على وحدة QPU الفعلية.
للاطلاع على تفاصيل الأخطاء المُضمَّنة عند تهيئة نموذج الضوضاء من وحدة QPU، راجع مرجع Aer API لـ NoiseModel.
ابدأ بإجراء محاكاتٍ كلاسيكية مثالية وأخرى بضوضاء.
# 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.99023438, 0.99609375, 0.9921875 , 0.99023438, 0.99414062,
0.99414062])), NeatPubResult(vals=array([0.984375 , 0.99414062, 0.98242188, 0.98828125, 0.98632812,
0.99414062])), NeatPubResult(vals=array([0.96679688, 0.97070312, 0.95898438, 0.97851562, 0.98046875,
0.98828125])), NeatPubResult(vals=array([0.9453125 , 0.953125 , 0.97070312, 0.96875 , 0.98242188,
0.99023438])), NeatPubResult(vals=array([0.93164062, 0.9375 , 0.953125 , 0.96875 , 0.96484375,
0.98046875])), NeatPubResult(vals=array([0.92578125, 0.921875 , 0.93359375, 0.953125 , 0.95898438,
0.9765625 ]))])
بعد ذلك، طبّق العمليات الرياضية لحساب الفرق المطلق. يستخدم بقية الدليل الفرق المطلق بوصفه مقياساً للجودة لمقارنة النتائج المثالية بالنتائج المشوَّشة أو التجريبية، غير أنه يمكن إعداد مقاييس جودة مشابهة أيضاً.
يوضّح الفرق المطلق أن تأثير الضوضاء يزداد مع زيادة أحجام الدوائر.
# 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 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:
0.72%
Mean absolute difference between ideal and noisy results for circuits with 2 layers:
1.17%
Mean absolute difference between ideal and noisy results for circuits with 3 layers:
2.6%
Mean absolute difference between ideal and noisy results for circuits with 4 layers:
3.16%
Mean absolute difference between ideal and noisy results for circuits with 5 layers:
4.4%
Mean absolute difference between ideal and noisy results for circuits with 6 layers:
5.5%
يمكنك اتباع هذه الإرشادات التقريبية والمبسَّطة لتحسين الدوائر من هذا النوع:
- إذا كان متوسط الفرق المطلق أكبر من 90%، فمن المرجح ألا تُجدي المعالجة نفعاً.
- إذا كان متوسط الفرق المطلق أقل من 90%، فمن المرجح أن تتمكن تضخيم الخطأ الاحتمالي (PEA) من تحسين النتائج.
- إذا كان متوسط الفرق المطلق أقل من 80%، فمن المرجح أيضاً أن يتمكن ZNE مع طيّ البوابات من تحسين النتائج.
نظراً لأن جميع الفوارق المطلقة أعلاه أقل من 90%، فإن تطبيق PEA على الدائرة الأصلية سيُحسّن على الأرجح جودة نتائجها. يمكنك تحديد نماذج ضوضاء مختلفة في المحلل. يُجري المثال التال ي نفس الاختبار لكنه يُضيف نموذج ضوضاء مخصصاً.
# 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 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%
كما هو موضّح، بمعرفة نموذج الضوضاء، يمكنك محاولة قياس تأثير الضوضاء على PUBs المعنية (في نسختها Cliffordized) قبل تشغيلها على وحدة QPU.
التطبيق 2: قياس أداء استراتيجيات مختلفة
يستخدم هذا المثال Neat للمساعدة في تحديد أفضل الخيارات لـ PUBs الخاصة بك. للقيام بذلك، فكّر في تشغيل مسألة تقدير مع PEA، والتي لا يمكن محاكاتها باستخدام qiskit_aer. يمكنك استخدام Neat للمساعدة في تحديد عوامل تضخيم الضوضاء الأنسب، ثم استخدام تلك العوامل عند تشغيل التجربة الأصلية على وحدة 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 tell 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 {factors}:\n {np.round(np.mean(d), 2)}%\n"
)
Mean absolute difference for factors [1, 1.1]:
6.83%
Mean absolute difference for factors [1, 1.1, 1.2]:
8.76%
Mean absolute difference for factors [1, 1.5, 2]:
8.03%
Mean absolute difference for factors [1, 1.5, 2, 2.5, 3]:
10.17%
Mean absolute difference for factors [1, 4]:
8.02%
تشير النتي جة ذات الفرق الأصغر إلى الخيارات الأنسب للاستخدام.
الخطوات التالية
- تعلَّم عن المحاكاة الدقيقة والمحاكاة بالضوضاء مع Qiskit Aer primitives.
- تعلَّم عن خيارات Qiskit Runtime المتاحة.
- تعلَّم عن تقنيات تخفيف الأخطاء وقمعها.
- زُر موضوع التحويل باستخدام مديري التمريرات.
- تعلَّم كيفية تحويل الدوائر كجزء من سير عمل أنماط Qiskit باستخدام Qiskit Runtime.
- راجع توثيق API لأدوات التصحيح.