ข้ามไปยังเนื้อหาหลัก
โครงการนี้อยู่ในช่วงเบต้า พบข้อผิดพลาด? สร้าง GitHub Issue มีคำถามหรือไอเดีย? ถามใน Discussions — ยินดีรับฟังความคิดเห็น!
คุณภาพการแปลในหน้านี้เป็นอย่างไร?

สร้างการทดลองเรียนรู้

บทแนะนำนี้สาธิตวิธีสร้างการทดลองเรียนรู้มาตรฐานตั้งแต่ต้น และใช้เรียนรู้โมเดลจากข้อมูลที่มีสัญญาณรบกวนแบบจำลอง

  1. กำหนด gate set บนวงแหวนของ qubit

  2. เลือกโมเดล Pauli-Lindblad แบบ 2-local

  3. สร้างการทดลองเรียนรู้

  4. สร้าง circuit

  5. ตั้งค่าการจำลองในเครื่อง

  6. รันโปรแกรม

  7. วิเคราะห์ข้อมูล

การรันบนฮาร์ดแวร์จริง

circuit ด้านล่างจำลองในเครื่อง ดังนั้นการทำตามขั้นตอนนี้ไม่ต้องใช้ข้อมูลรับรอง IBM Quantum® หากต้องการรันบนอุปกรณ์จริงแทน:

  • ขั้นตอนที่ 1: แทนที่ FakeMarrakesh ด้วย backend จริง

  • ขั้นตอนที่ 5: ส่ง backend นั้นเป็น mode ของ executor และเอาตัวเลือกของ simulator ออก

1. กำหนด gate set บนวงแหวนของ qubit​

สร้าง QiskitGateSet จาก Target ของ backend และชุดย่อยของ qubit ของมัน ในที่นี้คือวงแหวน qubit สิบสองตัวของ FakeMarrakesh จากนั้นเพิ่ม gate หนึ่งตัวเข้าไป คือชั้นของ CZ gate หกตัวที่ครอบคลุมวงแหวนนั้น โดยค่าเริ่มต้น gate set จะถูกกำหนดค่าเริ่มต้นด้วย gate เตรียมสถานะ P และ gate การวัด M

from qiskit_ibm_runtime.fake_provider import FakeMarrakesh

from qiskit_noise_learning.gate_sets import QiskitGateSet

backend = FakeMarrakesh()

qubit_subset = [*range(25, 30), *range(37, 39), *range(45, 50)]
cz_pairs = [(25, 26), (27, 28), (29, 38), (37, 45), (46, 47), (48, 49)]

gate_set = QiskitGateSet(backend.num_qubits, target=backend.target, qubit_subset=qubit_subset)

with gate_set.build_new_gate("cz_gate", latex_str=r"\mathrm{CZ}") as builder:
for pair in cz_pairs:
builder.circuit.cz(*pair)

list(gate_set)
['M', 'P', 'cz_gate']
การรันบนฮาร์ดแวร์จริง
from qiskit_ibm_runtime import QiskitRuntimeService

backend = QiskitRuntimeService().backend("ibm_marrakesh")

เรียก draw() เพื่อดู gate บนโทโพโลยีของอุปกรณ์ ได้แก่วงแหวนของ qubit ใน gate set และคู่ใดของมันที่ gate ทำให้เกิดเอนแทงเกิล

gate_set.draw()

2. เลือกโมเดล Pauli-Lindblad แบบ 2-local​

กำหนดว่าสัญญาณรบกวนมี generator แบบ Pauli-Lindblad ใดได้บ้างด้วย PauliLindbladModel สร้างชุด generator นั้นจากการเชื่อมต่อของ gate set ด้วย k_local() ในที่นี้คือ Pauli แบบ 2-local ทุกตัวบนคู่ qubit ที่เชื่อมต่อกันของ unitary gate และ Pauli แบบ single-qubit สำหรับการเตรียมสถานะและการวัด

from qiskit_noise_learning.models import PauliLindbladModel

model = PauliLindbladModel.k_local(gate_set, gate_k={"cz_gate": 2, "M": 1, "P": 1})

แสดงจำนวนพารามิเตอร์ที่ไม่ทราบค่าของโมเดลสัญญาณรบกวนของแต่ละ gate

{name: len(generators) for name, generators in model.generators.items()}
{'M': 12, 'P': 12, 'cz_gate': 144}

3. สร้างการทดลองเรียนรู้​

ประกอบ Experiment ด้วยการประกอบ builder stage แต่ละ stage อ่านสิ่งที่ stage ก่อนหน้าเขียนไว้ ลำดับจึงสำคัญ:

from qiskit_noise_learning.experiment_builder import (
BindFragmentDepths,
CompleteSequences,
EvenDepthVanillaPaths,
Experiment,
GenerateInstructionSequences,
IdentifyRelations,
MergeInstructionSequences,
SPAMPaths,
VanillaInstructionSequences,
)

experiment_builder = (
# Add standard vanilla learning paths and instruction sequences, and identify relations
EvenDepthVanillaPaths()
+ VanillaInstructionSequences()
+ IdentifyRelations()
# Add paths for learning SPAM, then generate and merge instruction sequences for measuring them
+ SPAMPaths()
+ GenerateInstructionSequences()
+ MergeInstructionSequences()
# Finalize by completing the instruction sequences and setting experiment depths
+ CompleteSequences()
+ BindFragmentDepths([2, 16, 32, 64])
)

experiment = experiment_builder.run(
Experiment(fidelity_model=model, shots=20, randomizations=50)
)

print(f"Number of paths: {len(experiment.paths)}")
print(f"Number of instruction sequences: {len(experiment.instruction_sequences)}")
Number of paths: 156
Number of instruction sequences: 37

สังเกตแรงก์ของ design matrix:

print(f"Design matrix rank: {experiment.design_matrix.rank}")
Design matrix rank: 120

4. สร้าง circuit​

คอมไพล์การทดลองด้วย ExecutorCircuitGenerator เพื่อสร้าง QuantumProgram ซึ่งเป็น template circuit แบบมีพารามิเตอร์หนึ่งตัวต่อความลึกของแต่ละ fragment

from qiskit_noise_learning.circuit_generator import ExecutorCircuitGenerator

circuit_generator = ExecutorCircuitGenerator(gate_set)
quantum_program = circuit_generator.generate(experiment)

print(f"Number of template circuits: {len(quantum_program.items)}")
Number of template circuits: 5

วาด template circuit เพื่อตรวจสอบ

quantum_program.items[0].circuit.draw("mpl", idle_wires=False, fold=False)

../_images/4088c7e98baeb5b56925c6c1f276159582c5f7040fbba76de438b919210bcc5f.png

5. ตั้งค่าการจำลองในเครื่อง​

เพื่อกำหนดโมเดลสัญญาณรบกวนสำหรับการจำลอง เราใช้ generator ที่มีอยู่แล้วในโมเดลร่วมกับอัตราสุ่มเพื่อสร้าง PauliLindbladMap

import numpy as np
from qiskit.quantum_info import PauliLindbladMap

rng = np.random.default_rng(1234)

true_maps = {
name: PauliLindbladMap.from_terms(
[
PauliLindbladMap.GeneratorTerm(rate, generator)
for generator, rate in zip(generators, rng.uniform(2e-4, 1.5e-3, len(generators)))
]
)
for name, generators in model.generators.items()
if name != "P"
}
{name: noise_map.num_qubits for name, noise_map in true_maps.items()}
{'M': 156, 'cz_gate': 156}

map เหล่านั้นกว้างเท่ากับอุปกรณ์ เนื่องจากโมเดลแสดงด้วยการจัดดัชนี qubit ของ backend แต่ simulator ต้องการให้แต่ละ map กว้างเท่ากับ gate ที่ใช้ โดยดัชนี Pauli วิ่งผ่าน qubit ของ gate ตามลำดับ physical จากน้อยไปมาก ลดขนาดด้วย keep_qubits() ซึ่ง trace out ทุกอย่างที่อยู่นอกวงแหวน:

noise_dict = {
name: noise_map.keep_qubits(qubit_subset) for name, noise_map in true_maps.items()
}
{name: noise_map.num_qubits for name, noise_map in noise_dict.items()}
{'M': 12, 'cz_gate': 12}

simulator ตั้งชื่อสัญญาณรบกวนของแต่ละชั้นตามคำสั่ง box ที่ใช้สร้างชั้นนั้น ซึ่ง to_instruction() คืนค่าให้สำหรับ gate ใดๆ ใน gate set จับคู่แต่ละ box กับ map ของมัน ใช้วิธีจำลองแบบ stabilizer และตั้งค่า seed_simulator เพื่อให้ข้อมูลจำลองทำซ้ำได้:

from qiskit_aer import AerSimulator
from qiskit_ibm_runtime import Executor

executor = Executor(
mode=AerSimulator(method="stabilizer"),
options={
"simulator": {
"layer_noise_model": [
(gate_set[name].to_instruction(), noise_map)
for name, noise_map in noise_dict.items()
],
"seed_simulator": 42,
}
},
)
การรันบนฮาร์ดแวร์จริง
executor = Executor(mode=backend)

6. รันโปรแกรม​

รันโปรแกรม จากนั้นจัดรูปแบบผลลัพธ์ด้วย collect() เพื่อสร้าง Fit ซึ่งเป็นคอนเทนเนอร์ที่ analysis stage อ่านและเขียน

ขั้นตอนนี้เหมือนกันไม่ว่า executor จะชี้ไปที่ simulator หรืออุปกรณ์จริง

job = executor.run(quantum_program)
fit = circuit_generator.collect(job.result())

7. วิเคราะห์ข้อมูล​

สร้าง analysis pipeline รอบการ fit โมเดลด้วยกำลังสองน้อยที่สุดแบบไม่เป็นลบ

from qiskit_noise_learning.analysis import (
ComputeObservables, # computes observables from raw data
CurveFitObservables, # performs exponential fitting
LeastSquaresSolve, # solves model with (nonnegative) least squares
)

analyzer = ComputeObservables() + CurveFitObservables() + LeastSquaresSolve()

fit = analyzer.run(fit)
/opt/hostedtoolcache/Python/3.15.1/x64/lib/python3.15/site-packages/qiskit_noise_learning/analysis/model_solve.py:250: UserWarning: 7 of 156 row(s) of the linear system have a non-positive or non-finite uncertainty, so they carry no usable statistical weight. Positions in LinearSystemData.row_labels: 144, 145, 148, 149, 151, 152, 154.
system = LinearSystemData.from_fit(fit)

พล็อตค่าเฉลี่ยของ observable ที่วัดได้เทียบกับเอกซ์โพเนนเชียลที่ fit ได้ หนึ่ง subplot ต่อหนึ่งคู่ CZ เพื่อดูว่าการสลายที่กำลัง fit เป็นเอกซ์โพเนนเชียลจริงหรือไม่

fit.plot_qubit_pair_decays(
pairs=cz_pairs,
observable_type="means",
exponential_fit=True,
)

สลับ exponential_fit เป็น model_prediction เพื่อเปรียบเทียบข้อมูลเดียวกันกับการสลายที่นัยจากอัตราซึ่งได้จากการแก้กำลังสองน้อยที่สุดแบบไม่เป็นลบ

fit.plot_qubit_pair_decays(
pairs=cz_pairs,
observable_type="means",
model_prediction=True,
)