ข้ามไปยังเนื้อหาหลัก

เปรียบเทียบการตั้งค่า Transpiler

ประมาณการการใช้งาน: ไม่ถึงหนึ่งนาทีบนโปรเซสเซอร์ Eagle r3 (หมายเหตุ: นี่เป็นเพียงการประมาณการเท่านั้น เวลาจริงอาจแตกต่างกัน)

พื้นฐาน

เพื่อให้ได้ผลลัพธ์ที่เร็วและมีประสิทธิภาพมากขึ้น ตั้งแต่วันที่ 1 มีนาคม 2024 เป็นต้นไป Circuit และ observable ต้องถูกแปลงให้ใช้คำสั่งที่ QPU (หน่วยประมวลผลควอนตัม) รองรับเท่านั้น ก่อนส่งไปยัง Qiskit Runtime primitives เราเรียกสิ่งเหล่านี้ว่า instruction set architecture (ISA) Circuit และ observable วิธีทั่วไปในการทำเช่นนี้คือใช้ฟังก์ชัน generate_preset_pass_manager ของ Transpiler อย่างไรก็ตาม คุณอาจเลือกทำตามกระบวนการแบบ manual ก็ได้

ตัวอย่างเช่น คุณอาจต้องการกำหนดเป้าหมายเป็น Qubit กลุ่มเฉพาะบนอุปกรณ์เฉพาะ บทเรียนนี้ทดสอบประสิทธิภาพของการตั้งค่า Transpiler ต่าง ๆ โดยผ่านกระบวนการสร้าง transpile และส่ง Circuit อย่างครบถ้วน

ข้อกำหนดเบื้องต้น

ก่อนเริ่มต้น ตรวจสอบให้แน่ใจว่าติดตั้งสิ่งต่อไปนี้แล้ว:

  • Qiskit SDK v1.2 หรือใหม่กว่า พร้อมรองรับ visualization
  • Qiskit Runtime v0.28 หรือใหม่กว่า (pip install qiskit-ibm-runtime)

การตั้งค่า

# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-ibm-runtime
# 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 GroverOperator, Diagonal

# 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

# Qiskit Runtime
from qiskit_ibm_runtime import (
QiskitRuntimeService,
Batch,
SamplerV2 as Sampler,
)
from qiskit_ibm_runtime.transpiler.passes.scheduling import (
ASAPScheduleAnalysis,
PadDynamicalDecoupling,
)

ขั้นตอนที่ 1: แมปอินพุตคลาสสิกไปยังปัญหาควอนตัม

สร้าง Circuit ขนาดเล็กให้ Transpiler ลองเพิ่มประสิทธิภาพ ตัวอย่างนี้สร้าง Circuit ที่ทำ Grover's algorithm พร้อม oracle ที่ทำเครื่องหมายสถานะ 111 จากนั้น จำลองการแจกแจงในอุดมคติ (สิ่งที่คาดว่าจะวัดได้หากรันบนคอมพิวเตอร์ควอนตัมที่สมบูรณ์แบบจำนวนครั้งอนันต์) เพื่อเปรียบเทียบในภายหลัง

# To run on hardware, 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
'ibm_brisbanse'
oracle = Diagonal([1] * 7 + [-1])
qc = QuantumCircuit(3)
qc.h([0, 1, 2])
qc = qc.compose(GroverOperator(oracle))

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

Output of the previous code cell

ideal_distribution = Statevector.from_instruction(qc).probabilities_dict()

plot_histogram(ideal_distribution)

Output of the previous code cell

ขั้นตอนที่ 2: ปรับแต่งปัญหาสำหรับการรันบน hardware ควอนตัม

ต่อไป ทำการ transpile Circuit สำหรับ QPU คุณจะเปรียบเทียบประสิทธิภาพของ Transpiler โดยตั้ง optimization_level เป็น 0 (ต่ำสุด) กับ 3 (สูงสุด) ระดับการเพิ่มประสิทธิภาพต่ำสุดทำงานขั้นต่ำที่จำเป็นเพื่อให้ Circuit รันบนอุปกรณ์ได้ โดยแมป Qubit ของ Circuit ไปยัง Qubit ของอุปกรณ์และเพิ่ม swap Gate เพื่อให้การดำเนินการสองคิวบิตทั้งหมดเป็นไปได้ ระดับการเพิ่มประสิทธิภาพสูงสุดฉลาดกว่ามากและใช้เทคนิคหลายอย่างเพื่อลดจำนวน Gate โดยรวม เนื่องจาก Gate หลายคิวบิตมีอัตราข้อผิดพลาดสูงและ Qubit สูญเสียความเชื่อมโยงเมื่อเวลาผ่านไป Circuit ที่สั้นกว่าจึงควรให้ผลลัพธ์ที่ดีกว่า

เซลล์ต่อไปนี้ทำการ transpile qc สำหรับทั้งสองค่าของ optimization_level พิมพ์จำนวน Gate สองคิวบิต และเพิ่ม Circuit ที่ transpile แล้วลงในรายการ อัลกอริทึมบางส่วนของ Transpiler เป็นแบบ randomized จึงกำหนด seed เพื่อให้ได้ผลลัพธ์ที่ reproducible

# 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)
Two-qubit gates (optimization_level=0):  21
Two-qubit gates (optimization_level=3): 14

เนื่องจาก CNOT มักมีอัตราข้อผิดพลาดสูง Circuit ที่ transpile ด้วย optimization_level=3 จึงควรทำงานได้ดีกว่ามาก

อีกวิธีในการปรับปรุงประสิทธิภาพคือการใช้ dynamic decoupling โดยการใช้ลำดับ Gate กับ Qubit ที่ว่างงาน ซึ่งช่วยลดการรบกวนที่ไม่ต้องการจากสภาพแวดล้อม เซลล์ต่อไปนี้เพิ่ม dynamic decoupling เข้าไปใน Circuit ที่ transpile ด้วย optimization_level=3 และเพิ่มลงในรายการ

# 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 of the previous code cell

ขั้นตอนที่ 3: รันโดยใช้ Qiskit primitives

ณ จุดนี้ คุณมีรายการ Circuit ที่ transpile แล้วสำหรับ QPU ที่กำหนด ต่อไป สร้าง instance ของ Sampler primitive และเริ่ม batched job โดยใช้ context manager (with ...:) ซึ่งจะเปิดและปิด batch โดยอัตโนมัติ

ภายใน context manager ให้ sample Circuit และเก็บผลลัพธ์ไว้ใน result

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

ขั้นตอนที่ 4: ประมวลผลหลังการรันและคืนผลลัพธ์ในรูปแบบคลาสสิกที่ต้องการ

สุดท้าย plot ผลลัพธ์จากการรันบนอุปกรณ์เทียบกับการแจกแจงในอุดมคติ คุณจะเห็นว่าผลลัพธ์ที่ได้ด้วย optimization_level=3 ใกล้เคียงกับการแจกแจงในอุดมคติมากกว่า เนื่องจากจำนวน Gate น้อยกว่า และ optimization_level=3 + dd ใกล้เคียงยิ่งขึ้นไปอีกเนื่องจาก dynamic decoupling

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 of the previous code cell

คุณสามารถยืนยันสิ่งนี้ได้โดยคำนวณ Hellinger fidelity ระหว่างผลลัพธ์แต่ละชุดกับการแจกแจงในอุดมคติ (ค่าสูงกว่าดีกว่า และ 1 คือ fidelity สมบูรณ์แบบ)

for prob in binary_prob:
print(f"{hellinger_fidelity(prob, ideal_distribution):.3f}")
0.848
0.945
0.990
Source: IBM Quantum docs — updated 1 เม.ย. 2569
English version on doQumentation — updated 7 พ.ค. 2569
This translation based on the English version of 11 มี.ค. 2569