Skip to main content
IBM Quantum Platform

트랜스파일러 설정 비교

  • 이 페이지의 코드는 다음 요구 사항을 바탕으로 개발되었습니다. 이 버전 이상을 사용하시기를 권장합니다.

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

트랜스파일러 설정에 따라 회로에 적용되는 최적화 방식이 달라지며, 이는 대개 기존 처리 시간이 늘어나는 대가를 치르게 됩니다. 이 가이드에서는 다양한 설정의 성능을 테스트하는 방법을 보여주기 위해 회로를 생성하고, 트랜스파일링하고, 제출하는 전체 과정을 단계별로 안내합니다.

같은 설정이 한 회로의 성능은 향상시킬 수 있지만, 다른 회로의 성능은 저해할 수도 있다는 점에 유의하십시오. 실제 하드웨어에서 실행하기 전에 변환된 회로를 반드시 점검하십시오.


샘플 회로 설정 및 구성

# Create circuit to test transpiler on
from qiskit import QuantumCircuit
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit.circuit.library import grover_operator, DiagonalGate

# Use Statevector object to calculate the ideal output
from qiskit.quantum_info import Statevector
from qiskit.visualization import plot_histogram
from qiskit.transpiler import PassManager

from qiskit.circuit.library import XGate
from qiskit.quantum_info import hellinger_fidelity

트랜스파일러가 최적화를 시도할 수 있도록 작은 회로를 생성하십시오. 이 예제는 상태를 표시하는 오라클을 사용하여 그로버 111알고리즘을 수행하는 회로를 생성합니다. 다음으로, 나중에 비교하기 위해 이상적인 분포(완벽한 양자 컴퓨터에서 무한히 반복 실행했을 때 측정될 것으로 예상되는 결과)를 시뮬레이션합니다.

oracle = DiagonalGate([1] * 7 + [-1])
qc = QuantumCircuit(3)
qc.h([0, 1, 2])
qc = qc.compose(grover_operator(oracle))

qc.draw(output="mpl", style="iqp")

Output:

Output of the previous code cell
ideal_distribution = Statevector.from_instruction(qc).probabilities_dict()

plot_histogram(ideal_distribution)

Output:

Output of the previous code cell

트랜스파일

다음으로, QPU용 회로를 트랜스파일합니다. 트랜스파일러의 성능을 (최저 0 )로 설정했을 때와 3 (최고 optimization_level )로 설정했을 때를 비교하게 됩니다. 최저 최적화 수준은 회로가 장치에서 실행되도록 필요한 최소한의 작업만 수행합니다. 회로의 큐비트를 장치의 큐비트에 매핑하고 모든 2-큐비트 연산을 가능하게 하기 위해 스왑 게이트를 추가합니다. 최상위 최적화 수준은 훨씬 더 지능적이며, 전체 게이트 수를 줄이기 위해 다양한 기법을 활용합니다. 다중 큐비트 게이트는 오류율이 높고 큐비트는 시간이 지남에 따라 디코히어런스를 일으키므로, 회로가 짧을수록 더 나은 결과를 얻을 수 있을 것이다.

Important

이 예제는 ‘ IBM Quantum® ’ 하드웨어를 사용하지만, Qiskit과 호환되는 모든 QPU에서 실행해 볼 수 있습니다. 결과는 다를 수 있습니다.

다음 셀은 두 값 모두에 대해 qc``optimization_level 트랜스파일링을 수행하고, 2큐비트 게이트의 개수를 출력하며, 트랜스파일링된 회로를 리스트에 추가합니다. 일부 트랜스파일러 알고리즘은 무작위화되므로 재현성을 위해 시드를 설정합니다.

# Use IBM Quantum Compute Service to run jobs on hardware
from qiskit_ibm_runtime import (
    QiskitRuntimeService,
    SamplerV2 as Sampler,
)
# Select the backend with the fewest number of jobs in the queue
service = QiskitRuntimeService()
backend = service.least_busy(
    operational=True, simulator=False, min_num_qubits=127
)
backend.name

Output:

'ibm_fez'
# Need to add measurements to the circuit
qc.measure_all()

# Find the correct two-qubit gate
twoQ_gates = set(["ecr", "cz", "cx"])
for gate in backend.basis_gates:
    if gate in twoQ_gates:
        twoQ_gate = gate

circuits = []
for optimization_level in [0, 3]:
    pm = generate_preset_pass_manager(
        optimization_level, backend=backend, seed_transpiler=0
    )
    t_qc = pm.run(qc)
    print(
        f"Two-qubit gates (optimization_level={optimization_level}): ",
        t_qc.count_ops()[twoQ_gate],
    )
    circuits.append(t_qc)

Output:

Two-qubit gates (optimization_level=0):  21
Two-qubit gates (optimization_level=3):  12

CNOT은 일반적으로 오류율이 높기 때문에, 로 트랜스파일된 회로는 훨씬 optimization_level=3 더 우수한 성능을 발휘할 것이다.

성능을 향상시킬 수 있는 또 다른 방법은 유휴 상태의 큐비트에 일련의 게이트를 적용하는 동적 디커플링을 활용하는 것입니다. 이를 통해 환경과의 원치 않는 상호작용을 일부 차단할 수 있습니다. 다음 셀은 로 변환된 회로에 동적 디커플링을 optimization_level=3 추가하고 이를 목록에 추가합니다.

from qiskit_ibm_runtime.transpiler.passes.scheduling import (
    ASAPScheduleAnalysis,
    PadDynamicalDecoupling,
)

# Get gate durations so the transpiler knows how long each operation takes
durations = backend.target.durations()

# This is the sequence we'll apply to idling qubits
dd_sequence = [XGate(), XGate()]

# Run scheduling and dynamic decoupling passes on circuit
pm = PassManager(
    [
        ASAPScheduleAnalysis(durations),
        PadDynamicalDecoupling(durations, dd_sequence),
    ]
)
circ_dd = pm.run(circuits[1])

# Add this new circuit to our list
circuits.append(circ_dd)
circ_dd.draw(output="mpl", style="iqp", idle_wires=False)

Output:

Output of the previous code cell

회로 실행하기

이제 다양한 설정으로 변환된 회로 목록이 준비되었습니다. 다음으로, 샘플러 프리미티브를 사용하여 이 회로들을 실행하고 결과를 에 저장하세요 result.

sampler = Sampler(backend)
job = sampler.run(
    [(circuit) for circuit in circuits],  # sample all three circuits
    shots=8000,
)
result = job.result()

뷰 결과

마지막으로, 장치 실험 결과를 이상 분포와 비교하여 그래프로 나타내십시오. 게이트 수가 적기 때문에 의 결과가 이상적인 optimization_level=3 분포에 더 가깝고, 동적 디커플링 덕분에 의 optimization_level=3 + dd 결과가 더욱 이상적인 분포에 가깝다는 것을 확인할 수 있습니다.

binary_prob = [
    {
        k: v / res.data.meas.num_shots
        for k, v in res.data.meas.get_counts().items()
    }
    for res in result
]
plot_histogram(
    binary_prob + [ideal_distribution],
    bar_labels=False,
    legend=[
        "optimization_level=0",
        "optimization_level=3",
        "optimization_level=3 + dd",
        "ideal distribution",
    ],
)

Output:

Output of the previous code cell

각 결과 집합과 이상적 분포 사이의 헬링거 충실도를 계산하여 이를 확인할 수 있습니다(값이 높을수록 좋으며, 1은 완벽한 충실도를 의미합니다).

for prob in binary_prob:
    print(f"{hellinger_fidelity(prob, ideal_distribution):.3f}")

Output:

0.717
0.982
0.981

다음 단계

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