انتقل إلى المحتوى الرئيسي

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

Package versions

The code on this page was developed using the following requirements. We recommend using these versions or newer.

qiskit[all]~=2.4.1
qiskit-ibm-runtime~=0.47.0
samplomatic~=0.18.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.

NoiseLearner

نظرة عامة

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

# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime samplomatic
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{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',
'IIIIIIIIIIIIIIIIIIIIIIIIXIX', 'IIIIIIIIIIIIIIIIIIIIIIIIXIY',
'IIIIIIIIIIIIIIIIIIIIIIIIXIZ', 'IIIIIIIIIIIIIIIIIIIIIIIIYII',
'IIIIIIIIIIIIIIIIIIIIIIIIYIX', 'IIIIIIIIIIIIIIIIIIIIIIIIYIY',
'IIIIIIIIIIIIIIIIIIIIIIIIYIZ', 'IIIIIIIIIIIIIIIIIIIIIIIIZII',
'IIIIIIIIIIIIIIIIIIIIIIIIZIX', 'IIIIIIIIIIIIIIIIIIIIIIIIZIY',
'IIIIIIIIIIIIIIIIIIIIIIIIZIZ', 'IIIIIIIIIIIIIIIIIIIIIIIXIII',
'IIIIIIIIIIIIIIIIIIIIIIIYIII', 'IIIIIIIIIIIIIIIIIIIIIIIZIII',
'IIIIIIIIIIIIIIIIIIIIIIXIIII', 'IIIIIIIIIIIIIIIIIIIIIIXXIII',
'IIIIIIIIIIIIIIIIIIIIIIXYIII', 'IIIIIIIIIIIIIIIIIIIIIIXZIII',
'IIIIIIIIIIIIIIIIIIIIIIYIIII', 'IIIIIIIIIIIIIIIIIIIIIIYXIII',
'IIIIIIIIIIIIIIIIIIIIIIYYIII', 'IIIIIIIIIIIIIIIIIIIIIIYZIII',
'IIIIIIIIIIIIIIIIIIIIIIZIIII', 'IIIIIIIIIIIIIIIIIIIIIIZXIII',
'IIIIIIIIIIIIIIIIIIIIIIZYIII', 'IIIIIIIIIIIIIIIIIIIIIIZZIII',
'IIIIIIIIIIIIIIIIIIIIIXIIIII', 'IIIIIIIIIIIIIIIIIIIIIXXIIII',
'IIIIIIIIIIIIIIIIIIIIIXYIIII', 'IIIIIIIIIIIIIIIIIIIIIXZIIII',
'IIIIIIIIIIIIIIIIIIIIIYIIIII', 'IIIIIIIIIIIIIIIIIIIIIYXIIII',
'IIIIIIIIIIIIIIIIIIIIIYYIIII', 'IIIIIIIIIIIIIIIIIIIIIYZIIII',
'IIIIIIIIIIIIIIIIIIIIIZIIIII', 'IIIIIIIIIIIIIIIIIIIIIZXIIII',
'IIIIIIIIIIIIIIIIIIIIIZYIIII', 'IIIIIIIIIIIIIIIIIIIIIZZIIII',
'IIIIIIIIIIIIIIIIIIIIXIIIIII', 'IIIIIIIIIIIIIIIIIIIIXXIIIII',
'IIIIIIIIIIIIIIIIIIIIXYIIIII', 'IIIIIIIIIIIIIIIIIIIIXZIIIII',
'IIIIIIIIIIIIIIIIIIIIYIIIIII', 'IIIIIIIIIIIIIIIIIIIIYXIIIII',
'IIIIIIIIIIIIIIIIIIIIYYIIIII', 'IIIIIIIIIIIIIIIIIIIIYZIIIII',
'IIIIIIIIIIIIIIIIIIIIZIIIIII', 'IIIIIIIIIIIIIIIIIIIIZXIIIII',
'IIIIIIIIIIIIIIIIIIIIZYIIIII', 'IIIIIIIIIIIIIIIIIIIIZZIIIII',
'IIIIIIIIIIIIIIIIIIIXIIIIIII', 'IIIIIIIIIIIIIIIIIIIXXIIIIII',
'IIIIIIIIIIIIIIIIIIIXYIIIIII', 'IIIIIIIIIIIIIIIIIIIXZIIIIII',
'IIIIIIIIIIIIIIIIIIIYIIIIIII', 'IIIIIIIIIIIIIIIIIIIYXIIIIII',
'IIIIIIIIIIIIIIIIIIIYYIIIIII', 'IIIIIIIIIIIIIIIIIIIYZIIIIII', ...]

Along with the error rates:
[5.9e-04 5.3e-04 5.7e-04 ... 0.0e+00 1.0e-05 0.0e+00]

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

Λ(ρ)=expjrj(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

يمكن أيضًا استخدام نموذج الضوضاء المُتعلَّم من الدائرة الكمومية كمدخل لـ primitive الخاص بـ EstimatorV2 المُنفَّذ في Qiskit Runtime. يمكن تمرير هذا النموذج إلى الـ 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='r789B', modifier_ref='', site='before')]

نتيجة المهمة هي قائمة من كائنات 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 (truncated to 3): \n{noise_map.generators()[:3]}\n"
)
with numpy.printoptions(threshold=20):
print(
f"Along with the error rates (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_0, Y_0, Z_0]>

Along with the error rates (truncated to 3):
[0.00026 0.00032 0.00023]

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

يدعم 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 إلى الصناديق التي تحتوي على بوابات تشابك.
  • inject_noise_strategy="uniform_modification" يحدد تعيين نفس ref وmodifier_ref لجميع الصناديق المتكافئة التي تحمل تعليقات InjectNoise.
    • InjectNoise.ref هو معرِّف فريد يُستخدَم لتعيين نموذج ضوضاء لذلك الصندوق.
    • InjectNoise.modifier_ref يتيح تحجيم نموذج الضوضاء المُعيَّن لصندوق ما بعوامل ضرب.
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='r789B', modifier_ref='r789B', site='before')]

Annotations of box #1: [Twirl(group='pauli', dressing='left', decomposition='rzsx'), InjectNoise(ref='r054B', modifier_ref='r054B', site='before')]

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)

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