メインコンテンツへスキップ

ノイズ学習ヘルパー

Package versions

このページのコードは、以下の要件を使用して開発されました。 これらのバージョン以降を使用することを推奨します。

qiskit[all]~=2.4.1
qiskit-ibm-runtime~=0.47.0
samplomatic~=0.18.0

エラー緩和技術である PEAPEC はいずれも、Pauli-Lindbladノイズモデルに基づくノイズ学習コンポーネントを使用しています。このコンポーネントは通常、qiskit-ibm-runtime を通じて1つ以上のジョブを送信した後の実行中に管理され、フィッティングされたノイズモデルへのローカルアクセスはありません。しかし、qiskit-ibm-runtime v0.27.1 以降、NoiseLearner クラスと関連する NoiseLearnerOptions クラスが作成され、これらのノイズ学習実験の結果を取得できるようになりました。これらの結果は NoiseLearnerResult としてローカルに保存し、後続の実験の入力として使用することができます。このページでは、その使用方法と利用可能なオプションの概要を説明します。

また、qiskit-ibm-runtime v0.47.0 以降、Executor プリミティブと互換性のある新しい NoiseLearnerV3 クラスが追加されました。この新バージョンは指向性実行モデルの一部でもあり、学習するレイヤーを明示的に指定できます。

備考

NoiseLearner は EstimatorV2 とのみ動作し、NoiseLearnerV3 は Executor とのみ動作します。

NoiseLearner

概要

NoiseLearner クラスは、1つ(または複数の)回路に対して、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"
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',
'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_jLayerError.ratesPjP_jLayerError.generators に指定された Pauli 演算子です。

ノイズ学習オプション

NoiseLearner オブジェクトをインスタンス化する際に指定できるオプションがいくつかあります。これらのオプションは qiskit_ibm_runtime.options.NoiseLearnerOptions クラスにカプセル化されており、学習する最大層数、ランダム化の回数、twirling 戦略などを指定する機能が含まれています。詳細については、NoiseLearnerOptions の API ドキュメントを参照してください。

以下は、NoiseLearner 実験で NoiseLearnerOptions を使用する簡単な例です。

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

プリミティブへのノイズモデルの入力

回路で学習したノイズモデルは、Qiskit Runtime に実装されている EstimatorV2 プリミティブへの入力としても使用できます。このノイズモデルは、いくつかの異なる方法でプリミティブに渡すことができます。次の3つの例では、ノイズモデルを estimator.options 属性に直接渡す方法、Estimator プリミティブをインスタンス化する前に ResilienceOptionsV2 オブジェクトを使用して渡す方法、および適切にフォーマットされた辞書を渡す方法を示します。

# 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 クラスは1つ以上の回路に対して、Pauli-Lindbladノイズモデルに基づいてノイズプロセスを特徴付ける実験を実行します。その run() メソッドは命令のリストを入力として受け取り、各命令は ISA 操作を含む、twirl アノテーション付きの BoxOp でなければなりません。

NoiseLearnerV3 ジョブの結果には、入力命令ごとに1つずつ、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 オブジェクトのリストであり、入力ボックス化命令セットごとに1つ含まれます。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_0, Y_0, Z_0]>

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

ノイズ学習オプション

NoiseLearnerV3 はランダム化の回数やレイヤーペアの深さなど、いくつかのオプションをサポートしています。プリミティブと同様に、NoiseLearnerV3 オブジェクトのインスタンス化時または後にオプションを指定できます。前述のコード例では、shots_per_randomizationnum_randomizations オプションの設定方法を示しました。詳細については、NoiseLearnerV3Options の API ドキュメントを参照してください。

Executor へのノイズモデルの入力

Executor は回路アノテーション(samplex の形式)とオプションで指定された設計意図に従います。InjectNoise はノイズを注入する場所を指定するアノテーションであり、pauli_lindblad_maps samplex 引数はどのノイズマップを使用するかを指定します。

前の例の回路は boxing パスマネージャーを通り、命令がアノテーション付きのボックスにグループ化されます。理解しやすくするため、関連するコードをここに示します。

  • inject_noise_targets="gates" は、エンタングラーを含むボックスに InjectNoise アノテーションを追加するよう指定します。
  • inject_noise_strategy="uniform_modification" は、同じ refmodifier_refInjectNoise アノテーション付きの同等なすべてのボックスに割り当てるよう指定します。
    • 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",
)

前の例の回路には3つのボックスが含まれており、そのうち2つには異なる ref 属性を持つ InjectNoise アノテーションが付いています(同等でないため)。

# 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 に渡す方法を示します。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)

次のステップ

推奨事項