Skip to main content
IBM Quantum Platform

NEAT를 사용하여 작업 디버깅하기

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

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

Neat 클래스를 사용하여 Estimator 워크로드에 미치는 노이즈의 영향을 분석할 수 있습니다. 구문 검증을 위해서는 로컬 테스트 모드를 사용하십시오.


Neat 클래스 사용법

리소스 집약적인 워크로드를 하드웨어에서 실행하기 전에, IBM Quantum 의 Compute NEAT(Noisy Estimator Analyzer Tool) 클래스를 사용하여 에스티메이터 워크로드가 올바르게 설정되었는지, 정확한 결과를 반환할 가능성이 높은지, 지정된 문제에 가장 적합한 옵션을 사용하고 있는지 등을 확인할 수 있습니다.

Neat 구조와 깊이를 유지하면서 효율적인 시뮬레이션을 위해 입력 회로를 간소화합니다. 클리포드 회로는 비슷한 수준의 노이즈가 발생하며 관심 있는 원래 회로를 연구하는 데 좋은 대용품입니다.

먼저, 관련 패키지를 가져오고 IBM Quantum 컴퓨트 서비스에 인증합니다.

환경 준비

import numpy as np
import random

from qiskit.circuit import QuantumCircuit
from qiskit.transpiler import generate_preset_pass_manager
from qiskit.quantum_info import SparsePauliOp

from qiskit_ibm_runtime import QiskitRuntimeService, EstimatorV2 as Estimator
from qiskit_ibm_runtime.debug_tools import Neat

from qiskit_aer.noise import NoiseModel, depolarizing_error
# Choose the least busy backend
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

# Generate a preset pass manager
# This will be used to convert the abstract circuit to an equivalent
# Instruction Set Architecture (ISA) circuit.

pm = generate_preset_pass_manager(backend=backend, optimization_level=0)

# Set the random seed
random.seed(10)

대상 회로 초기화

다음과 같은 속성을 가진 6큐비트 회로를 생각해 보겠습니다:

  • 무작위 RZ 회전과 CNOT 게이트의 레이어를 번갈아 가며 사용합니다.
  • 미러 구조, 즉 단일 U 다음에 그 역을 적용합니다.
def generate_circuit(n_qubits, n_layers):
    r"""
    A function to generate a pseudo-random a circuit with ``n_qubits`` qubits
    and ``2*n_layers`` entangling layers of the type used in this notebook.
    """
    # An array of random angles
    angles = [
        [random.random() for q in range(n_qubits)] for s in range(n_layers)
    ]

    qc = QuantumCircuit(n_qubits)
    qubits = list(range(n_qubits))

    # do random circuit
    for layer in range(n_layers):
        # rotations
        for q_idx, qubit in enumerate(qubits):
            qc.rz(angles[layer][q_idx], qubit)

        # cx gates
        control_qubits = (
            qubits[::2] if layer % 2 == 0 else qubits[1 : n_qubits - 1 : 2]
        )
        for qubit in control_qubits:
            qc.cx(qubit, qubit + 1)

    # undo random circuit
    for layer in range(n_layers)[::-1]:
        # cx gates
        control_qubits = (
            qubits[::2] if layer % 2 == 0 else qubits[1 : n_qubits - 1 : 2]
        )
        for qubit in control_qubits:
            qc.cx(qubit, qubit + 1)

        # rotations
        for q_idx, qubit in enumerate(qubits):
            qc.rz(-angles[layer][q_idx], qubit)

    return qc


# Generate a random circuit
qc = generate_circuit(6, 3)
# Convert the abstract circuit to an equivalent ISA circuit.
isa_qc = pm.run(qc)

qc.draw("mpl", idle_wires=0)

Output:

Output of the previous code cell

단일 폴리 Z 연산자를 옵저버블로 선택하고 이를 사용해 프리미티브 통합 블록(PUB)을 초기화합니다.

# Initialize the observables
obs = ["ZIIIII", "IZIIII", "IIZIII", "IIIZII", "IIIIZI", "IIIIIZ"]
print(f"Observables: {obs}")

# Map the observables to the backend's layout
isa_obs = [SparsePauliOp(o).apply_layout(isa_qc.layout) for o in obs]

# Initialize the PUBs, which consist of six-qubit circuits
# with `n_layers` 1, ..., 6
all_n_layers = [1, 2, 3, 4, 5, 6]

pubs = [(pm.run(generate_circuit(6, n)), isa_obs) for n in all_n_layers]

Output:

Observables: ['ZIIIII', 'IZIIII', 'IIZIII', 'IIIZII', 'IIIIZI', 'IIIIIZ']

회로를 클리포드화하다

앞서 정의한 PUB 회로는 클리포드 회로가 아니므로 고전적으로 시뮬레이션하기 어렵습니다. 하지만 Neat to_clifford 메서드를 사용하여 클리포드 회로에 매핑하여 보다 효율적으로 시뮬레이션할 수 있습니다. 메서드는 to_clifford 메서드는 트랜스파일러 패스를 감싸는 ConvertISAToClifford 트랜스파일러 패스를 감싸는 것으로, 독립적으로 사용할 수도 있습니다. 특히 기존 회로의 비클리포드 단일 큐비트 게이트를 클리포드 단일 큐비트 게이트로 대체하지만, 2큐비트 게이트나 큐비트 수, 회로 깊이는 변경하지 않습니다.

클리포드 회로 시뮬레이션에 대한 자세한 내용은 키스킷 에어 프리미티브를 사용한 안정기 회로의 효율적인 시뮬레이션을 참조하세요.

먼저 Neat 을 초기화합니다.

# You could specify a custom `NoiseModel` here. If `None`, `Neat`
# pulls the noise model from the given backend
noise_model = None

# Initialize `Neat`
analyzer = Neat(backend, noise_model)

다음으로, PUB를 클리포드화합니다.

clifford_pubs = analyzer.to_clifford(pubs)

clifford_pubs[0].circuit.draw("mpl", idle_wires=0)

Output:

Output of the previous code cell

응용 1: 노이즈가 회로 출력에 미치는 영향 분석

이 예제는 이상적인 (ideal_sim) 조건과 잡음이 있는 (noisy_sim) 조건 모두에서 시뮬레이션을 실행함으로써 회로 깊이에 따른 다양한 잡음 모델이 PUB에 미치는 영향을 연구하는 Neat 방법을 보여줍니다. 이는 QPU에서 작업을 실행하기 전에 실험 결과의 품질에 대한 기대치를 설정하는 데 유용할 수 있습니다. 노이즈 모델에 대해 자세히 알아보려면 Qiskit Aer 프리미티브를 사용한 정확한 시뮬레이션과 노이즈 시뮬레이션을 참조하십시오.

시뮬레이션된 결과는 수학적 연산을 지원하므로 서로(또는 실험 결과와) 비교하여 장점 수치를 계산할 수 있습니다.

Caution

QPU는 다양한 종류의 노이즈에 영향을 받을 수 있습니다. 여기에 사용된 키스킷 에어 노이즈 모델은 일부만 시뮬레이션하므로 실제 QPU의 노이즈보다 덜 심각할 수 있습니다.

QPU에서 노이즈 모델을 초기화할 때 어떤 오류가 포함되는지에 대한 자세한 내용은 Aer NoiseModel API 레퍼런스를 참조하세요.

이상적이고 노이즈가 많은 클래식 시뮬레이션을 수행하여 시작하세요.

# Perform a noiseless simulation
ideal_results = analyzer.ideal_sim(clifford_pubs)
print(f"Ideal results:\n {ideal_results}\n")

# Perform a noisy simulation with the backend's noise model
noisy_results = analyzer.noisy_sim(clifford_pubs)
print(f"Noisy results:\n {noisy_results}\n")

Output:

Ideal results:
 NeatResult([NeatPubResult(vals=array([1., 1., 1., 1., 1., 1.])), NeatPubResult(vals=array([1., 1., 1., 1., 1., 1.])), NeatPubResult(vals=array([1., 1., 1., 1., 1., 1.])), NeatPubResult(vals=array([1., 1., 1., 1., 1., 1.])), NeatPubResult(vals=array([1., 1., 1., 1., 1., 1.])), NeatPubResult(vals=array([1., 1., 1., 1., 1., 1.]))])

Noisy results:
 NeatResult([NeatPubResult(vals=array([0.99609375, 0.99414062, 0.98632812, 0.9921875 , 0.97460938,
       0.97851562])), NeatPubResult(vals=array([0.984375  , 0.98828125, 0.98046875, 0.98632812, 0.96679688,
       0.98828125])), NeatPubResult(vals=array([0.9609375 , 0.9765625 , 0.953125  , 0.95898438, 0.95703125,
       0.96679688])), NeatPubResult(vals=array([0.96875   , 0.97070312, 0.93164062, 0.94335938, 0.93164062,
       0.97460938])), NeatPubResult(vals=array([0.9140625 , 0.9296875 , 0.91796875, 0.92382812, 0.90429688,
       0.91992188])), NeatPubResult(vals=array([0.89648438, 0.9140625 , 0.921875  , 0.94921875, 0.92773438,
       0.95117188]))])

다음으로 수학적 연산을 적용하여 절대 차이를 계산합니다. 가이드의 나머지 부분에서는 이상적인 결과와 노이즈 또는 실험 결과를 비교하기 위해 절대 차이를 장점 수치로 사용하지만 유사한 장점 수치를 설정할 수도 있습니다.

절대적인 차이는 회로의 크기에 따라 노이즈의 영향이 커진다는 것을 보여줍니다.

# Figure of merit: Absolute difference
def rdiff(res1, res2):
    r"""The absolute difference between `res1` and res2`.

    --> The closer to `0`, the better.
    """
    d = abs(res1 - res2)
    return np.round(d.vals * 100, 2)


for idx, (ideal_res, noisy_res) in enumerate(
    zip(ideal_results, noisy_results)
):
    vals = rdiff(ideal_res, noisy_res)

    # Print the mean absolute difference for the observables
    mean_vals = np.round(np.mean(vals), 2)
    print(
        f"Mean absolute difference between ideal and noisy results "
        f"for circuits with {all_n_layers[idx]} layers:\n  {mean_vals}%\n"
    )

Output:

Mean absolute difference between ideal and noisy results for circuits with 1 layers:
  1.3%

Mean absolute difference between ideal and noisy results for circuits with 2 layers:
  1.76%

Mean absolute difference between ideal and noisy results for circuits with 3 layers:
  3.78%

Mean absolute difference between ideal and noisy results for circuits with 4 layers:
  4.66%

Mean absolute difference between ideal and noisy results for circuits with 5 layers:
  8.17%

Mean absolute difference between ideal and noisy results for circuits with 6 layers:
  7.32%

이러한 유형의 회로를 개선하기 위해 다음과 같은 대략적이고 간단한 지침을 따를 수 있습니다:

  • 평균 절대 차이가 90%보다 크면 완화가 도움이 되지 않을 가능성이 높습니다.
  • 평균 절대 차이가 90% 미만인 경우 확률적 오류 증폭(PEA) 을 통해 결과를 개선할 수 있습니다.
  • 평균 절대 차이가 80% 미만인 경우, 게이트 폴딩이 있는 ZNE도 결과를 개선할 수 있을 것입니다.

위의 모든 절대적인 차이가 90% 미만이므로 원래 회로에 PEA를 적용하면 결과의 품질이 향상될 수 있습니다.

분석기에서 다양한 노이즈 모델을 지정할 수 있습니다. 다음 예제에서는 동일한 테스트를 수행하지만 사용자 지정 노이즈 모델을 추가합니다.

# Set up a noise model with strength 0.02 on every two-qubit gate
noise_model = NoiseModel()
for qubits in backend.coupling_map:
    noise_model.add_quantum_error(
        depolarizing_error(0.02, 2), ["ecr", "cx", "cz"], qubits
    )

# Update the analyzer's noise model
analyzer.noise_model = noise_model

# Perform a noiseless simulation
ideal_results = analyzer.ideal_sim(clifford_pubs)

# Perform a noisy simulation with the backend's noise model
noisy_results = analyzer.noisy_sim(clifford_pubs)

# Compare the results
for idx, (ideal_res, noisy_res) in enumerate(
    zip(ideal_results, noisy_results)
):
    values = rdiff(ideal_res, noisy_res)

    # Print the mean absolute difference for the observables
    mean_values = np.round(np.mean(values), 2)
    print(
        f"Mean absolute difference between ideal and noisy results "
        f"for circuits with {all_n_layers[idx]} layers:\n  {mean_values}%\n"
    )

Output:

Mean absolute difference between ideal and noisy results for circuits with 1 layers:
  4.16%

Mean absolute difference between ideal and noisy results for circuits with 2 layers:
  8.92%

Mean absolute difference between ideal and noisy results for circuits with 3 layers:
  12.86%

Mean absolute difference between ideal and noisy results for circuits with 4 layers:
  17.45%

Mean absolute difference between ideal and noisy results for circuits with 5 layers:
  25.82%

Mean absolute difference between ideal and noisy results for circuits with 6 layers:
  27.96%

위에서 살펴본 바와 같이, 노이즈 모델이 주어지면 QPU에서 실행하기 전에 관심 있는 (클리포드화된 버전의) PUB에 대한 노이즈의 영향을 정량화해 볼 수 있습니다.


응용 2: 다양한 전략 비교 평가

이 예에서는 Neat 을 사용하여 PUB에 가장 적합한 옵션을 식별하는 데 도움을 줍니다. 이를 위해 qiskit_aer 으로는 시뮬레이션할 수 없는 PEA 로 추정 문제를 실행하는 것을 고려해 보세요. Neat 을 사용하여 어떤 노이즈 증폭 인자가 가장 적합한지 결정한 다음, QPU에서 원래 실험을 실행할 때 해당 인자를 사용할 수 있습니다.

# Generate a circuit with six qubits and six layers
isa_qc = pm.run(generate_circuit(6, 3))

# Use the same observables as previously
pubs = [(isa_qc, isa_obs)]
clifford_pubs = analyzer.to_clifford(pubs)
noise_factors = [
    [1, 1.1],
    [1, 1.1, 1.2],
    [1, 1.5, 2],
    [1, 1.5, 2, 2.5, 3],
    [1, 4],
]
# Run the PUBs on a QPU
estimator = Estimator(backend)
estimator.options.default_shots = 100000
estimator.options.twirling.enable_gates = True
estimator.options.twirling.enable_measure = True
estimator.options.twirling.shots_per_randomization = 100
estimator.options.resilience.measure_mitigation = True
estimator.options.resilience.zne_mitigation = True
estimator.options.resilience.zne.amplifier = "pea"

jobs = []
for factors in noise_factors:
    estimator.options.resilience.zne.noise_factors = factors
    jobs.append(estimator.run(clifford_pubs))

results = [job.result() for job in jobs]
# Perform a noiseless simulation
ideal_results = analyzer.ideal_sim(clifford_pubs)
# Look at the mean absolute difference to quickly determine
# the best choice for your options
for factors, res in zip(noise_factors, results):
    d = rdiff(ideal_results[0], res[0])
    print(
        f"Mean absolute difference for factors "
        f"{factors}:\n  {np.round(np.mean(d), 2)}%\n"
    )

Output:

Mean absolute difference for factors [1, 1.1]:
  10.9%

Mean absolute difference for factors [1, 1.1, 1.2]:
  4.64%

Mean absolute difference for factors [1, 1.5, 2]:
  4.33%

Mean absolute difference for factors [1, 1.5, 2, 2.5, 3]:
  5.66%

Mean absolute difference for factors [1, 4]:
  4.53%

차이가 가장 작은 결과에 따라 선택할 수 있는 옵션이 표시됩니다.


다음 단계

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