สร้างการทดลองเรียนรู้
บทแนะนำนี้สาธิตวิธีสร้างการทดลองเรียนรู้มาตรฐานตั้งแต่ต้น และใช้เรียนรู้โมเดลจากข้อมูลที่มีสัญญาณรบกวนแบบจำลอง
-
กำหนด gate set บนวงแหวนของ qubit
-
เลือกโมเดล Pauli-Lindblad แบบ 2-local
-
สร้างการทดลองเรียนรู้
-
สร้าง circuit
-
ตั้งค่าการจำลองในเครื่อง
-
รันโปรแกรม
-
วิเคราะห์ข้อมูล
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)
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,
)
