ابنِ تجربة تعلّم
يوضح هذا الدرس كيفية بناء تجربة تعلّم قياسية من الصفر، واستخدامها لتعلّم نموذج من بيانات ضوضائية محاكاة.
-
عرّف مجموعة بوابات على حلقة من الكيوبتات
-
اختر نموذج باولي-ليندبلاد ثنائي المحلية (2-local)
-
ابنِ تجربة التعلّم
-
ولّد الدوائر
-
جهّز المحاكاة المحلية
-
شغّل البرنامج
-
حلّل البيانات
تتم محاكاة الدوائر أدناه محلياً، لذا لا يحتاج هذا الشرح إلى بيانات اعتماد IBM Quantum®. لتشغيله بدلاً من ذلك على جهاز حقيقي:
-
الخطوة 1: استبدل
FakeMarrakeshبـ Backend حقيقي. -
الخطوة 5: مرّر هذا الـ Backend كوضع (mode) للمنفّذ، واحذف خيارات المحاكي.
1. عرّف مجموعة بوابات على حلقة من الكيوبتات
ابنِ QiskitGateSet من Target الخاص بالـ Backend ومجموعة جزئية من كيوبتاته — وهنا حلقة من اثني عشر كيوبت في FakeMarrakesh — ثم أضف إليها بوابة واحدة: طبقة من ست بوابات CZ تغطي تلك الحلقة. افتراضياً تُهيَّأ مجموعة البوابات ببوابة تحضير P وبوابة قياس M.
from qiskit_ibm_runtime.fake_provider import FakeMarrakesh
from qiskit_noise_learning.gate_sets import QiskitGateSet
backend = FakeMarrakesh()
qubit_subset = [*range(25, 30), *range(37, 39), *range(45, 50)]
cz_pairs = [(25, 26), (27, 28), (29, 38), (37, 45), (46, 47), (48, 49)]
gate_set = QiskitGateSet(backend.num_qubits, target=backend.target, qubit_subset=qubit_subset)
with gate_set.build_new_gate("cz_gate", latex_str=r"\mathrm{CZ}") as builder:
for pair in cz_pairs:
builder.circuit.cz(*pair)
list(gate_set)
['M', 'P', 'cz_gate']
from qiskit_ibm_runtime import QiskitRuntimeService
backend = QiskitRuntimeService().backend("ibm_marrakesh")
استدعِ draw() لرؤية البوابة على طوبولوجيا الجهاز: حلقة الكيوبتات في مجموعة البوابات، وأي أزواج منها تُشبكها البوابة.
gate_set.draw()
2. اختر نموذج باولي-ليندبلاد ثنائي المحلية (2-local)
حدّد أي مولّدات باولي-ليندبلاد يُسمح للضوضاء بامتلاكها باستخدام PauliLindbladModel. ابنِ مجموعة المولّدات هذه من ترابط مجموعة البوابات باستخدام k_local() — وهنا كل مؤثرات باولي ثنائية المحلية على أزواج الكيوبتات المتصلة في البوابة الوحدوية، ومؤثرات باولي أحادية الكيوبت للتحضير والقياس.
from qiskit_noise_learning.models import PauliLindbladModel
model = PauliLindbladModel.k_local(gate_set, gate_k={"cz_gate": 2, "M": 1, "P": 1})
اعرض عدد المعاملات المجهولة في نموذج الضوضاء لكل بوابة.
{name: len(generators) for name, generators in model.generators.items()}
{'M': 12, 'P': 12, 'cz_gate': 144}
3. ابنِ تجربة التعلّم
اجمع Experiment عبر تركيب مراحل البناء. كل مرحلة تقرأ ما كتبته المراحل السابقة، لذا الترتيب مهم:
from qiskit_noise_learning.experiment_builder import (
BindFragmentDepths,
CompleteSequences,
EvenDepthVanillaPaths,
Experiment,
GenerateInstructionSequences,
IdentifyRelations,
MergeInstructionSequences,
SPAMPaths,
VanillaInstructionSequences,
)
experiment_builder = (
# Add standard vanilla learning paths and instruction sequences, and identify relations
EvenDepthVanillaPaths()
+ VanillaInstructionSequences()
+ IdentifyRelations()
# Add paths for learning SPAM, then generate and merge instruction sequences for measuring them
+ SPAMPaths()
+ GenerateInstructionSequences()
+ MergeInstructionSequences()
# Finalize by completing the instruction sequences and setting experiment depths
+ CompleteSequences()
+ BindFragmentDepths([2, 16, 32, 64])
)
experiment = experiment_builder.run(
Experiment(fidelity_model=model, shots=20, randomizations=50)
)
print(f"Number of paths: {len(experiment.paths)}")
print(f"Number of instruction sequences: {len(experiment.instruction_sequences)}")
Number of paths: 156
Number of instruction sequences: 37
لاحظ رتبة مصفوفة التصميم:
print(f"Design matrix rank: {experiment.design_matrix.rank}")
Design matrix rank: 120
4. ولّد الدوائر
اصرف التجربة (compile) باستخدام ExecutorCircuitGenerator، لتوليد QuantumProgram — دائرة قالب واحدة ذات معاملات لكل عمق جزء (fragment).
from qiskit_noise_learning.circuit_generator import ExecutorCircuitGenerator
circuit_generator = ExecutorCircuitGenerator(gate_set)
quantum_program = circuit_generator.generate(experiment)
print(f"Number of template circuits: {len(quantum_program.items)}")
Number of template circuits: 5
ارسم دائرة قالب لفحصها.
quantum_program.items[0].circuit.draw("mpl", idle_wires=False, fold=False)
5. جهّز المحاكاة المحلية
لتعريف نموذج الضوضاء للمحاكاة، نستخدم المولّدات الموجودة أصلاً في النموذج مع معدلات عشوائية لبناء PauliLindbladMap.
import numpy as np
from qiskit.quantum_info import PauliLindbladMap
rng = np.random.default_rng(1234)
true_maps = {
name: PauliLindbladMap.from_terms(
[
PauliLindbladMap.GeneratorTerm(rate, generator)
for generator, rate in zip(generators, rng.uniform(2e-4, 1.5e-3, len(generators)))
]
)
for name, generators in model.generators.items()
if name != "P"
}
{name: noise_map.num_qubits for name, noise_map in true_maps.items()}
{'M': 156, 'cz_gate': 156}
هذه الخرائط بعرض الجهاز كله، لأن النموذج معبَّر عنه بترقيم كيوبتات backend، لكن المحاكي يريد أن تكون كل خريطة بعرض البوابة التي تُطبَّق عليها، مع مؤشرات باولي تمتد على كيوبتات البوابة بترتيب فيزيائي تصاعدي. قلّص عرضها باستخدام keep_qubits()، الذي يتتبّع (trace out) كل ما هو خارج الحلقة:
noise_dict = {
name: noise_map.keep_qubits(qubit_subset) for name, noise_map in true_maps.items()
}
{name: noise_map.num_qubits for name, noise_map in noise_dict.items()}
{'M': 12, 'cz_gate': 12}
يسمّي المحاكي ضوضاء الطبقة باسم تعليمة الصندوق التي بُنيت منها الطبقة، والتي تعيدها to_instruction() لأي بوابة في مجموعة البوابات. اقرن كل صندوق بخريطته، واستخدم طريقة محاكاة المثبّتات (stabilizer)، وعيّن seed_simulator لجعل البيانات المحاكاة قابلة لإعادة الإنتاج:
from qiskit_aer import AerSimulator
from qiskit_ibm_runtime import Executor
executor = Executor(
mode=AerSimulator(method="stabilizer"),
options={
"simulator": {
"layer_noise_model": [
(gate_set[name].to_instruction(), noise_map)
for name, noise_map in noise_dict.items()
],
"seed_simulator": 42,
}
},
)
executor = Executor(mode=backend)
6. شغّل البرنامج
شغّل البرنامج، ثم نسّق النتائج باستخدام collect()، لإنتاج Fit — الحاوية التي تقرأ منها مراحل التحليل وتكتب إليها.
هذه الخطوة هي نفسها سواء كان المنفّذ (executor) موجهاً إلى محاكي أو إلى جهاز حقيقي.
job = executor.run(quantum_program)
fit = circuit_generator.collect(job.result())
7. حلّل البيانات
ابنِ خط تحليل (pipeline) حول مطابقة النموذج بطريقة المربعات الصغرى غير السالبة.
from qiskit_noise_learning.analysis import (
ComputeObservables, # computes observables from raw data
CurveFitObservables, # performs exponential fitting
LeastSquaresSolve, # solves model with (nonnegative) least squares
)
analyzer = ComputeObservables() + CurveFitObservables() + LeastSquaresSolve()
fit = analyzer.run(fit)
/opt/hostedtoolcache/Python/3.15.1/x64/lib/python3.15/site-packages/qiskit_noise_learning/analysis/model_solve.py:250: UserWarning: 7 of 156 row(s) of the linear system have a non-positive or non-finite uncertainty, so they carry no usable statistical weight. Positions in LinearSystemData.row_labels: 144, 145, 148, 149, 151, 152, 154.
system = LinearSystemData.from_fit(fit)
ارسم متوسطات المراقَبات المقيسة مقابل دوالها الأسية المطابَقة، برسم فرعي لكل زوج CZ، لترى هل التناقصات المطابَقة أسية أصلاً.
fit.plot_qubit_pair_decays(
pairs=cz_pairs,
observable_type="means",
exponential_fit=True,
)
بدّل exponential_fit بـ model_prediction لمقارنة البيانات نفسها بالتناقصات التي تنتج عن المعدلات الخارجة من حل المربعات الصغرى غير السالبة.
fit.plot_qubit_pair_decays(
pairs=cz_pairs,
observable_type="means",
model_prediction=True,
)
