انتقل إلى المحتوى الرئيسي
هذا المشروع في مرحلة تجريبية. وجدت خطأ؟ افتح مشكلة على GitHub. لديك سؤال أو فكرة؟ اسأل في Discussions — نحب سماع ملاحظاتك!
كيف جودة الترجمة في هذه الصفحة؟

مساعد تعلم الضوضاء

Package versions

تم تطوير الكود في هذه الصفحة باستخدام المتطلبات التالية. ننصح باستخدام هذه الإصدارات أو أحدث.

qiskit[all]~=2.5.2
qiskit-ibm-runtime~=0.47.0
samplomatic~=0.21.0

تستخدم تقنيتا تخفيف الأخطاء PEA وPEC مكونًا لتعلم الضوضاء يعتمد على نموذج ضوضاء Pauli-Lindblad، وهو ما يُدار عادةً أثناء التنفيذ بعد إرسال مهمة واحدة أو أكثر عبر qiskit-ibm-runtime دون أي وصول محلي إلى نموذج الضوضاء المُعايَر. غير أنه اعتبارًا من الإصدار v0.27.1 من qiskit-ibm-runtime، جرى إنشاء فئة NoiseLearner ومعها فئة NoiseLearnerOptions للحصول على نتائج تجارب تعلم الضوضاء هذه. يمكن تخزين هذه النتائج محليًا كـ NoiseLearnerResult واستخدامها كمدخل في التجارب اللاحقة. توفر هذه الصفحة نظرة عامة على طريقة استخدامه والخيارات المتاحة.

بالإضافة إلى ذلك، اعتبارًا من الإصدار v0.47.0 من qiskit-ibm-runtime، ثمة فئة جديدة NoiseLearnerV3 متوافقة مع Executor primitive. هذا الإصدار الجديد، الذي يُعدّ أيضًا جزءًا من نموذج التنفيذ الموجَّه، يمنحك القدرة على تحديد الطبقات التي تريد تعلّمها بشكل صريح.

ملاحظة

NoiseLearner يعمل فقط مع EstimatorV2 من جانب الخادم وNoiseLearnerV3 يعمل فقط مع Executor وEstimator الجديد من جانب العميل (الذي تم تقديمه في qiskit-ibm-runtime v0.50.0).

NoiseLearner​

نظرة عامة​

تُجري فئة NoiseLearner تجارب تُوصِّف عمليات الضوضاء بناءً على نموذج ضوضاء Pauli-Lindblad لدائرة كمومية واحدة أو أكثر. تمتلك هذه الفئة طريقة run() تُنفِّذ تجارب التعلم، وتأخذ كمدخل إما قائمة من الدوائر الكمومية أو PUB، وتعيد NoiseLearnerResult يحتوي على قنوات الضوضاء المُتعلَّمة وبيانات تعريفية عن المهام المُرسَلة. في ما يلي مقتطف كود يوضح كيفية استخدام البرنامج المساعد.

# 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, 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()

النتيجة NoiseLearnerResult.data هي قائمة من كائنات LayerError التي تحتوي على نموذج الضوضاء لكل طبقة تشابك منفردة تنتمي إلى الدوائر المستهدفة. يخزِّن كل LayerError معلومات الطبقة في صورة دائرة كمومية ومجموعة من تسميات الكيوبتات، إلى جانب PauliLindbladError لنموذج الضوضاء الذي جرى تعلمه للطبقة المعطاة.

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"
)
Noise learner result contains 2 entries and has the following type:
<class 'qiskit_ibm_runtime.utils.noise_learner_result.NoiseLearnerResult'>

Each element of `NoiseLearnerResult` then contains an object of type:
<class 'qiskit_ibm_runtime.utils.noise_learner_result.LayerError'>

And each of these `LayerError` objects possess data on the generators for the error channel:
['IIIIIIIIIIIIIIIIIIIIIIIIIIX', 'IIIIIIIIIIIIIIIIIIIIIIIIIIY',
'IIIIIIIIIIIIIIIIIIIIIIIIIIZ', 'IIIIIIIIIIIIIIIIIIIIIIIIIXI',
'IIIIIIIIIIIIIIIIIIIIIIIIIXX', 'IIIIIIIIIIIIIIIIIIIIIIIIIXY',
'IIIIIIIIIIIIIIIIIIIIIIIIIXZ', 'IIIIIIIIIIIIIIIIIIIIIIIIIYI',
'IIIIIIIIIIIIIIIIIIIIIIIIIYX', 'IIIIIIIIIIIIIIIIIIIIIIIIIYY',
'IIIIIIIIIIIIIIIIIIIIIIIIIYZ', 'IIIIIIIIIIIIIIIIIIIIIIIIIZI',
'IIIIIIIIIIIIIIIIIIIIIIIIIZX', 'IIIIIIIIIIIIIIIIIIIIIIIIIZY',
'IIIIIIIIIIIIIIIIIIIIIIIIIZZ', 'IIIIIIIIIIIIIIIIIIIIIIIIXII',
'IIIIIIIIIIIIIIIIIIIIIIIIXXI', 'IIIIIIIIIIIIIIIIIIIIIIIIXYI',
'IIIIIIIIIIIIIIIIIIIIIIIIXZI', 'IIIIIIIIIIIIIIIIIIIIIIIIYII',
'IIIIIIIIIIIIIIIIIIIIIIIIYXI', 'IIIIIIIIIIIIIIIIIIIIIIIIYYI',
'IIIIIIIIIIIIIIIIIIIIIIIIYZI', 'IIIIIIIIIIIIIIIIIIIIIIIIZII',
'IIIIIIIIIIIIIIIIIIIIIIIIZXI', 'IIIIIIIIIIIIIIIIIIIIIIIIZYI',
'IIIIIIIIIIIIIIIIIIIIIIIIZZI', 'IIIIIIIIIIIIIIIIIIIIIIIXIII',
'IIIIIIIIIIIIIIIIIIIIIIIXXII', 'IIIIIIIIIIIIIIIIIIIIIIIXYII',
'IIIIIIIIIIIIIIIIIIIIIIIXZII', 'IIIIIIIIIIIIIIIIIIIIIIIYIII',
'IIIIIIIIIIIIIIIIIIIIIIIYXII', 'IIIIIIIIIIIIIIIIIIIIIIIYYII',
'IIIIIIIIIIIIIIIIIIIIIIIYZII', 'IIIIIIIIIIIIIIIIIIIIIIIZIII',
'IIIIIIIIIIIIIIIIIIIIIIIZXII', 'IIIIIIIIIIIIIIIIIIIIIIIZYII',
'IIIIIIIIIIIIIIIIIIIIIIIZZII', 'IIIIIIIIIIIIIIIIIIIIIIXIIII',
'IIIIIIIIIIIIIIIIIIIIIIXXIII', 'IIIIIIIIIIIIIIIIIIIIIIXYIII',
'IIIIIIIIIIIIIIIIIIIIIIXZIII', 'IIIIIIIIIIIIIIIIIIIIIIYIIII',
'IIIIIIIIIIIIIIIIIIIIIIYXIII', 'IIIIIIIIIIIIIIIIIIIIIIYYIII',
'IIIIIIIIIIIIIIIIIIIIIIYZIII', 'IIIIIIIIIIIIIIIIIIIIIIZIIII',
'IIIIIIIIIIIIIIIIIIIIIIZXIII', 'IIIIIIIIIIIIIIIIIIIIIIZYIII',
'IIIIIIIIIIIIIIIIIIIIIIZZIII', 'IIIIIIIIIIIIIIIIIIIIIXIIIII',
'IIIIIIIIIIIIIIIIIIIIIXIIIIX', 'IIIIIIIIIIIIIIIIIIIIIXIIIIY',
'IIIIIIIIIIIIIIIIIIIIIXIIIIZ', 'IIIIIIIIIIIIIIIIIIIIIYIIIII',
'IIIIIIIIIIIIIIIIIIIIIYIIIIX', 'IIIIIIIIIIIIIIIIIIIIIYIIIIY',
'IIIIIIIIIIIIIIIIIIIIIYIIIIZ', 'IIIIIIIIIIIIIIIIIIIIIZIIIII',
'IIIIIIIIIIIIIIIIIIIIIZIIIIX', 'IIIIIIIIIIIIIIIIIIIIIZIIIIY',
'IIIIIIIIIIIIIIIIIIIIIZIIIIZ', 'IIIIIIIIIIIIIIIIIIIIXIIIIII',
'IIIIIIIIIIIIIIIIIIIIXIXIIII', 'IIIIIIIIIIIIIIIIIIIIXIYIIII',
'IIIIIIIIIIIIIIIIIIIIXIZIIII', 'IIIIIIIIIIIIIIIIIIIIYIIIIII',
'IIIIIIIIIIIIIIIIIIIIYIXIIII', 'IIIIIIIIIIIIIIIIIIIIYIYIIII',
'IIIIIIIIIIIIIIIIIIIIYIZIIII', 'IIIIIIIIIIIIIIIIIIIIZIIIIII',
'IIIIIIIIIIIIIIIIIIIIZIXIIII', 'IIIIIIIIIIIIIIIIIIIIZIYIIII', ...]

Along with the error rates:
[0.00037 0.00043 0.00032 ... 0.00031 0.00035 0.00017]

تحتوي الخاصية LayerError.error في نتيجة تعلم الضوضاء على المولِّدات ومعدلات الأخطاء لنموذج Pauli Lindblad المُعايَر، الذي يأخذ الصورة

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

حيث rjr_j هي LayerError.rates وPjP_j هي عوامل باولي المحددة في LayerError.generators.

خيارات تعلم الضوضاء​

يمكنك الاختيار من بين عدة خيارات عند إنشاء كائن NoiseLearner. تُغلَّف هذه الخيارات في فئة qiskit_ibm_runtime.options.NoiseLearnerOptions وتشمل إمكانية تحديد الحد الأقصى للطبقات المُراد تعلمها، وعدد التوزيعات العشوائية، واستراتيجية twirling، من بين أمور أخرى. راجع توثيق NoiseLearnerOptions في مرجع API للحصول على معلومات تفصيلية.

في ما يلي مثال بسيط يوضح كيفية استخدام NoiseLearnerOptions في تجربة 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()

إدخال نموذج الضوضاء إلى primitive​

يمكن أيضًا استخدام نموذج الضوضاء المُتعلَّم من الدائرة الكمومية كمدخل لـ IBM Quantum EstimatorV2 primitive. يمكن تمرير هذا النموذج إلى الـ primitive بعدة طرق مختلفة. توضح الأمثلة الثلاثة التالية كيفية تمرير نموذج الضوضاء إلى خاصية estimator.options مباشرةً، أو باستخدام كائن ResilienceOptionsV2 قبل إنشاء Estimator primitive، أو بتمرير قاموس بالتنسيق المناسب.

# Pass the noise model to the `estimator.options` attribute directly
estimator = EstimatorV2(mode=backend)
estimator.options.resilience.layer_noise_model = noise_model
# 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)
# Specify options by using a dictionary
options_dict = {
"resilience_level": 2,
"resilience": {"layer_noise_model": noise_model},
}

estimator = EstimatorV2(mode=backend, options=options_dict)

بعد تمرير نموذج الضوضاء إلى كائن EstimatorV2، يمكن استخدامه لتشغيل أحمال العمل وتنفيذ تخفيف الأخطاء كالمعتاد.

NoiseLearnerV3​

نظرة عامة​

على غرار NoiseLearner، تُجري فئة NoiseLearnerV3 تجارب تُوصِّف عمليات الضوضاء بناءً على نموذج ضوضاء Pauli-Lindblad لدائرة كمومية واحدة أو أكثر. تأخذ طريقة run() الخاصة بها قائمةً من التعليمات، يجب أن تكون كل منها BoxOp يحمل تعليق twirl التوضيحي ويحتوي على عمليات ISA.

تحتوي نتيجة مهمة NoiseLearnerV3 على قائمة من كائنات NoiseLearnerV3Result، واحدة لكل تعليمة مُدخَلة. يوضح الكود التالي كيفية استخدام البرنامج المساعد.

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')]

نتيجة المهمة هي قائمة من كائنات NoiseLearnerV3Result، واحدة لكل مجموعة تعليمات مُعبَّأة في صندوق. يمتلك NoiseLearnerV3Result طريقة to_pauli_lindblad_map() تعيد كائن PauliLindbladMap، الذي يوفر وسائل لاستخراج المولِّدات ومعدلات الأخطاء وغيرها.

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]

خيارات تعلم الضوضاء​

يدعم NoiseLearnerV3 عدة خيارات، من بينها عدد عمليات العشوائية وعمق أزواج الطبقات، وغير ذلك. وعلى غرار primitives، يمكنك تحديد الخيارات أثناء إنشاء كائن NoiseLearnerV3 أو بعده. يوضح مثال الكود السابق كيفية ضبط خياري shots_per_randomization وnum_randomizations. راجع توثيق NoiseLearnerV3Options في مرجع API للحصول على معلومات تفصيلية.

إدخال نموذج الضوضاء إلى Executor​

يتبع Executor نوايا التصميم المحددة في تعليقات الدائرة (على شكل samplex) والخيارات. InjectNoise هو التعليق المستخدم لتحديد موضع حقن الضوضاء، في حين يحدد وسيط samplex المسمّى pauli_lindblad_maps خريطة الضوضاء المراد استخدامها.

تمر الدائرة في المثال السابق عبر مدير تمريرات التعبئة في صناديق (boxing pass manager)، الذي يجمّع التعليمات في صناديق ذات تعليقات توضيحية. يُضاف الكود ذو الصلة هنا لتسهيل الفهم.

  • يحدد inject_noise_targets=”gates” إضافة تعليقات InjectNoise التوضيحية إلى الصناديق التي تحتوي على بوابات التشابك (entanglers).
  • يحدد inject_noise_strategy="uniform_modification" تعيين نفس ref وmodifier_ref لجميع الصناديق المكافئة التي تحمل تعليقات InjectNoise التوضيحية.
    • InjectNoise.ref هو معرّف فريد يُستخدم لتعيين نموذج ضوضاء لذلك الصندوق.
    • يسمح InjectNoise.modifier_ref بضبط مقياس نموذج الضوضاء المُعيَّن لصندوق بواسطة عوامل ضرب (multiplicative factors).
boxing_pm = generate_boxing_pass_manager(
enable_gates=True,
enable_measures=False,
inject_noise_targets="gates", # no measurement mitigation
inject_noise_strategy="uniform_modification",
)

تحتوي الدائرة من المثال السابق على ثلاثة صناديق، اثنان منها يحملان تعليقات InjectNoise بسمات ref مختلفة (لأنهما غير متكافئين).

# 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')]

يجب تحويل نتيجة مهمة NoiseLearnerV3 إلى قاموس قبل تمريرها إلى Executor. مفاتيح هذا القاموس هي سمات InjectNoise.ref والقيم هي خرائط الضوضاء المقابلة. يخبر هذا التعيين Executor بنماذج الضوضاء التي يجب حقنها وأين.

يوضح الكود التالي كيفية أخذ الدائرة ونتيجة NoiseLearnerV3 من المثال السابق وتمريرهما إلى Executor، الذي سيُنشئ متغيرات الدائرة مع نماذج الضوضاء المُحقَنة وينفذها على العتاد الكمومي.

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)

استخدام NoiseLearnerV3 مع Estimator من جانب العميل​

يوضح الكود التالي كيفية استخدام البرنامج المساعد مع Estimator الجديد من جانب العميل

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()

الخطوات التالية​