Skip to main content
IBM Quantum Platform

소음 모델 구축

  • 이 페이지의 코드는 다음 요구 사항을 사용하여 개발되었습니다. 다음 버전 이상을 사용하는 것이 좋습니다.

    qiskit[all]~=2.5.2
    qiskit-ibm-runtime~=0.47.0
    qiskit-aer~=0.17
    

이 페이지는 키스킷 Aer noise 모듈을 사용하여 오류가 있는 양자 회로를 시뮬레이션하기 위한 노이즈 모델을 구축하는 방법을 설명합니다. 이는 노이즈가 많은 양자 프로세서를 에뮬레이션하고 양자 알고리즘 실행에 대한 노이즈의 영향을 연구하는 데 유용합니다.

import numpy as np
from qiskit import QuantumCircuit
from qiskit.quantum_info import Kraus, SuperOp
from qiskit.visualization import plot_histogram
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_aer import AerSimulator

# Import from Qiskit Aer noise module
from qiskit_aer.noise import (
    NoiseModel,
    QuantumError,
    ReadoutError,
    depolarizing_error,
    pauli_error,
    thermal_relaxation_error,
)

Qiskit Aer noise 모듈

키스킷 에어 noise 모듈에는 시뮬레이션을 위한 맞춤형 노이즈 모델을 구축할 수 있는 Python 클래스가 포함되어 있습니다. 세 가지 주요 클래스가 있습니다:

  1. 노이즈 시뮬레이션에 사용되는 노이즈 모델을 저장하는 NoiseModel 클래스입니다.

  2. CPTP 게이트 오류를 설명하는 QuantumError 클래스입니다. 이를 적용할 수 있습니다:

    • 게이트 또는 재설정 지침 후
    • 측정 전 지침.
  3. 일반적인 판독 오류를 설명하는 ReadoutError 클래스입니다.


백엔드에서 노이즈 모델 초기화

물리적 백엔드의 최신 보정 데이터를 기반으로 매개변수를 설정하여 노이즈 모델을 초기화할 수 있습니다.

Note

이 예제에서는 의 모의 FakeSherbrooke``qiskit_ibm_runtime 백엔드를 사용하지만, Qiskit과 호환되는 실제 또는 모의 백엔드라면 어떤 것이든 사용해 볼 수 있습니다.

from qiskit_ibm_runtime.fake_provider import FakeSherbrooke

backend = FakeSherbrooke()
noise_model = NoiseModel.from_backend(backend)

이렇게 하면 해당 백엔드를 사용할 때 발생할 수 있는 오류를 대략적으로 추정할 수 있는 노이즈 모델이 생성됩니다. 노이즈 모델의 파라미터를 더 자세히 제어하려면 이 페이지의 나머지 부분에서 설명하는 대로 자체 노이즈 모델을 만들어야 합니다.


양자 오류

객체를 QuantumError 직접 다루기보다는, 특정 유형의 매개변수화된 양자 오류를 자동으로 생성하는 많은 보조 함수들이 존재합니다. 이들은 noise 모듈에 포함되어 있으며 양자 컴퓨팅 연구에서 사용되는 다양한 일반적인 오류 유형에 대한 함수를 포함합니다. 함수명과 해당 함수가 반환하는 오류 유형은 다음과 같습니다:

표준 오류 함수
세부사항
kraus_error크라우스 행렬의 목록으로 주어진 일반적인 n-쿼비트 CPTP 오류 채널 [K0,...][K_0, ...].
mixed_unitary_error단일 행렬과 확률의 목록으로 주어진 n-쿼비트 혼합 단일 오차 [(U0,p0),...][(U_0, p_0),...].
coherent_unitary_error단일 유니타리 행렬로 주어진 n-큐비트 코히어런트 유니타리 오류 UU.
pauli_error폴리와 확률의 목록으로 주어진 n-큐비트 폴리 오류 채널(혼합 단일) [(P0,p0),...][(P_0, p_0),...]
depolarizing_error탈분극 확률로 파라미터화된 n-큐비트 탈분극 오류 채널 pp.
reset_error확률 p0,p1p_0, p_1 에 의해 매개변수화된 상태로의 1\vert1\rangle 재설정 오류가 있는 0\vert0\rangle 단일 큐비트 재설정.
thermal_relaxation_error이완 시간 상수 T1T_1, T2T_2, 게이트 시간 tt, 여기 상태 열 인구 p1p_1 로 파라미터화된 단일 큐비트 열 이완 채널입니다.
phase_amplitude_damping_error진폭 감쇠 파라미터 λ\lambda, 위상 감쇠 파라미터 γ\gamma, 여기 상태 열 인구 p1p_1 로 주어진 단일 큐비트 일반화된 결합 위상 및 진폭 감쇠 오류 채널입니다.
amplitude_damping_error진폭 감쇠 파라미터 λ\lambda 와 여기 상태 열 인구 p1p_1 로 주어진 단일 큐비트 일반화 진폭 감쇠 오류 채널입니다.
phase_damping_error위상 감쇠 매개변수 로 주어지는 단일 큐비트 γ\gamma 위상 감쇠 오류 채널.

양자 오류를 합산하다

QuantumError 인스턴스를 구성, 텐서 곱, 텐서 확장(역순 텐서 곱)을 사용하여 결합하여 새로운 QuantumErrors 으로 생성할 수 있습니다:

  • 구성: E(ρ)=E2(E1(ρ))\cal{E}(\rho)=\cal{E_2}(\cal{E_1}(\rho)) as error = error1.compose(error2)
  • 텐서곱: E(ρ)=(E1E2)(ρ)\cal{E}(\rho) =(\cal{E_1}\otimes\cal{E_2})(\rho) as error = error1.tensor(error2)
  • 제품 확장: E(ρ)=(E2E1)(ρ)\cal{E}(\rho) =(\cal{E_2}\otimes\cal{E_1})(\rho) as error = error1.expand(error2)

5% 단일 큐비트 비트 플립 오류를 구성합니다:

# Construct a 1-qubit bit-flip and phase-flip errors
p_error = 0.05
bit_flip = pauli_error([("X", p_error), ("I", 1 - p_error)])
phase_flip = pauli_error([("Z", p_error), ("I", 1 - p_error)])
print(bit_flip)
print(phase_flip)

Output:

QuantumError on 1 qubits. Noise circuits:
  P(0) = 0.05, Circuit = 
   ┌───┐
q: ┤ X ├
   └───┘
  P(1) = 0.95, Circuit = 
   ┌───┐
q: ┤ I ├
   └───┘
QuantumError on 1 qubits. Noise circuits:
  P(0) = 0.05, Circuit = 
   ┌───┐
q: ┤ Z ├
   └───┘
  P(1) = 0.95, Circuit = 
   ┌───┐
q: ┤ I ├
   └───┘
# Compose two bit-flip and phase-flip errors
bitphase_flip = bit_flip.compose(phase_flip)
print(bitphase_flip)

Output:

QuantumError on 1 qubits. Noise circuits:
  P(0) = 0.0025000000000000005, Circuit = 
   ┌───┐┌───┐
q: ┤ X ├┤ Z ├
   └───┘└───┘
  P(1) = 0.0475, Circuit = 
   ┌───┐┌───┐
q: ┤ X ├┤ I ├
   └───┘└───┘
  P(2) = 0.0475, Circuit = 
   ┌───┐┌───┐
q: ┤ I ├┤ Z ├
   └───┘└───┘
  P(3) = 0.9025, Circuit = 
   ┌───┐┌───┐
q: ┤ I ├┤ I ├
   └───┘└───┘
# Tensor product two bit-flip and phase-flip errors with
# bit-flip on qubit-0, phase-flip on qubit-1
error2 = phase_flip.tensor(bit_flip)
print(error2)

Output:

QuantumError on 2 qubits. Noise circuits:
  P(0) = 0.0025000000000000005, Circuit = 
     ┌───┐
q_0: ┤ X ├
     ├───┤
q_1: ┤ Z ├
     └───┘
  P(1) = 0.0475, Circuit = 
     ┌───┐
q_0: ┤ I ├
     ├───┤
q_1: ┤ Z ├
     └───┘
  P(2) = 0.0475, Circuit = 
     ┌───┐
q_0: ┤ X ├
     ├───┤
q_1: ┤ I ├
     └───┘
  P(3) = 0.9025, Circuit = 
     ┌───┐
q_0: ┤ I ├
     ├───┤
q_1: ┤ I ├
     └───┘

QuantumChannel 연산자 간 변환

또한 키스킷 에어의 QuantumError 객체와 키스킷의 QuantumChannel 객체 사이를 오가며 변환할 수 있습니다.

# Convert to Kraus operator
bit_flip_kraus = Kraus(bit_flip)
print(bit_flip_kraus)

Output:

Kraus([[[-9.74679434e-01+0.j,  0.00000000e+00+0.j],
        [ 0.00000000e+00+0.j, -9.74679434e-01+0.j]],

       [[ 0.00000000e+00+0.j,  2.23606798e-01+0.j],
        [ 2.23606798e-01+0.j, -4.96506831e-17+0.j]]],
      input_dims=(2,), output_dims=(2,))
# Convert to Superoperator
phase_flip_sop = SuperOp(phase_flip)
print(phase_flip_sop)

Output:

SuperOp([[1. +0.j, 0. +0.j, 0. +0.j, 0. +0.j],
         [0. +0.j, 0.9+0.j, 0. +0.j, 0. +0.j],
         [0. +0.j, 0. +0.j, 0.9+0.j, 0. +0.j],
         [0. +0.j, 0. +0.j, 0. +0.j, 1. +0.j]],
        input_dims=(2,), output_dims=(2,))
# Convert back to a quantum error
print(QuantumError(bit_flip_kraus))

# Check conversion is equivalent to original error
QuantumError(bit_flip_kraus) == bit_flip

Output:

QuantumError on 1 qubits. Noise circuits:
  P(0) = 1.0, Circuit = 
   ┌───────┐
q: ┤ kraus ├
   └───────┘
True

읽기 오류

고전적 판독 오류는 할당 확률 벡터 목록으로 P(AB)P(A|B) 지정됩니다:

  • AA기록된 클래식 비트 값입니다
  • BB 는 측정에서 반환된 실제 비트 값입니다

예를 들어, 1 큐비트의 경우: P(AB)=[P(A0),P(A1)] P(A|B) = [P(A|0), P(A|1)].

# Measurement misassignment probabilities
p0given1 = 0.1
p1given0 = 0.05

ReadoutError([[1 - p1given0, p1given0], [p0given1, 1 - p0given1]])

Output:

ReadoutError([[0.95 0.05]
 [0.1  0.9 ]])

양자 오류와 마찬가지로 compose, tensorexpand 를 사용하여 판독 오류를 결합할 수도 있습니다.


노이즈 모델에 오류를 추가하다

노이즈 모델에 양자 오류를 추가할 때는 양자 오류가 작용하는 명령어 유형과 이를 적용할 큐비트를 지정해야 합니다. 양자 오류에는 두 가지 경우가 있습니다:

  1. 모든 큐비트 양자 오류
  2. 특정 큐비트 양자 오류

1. 모든 큐비트 양자 오류

이는 명령어가 어떤 큐비트에 작용하는지에 관계없이 모든 명령어 발생에 동일한 오류를 적용합니다.

noise_model.add_all_qubit_quantum_error(error, instructions) 로 추가됩니다:

# Create an empty noise model
noise_model = NoiseModel()

# Add depolarizing error to all single qubit u1, u2, u3 gates
error = depolarizing_error(0.05, 1)
noise_model.add_all_qubit_quantum_error(error, ["u1", "u2", "u3"])

# Print noise model info
print(noise_model)

Output:

NoiseModel:
  Basis gates: ['cx', 'id', 'rz', 'sx', 'u1', 'u2', 'u3']
  Instructions with noise: ['u3', 'u1', 'u2']
  All-qubits errors: ['u1', 'u2', 'u3']

2. 특정 큐비트 양자 오류

이렇게 하면 지정된 큐비트 목록에 작용하는 모든 명령어 발생에 오류가 적용됩니다. 예를 들어, 2큐비트 게이트의 경우 큐비트 [0, 1에] 적용되는 오류는 큐비트 [1, 0에] 적용되는 오류와 다르므로 큐비트의 순서가 중요하다는 점에 유의하세요.

noise_model.add_quantum_error(error, instructions, qubits) 로 추가됩니다:

# Create an empty noise model
noise_model = NoiseModel()

# Add depolarizing error to all single qubit u1, u2, u3 gates on qubit 0 only
error = depolarizing_error(0.05, 1)
noise_model.add_quantum_error(error, ["u1", "u2", "u3"], [0])

# Print noise model info
print(noise_model)

Output:

NoiseModel:
  Basis gates: ['cx', 'id', 'rz', 'sx', 'u1', 'u2', 'u3']
  Instructions with noise: ['u3', 'u1', 'u2']
  Qubits with noise: [0]
  Specific qubit errors: [('u1', (0,)), ('u2', (0,)), ('u3', (0,))]

비국소 큐비트 양자 오류에 관한 참고 사항

NoiseModel 비국소 큐비트 양자 오류의 추가를 지원하지 않습니다. 이는. NoiseModel외부에서 처리해야 합니다. 즉, 특정 조건 하에서 회로에 양자 오류를 삽입해야 한다면, 직접 트랜스파일러 패스(TransformationPass)를 작성하여 시뮬레이터를 실행하기 직전에 해당 패스를 실행해야 합니다.

노이즈 모델을 사용하여 노이즈 시뮬레이션을 실행합니다

AerSimulator(noise_model=noise_model) 명령은 주어진 노이즈 모델에 맞게 구성된 시뮬레이터를 반환합니다. 시뮬레이터의 노이즈 모델을 설정하는 것 외에도 노이즈 모델의 게이트에 따라 시뮬레이터의 기본 게이트도 오버라이드합니다.


소음 모델 예시

이제 소음 모델의 몇 가지 예를 들어 보겠습니다. 시연을 위해 우리는 n-큐비트 GHZ 상태를 생성하는 간단한 테스트 회로를 사용합니다:

# System Specification
n_qubits = 4
circ = QuantumCircuit(n_qubits)

# Test Circuit
circ.h(0)
for qubit in range(n_qubits - 1):
    circ.cx(qubit, qubit + 1)
circ.measure_all()
print(circ)

Output:

        ┌───┐                ░ ┌─┐         
   q_0: ┤ H ├──■─────────────░─┤M├─────────
        └───┘┌─┴─┐           ░ └╥┘┌─┐      
   q_1: ─────┤ X ├──■────────░──╫─┤M├──────
             └───┘┌─┴─┐      ░  ║ └╥┘┌─┐   
   q_2: ──────────┤ X ├──■───░──╫──╫─┤M├───
                  └───┘┌─┴─┐ ░  ║  ║ └╥┘┌─┐
   q_3: ───────────────┤ X ├─░──╫──╫──╫─┤M├
                       └───┘ ░  ║  ║  ║ └╥┘
meas: 4/════════════════════════╩══╩══╩══╩═
                                0  1  2  3 

이상적인 시뮬레이션

# Ideal simulator and execution
sim_ideal = AerSimulator()
result_ideal = sim_ideal.run(circ).result()
plot_histogram(result_ideal.get_counts(0))

Output:

Output of the previous code cell

잡음 예시 1: 기본 비트 플립 오류 잡음 모델

양자 정보 이론 연구에서 흔히 볼 수 있는 간단한 장난감 잡음 모델을 예로 들어 보겠습니다:

  • 단일 큐비트 게이트를 적용할 때, 큐비트의 상태를 확률로 뒤집습니다 p_gate1.
  • 2큐비트 게이트를 적용할 때는 각 큐비트에 단일 큐비트 오류를 적용합니다.
  • 큐비트를 재설정할 때 0이 아닌 1로 재설정할 확률 p_reset.
  • 큐비트를 측정할 때 큐비트의 상태를 확률로 뒤집습니다 p_meas.
# Example error probabilities
p_reset = 0.03
p_meas = 0.1
p_gate1 = 0.05

# QuantumError objects
error_reset = pauli_error([("X", p_reset), ("I", 1 - p_reset)])
error_meas = pauli_error([("X", p_meas), ("I", 1 - p_meas)])
error_gate1 = pauli_error([("X", p_gate1), ("I", 1 - p_gate1)])
error_gate2 = error_gate1.tensor(error_gate1)

# Add errors to noise model
noise_bit_flip = NoiseModel()
noise_bit_flip.add_all_qubit_quantum_error(error_reset, "reset")
noise_bit_flip.add_all_qubit_quantum_error(error_meas, "measure")
noise_bit_flip.add_all_qubit_quantum_error(error_gate1, ["u1", "u2", "u3"])
noise_bit_flip.add_all_qubit_quantum_error(error_gate2, ["cx"])

print(noise_bit_flip)

Output:

NoiseModel:
  Basis gates: ['cx', 'id', 'rz', 'sx', 'u1', 'u2', 'u3']
  Instructions with noise: ['u1', 'u2', 'cx', 'measure', 'reset', 'u3']
  All-qubits errors: ['reset', 'measure', 'u1', 'u2', 'u3', 'cx']

잡음이 있는 시뮬레이션을 실행하십시오

# Create noisy simulator backend
sim_noise = AerSimulator(noise_model=noise_bit_flip)

# Transpile circuit for noisy basis gates
passmanager = generate_preset_pass_manager(
    optimization_level=3, backend=sim_noise
)
circ_tnoise = passmanager.run(circ)

# Run and get counts
result_bit_flip = sim_noise.run(circ_tnoise).result()
counts_bit_flip = result_bit_flip.get_counts(0)

# Plot noisy output
plot_histogram(counts_bit_flip)

Output:

Output of the previous code cell

예시 2: T1/T2 열적 이완

이제 큐비트 환경에서 열 완화를 기반으로 하는 보다 현실적인 오류 모델을 고려해 보겠습니다:

  • 각 큐비트는 열 완화 시간 상수 T1T_1 와 디페이징 시간 상수 T2T_2 로 파라미터화됩니다.
  • T22T1T_2 \le 2 T_1 이 있어야 합니다.
  • 명령어의 오류율은 게이트 시간과 큐비트 T1T_1, T2T_2 값에 의해 결정됩니다.
# T1 and T2 values for qubits 0-3
T1s = np.random.normal(
    50e3, 10e3, 4
)  # Sampled from normal distribution mean 50 microsec
T2s = np.random.normal(
    70e3, 10e3, 4
)  # Sampled from normal distribution mean 50 microsec

# Truncate random T2s <= T1s
T2s = np.array([min(T2s[j], 2 * T1s[j]) for j in range(4)])

# Instruction times (in nanoseconds)
time_u1 = 0  # virtual gate
time_u2 = 50  # (single X90 pulse)
time_u3 = 100  # (two X90 pulses)
time_cx = 300
time_reset = 1000  # 1 microsecond
time_measure = 1000  # 1 microsecond

# QuantumError objects
errors_reset = [
    thermal_relaxation_error(t1, t2, time_reset) for t1, t2 in zip(T1s, T2s)
]
errors_measure = [
    thermal_relaxation_error(t1, t2, time_measure) for t1, t2 in zip(T1s, T2s)
]
errors_u1 = [
    thermal_relaxation_error(t1, t2, time_u1) for t1, t2 in zip(T1s, T2s)
]
errors_u2 = [
    thermal_relaxation_error(t1, t2, time_u2) for t1, t2 in zip(T1s, T2s)
]
errors_u3 = [
    thermal_relaxation_error(t1, t2, time_u3) for t1, t2 in zip(T1s, T2s)
]
errors_cx = [
    [
        thermal_relaxation_error(t1a, t2a, time_cx).expand(
            thermal_relaxation_error(t1b, t2b, time_cx)
        )
        for t1a, t2a in zip(T1s, T2s)
    ]
    for t1b, t2b in zip(T1s, T2s)
]

# Add errors to noise model
noise_thermal = NoiseModel()
for j in range(4):
    noise_thermal.add_quantum_error(errors_reset[j], "reset", [j])
    noise_thermal.add_quantum_error(errors_measure[j], "measure", [j])
    noise_thermal.add_quantum_error(errors_u1[j], "u1", [j])
    noise_thermal.add_quantum_error(errors_u2[j], "u2", [j])
    noise_thermal.add_quantum_error(errors_u3[j], "u3", [j])
    for k in range(4):
        noise_thermal.add_quantum_error(errors_cx[j][k], "cx", [j, k])

print(noise_thermal)

Output:

NoiseModel:
  Basis gates: ['cx', 'id', 'rz', 'sx', 'u2', 'u3']
  Instructions with noise: ['u2', 'cx', 'measure', 'reset', 'u3']
  Qubits with noise: [0, 1, 2, 3]
  Specific qubit errors: [('reset', (0,)), ('reset', (1,)), ('reset', (2,)), ('reset', (3,)), ('measure', (0,)), ('measure', (1,)), ('measure', (2,)), ('measure', (3,)), ('u2', (0,)), ('u2', (1,)), ('u2', (2,)), ('u2', (3,)), ('u3', (0,)), ('u3', (1,)), ('u3', (2,)), ('u3', (3,)), ('cx', (0, 0)), ('cx', (0, 1)), ('cx', (0, 2)), ('cx', (0, 3)), ('cx', (1, 0)), ('cx', (1, 1)), ('cx', (1, 2)), ('cx', (1, 3)), ('cx', (2, 0)), ('cx', (2, 1)), ('cx', (2, 2)), ('cx', (2, 3)), ('cx', (3, 0)), ('cx', (3, 1)), ('cx', (3, 2)), ('cx', (3, 3))]

잡음이 있는 시뮬레이션을 실행하십시오

# Run the noisy simulation
sim_thermal = AerSimulator(noise_model=noise_thermal)

# Transpile circuit for noisy basis gates
passmanager = generate_preset_pass_manager(
    optimization_level=3, backend=sim_thermal
)
circ_tthermal = passmanager.run(circ)

# Run and get counts
result_thermal = sim_thermal.run(circ_tthermal).result()
counts_thermal = result_thermal.get_counts(0)

# Plot noisy output
plot_histogram(counts_thermal)

Output:

Output of the previous code cell

다음 단계

권장사항
이 페이지가 도움이 되었습니까?
GitHub에서 버그, 오타를 보고하거나 컨텐츠를 요청하십시오.