การฝึก Quantum Kernel
ประมาณการการใช้งาน: ไม่ถึงหนึ่งนาทีบนโปรเซสเซอร์ Heron r3 (หมายเหตุ: นี่เป็นเพียงการประมาณเท่านั้น เวลาการรันจริงอาจแตกต่างออกไป)
ผลลัพธ์การเรียนรู้
หลังจากเรียนจบบทช่วยสอนนี้ คาดว่าจะเข้าใจสิ่งต่อไปนี้:
- วิธีการ Kernel และการใช้งาน
- Quantum kernels และวิธีที่ช่วยให้ feature space มีประสิทธิภาพมากขึ้น
- การสร้างวงจร quantum kernel
- วิธีฝึก quantum kernel โดยใช้ Qiskit pattern: map, optimize, execute และ post-process
สิ่งที่ควรรู้ก่อน
แนะนำให้ทำความคุ้นเคยกับ quantum kernels ว่ามีความสำคัญอย่างไรและใช้งานในทางปฏิบัติอย่างไร
- Covariant quantum kernels for data with group structure (บทความ)
- Introduction to Quantum Kernels and Support Vector Machines (วิดีโอ)
- Quantum Kernels in Practice (วิดีโอ)
นอกจากนี้ ยังเป็นประโยชน์ถ้ามีความเข้าใจพื้นฐานเกี่ยวกับทฤษฎีกลุ่ม
พื้นหลัง
วิธีการ Kernel เป็นที่นิยมแพร่หลายในการประยุกต์ใช้ machine learning ในบริบทนี้ "kernel" หมายถึงเมทริกซ์ kernel หรือค่าแต่ละส่วนในเมทริกซ์นั้น โดยทั่วไป kernel คือการวัดความคล้ายคลึงระหว่างข้อมูลที่เข้ารหัสใน feature space มิติสูง และสามารถนำไปใช้ เช่น ในงานจำแนกประเภทด้วย support vector machines
Quantum kernel methods คือวิธีการที่ใช้คอมพิวเตอร์ quantum ในการประมาณ kernel เป็นที่ทราบกันว่าคอมพิวเตอร์ quantum สามารถเข้ารหัสข้อมูลใน feature space ที่ได้รับการเพิ่มประสิทธิภาพด้วย quantum ซึ่งแทนที่ analogs แบบ classical ได้อย่างมีประสิทธิภาพ สำหรับ และ โดยทั่วไปมี โดยที่ คือ feature map, เป้าหมายของ คือทำให้หมวดหมู่ของข้อมูลแยกออกจากกันด้วย hyperplane โดยนำเวกเตอร์ใน feature-mapped space มาเป็น arguments ฟังก์ชัน kernel คืนค่า inner product ของมัน: ในแนวทาง classical feature maps ที่น่าสนใจคือกรณีที่ฟังก์ชัน kernel สามารถประเมินได้ง่าย กล่าวคือ เมื่อ inner product ใน feature-mapped space เขียนในรูปของเวกเตอร์ข้อมูลต้นฉบับได้ โดยไม่ต้องสร้าง และ โดยตรง ในกรณีของ quantum kernels การ mapping ฟีเจอร์ทำโดยวงจร quantum และ kernel ถูกประมาณโดยใช้ความน่าจะเป็นของการวัดที่สุ่มจากวงจร
บทช่วยสอนนี้แสดงวิธีสร้าง Qiskit pattern สำหรับคำนวณค่าต่าง ๆ ในเมทริกซ์ quantum kernel ที่ใช้สำหรับการจำแนกแบบ binary
ข้อกำหนดเบื้องต้น
ก่อนเริ่มบทช่วยสอนนี้ ให้แน่ใจว่าได้ติดตั้งสิ่งต่อไปนี้แล้ว:
- Qiskit SDK v2.3.1 ขึ้นไป พร้อมรองรับ visualization
- Qiskit Runtime v0.44.0 ขึ้นไป (
pip install qiskit-ibm-runtime)
การตั้งค่า
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy pandas qiskit qiskit-ibm-runtime
# General Imports and helper functions
import urllib.request
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from qiskit.circuit import Parameter, ParameterVector, QuantumCircuit
from qiskit.circuit.library import unitary_overlap
from qiskit.primitives import StatevectorSampler
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService, Sampler
# Download the dataset (portable across platforms)
urllib.request.urlretrieve(
"https://raw.githubusercontent.com/qiskit-community/prototype-quantum-kernel-training/main/data/dataset_graph7.csv",
"dataset_graph7.csv",
)
def visualize_counts(res_counts, num_qubits, num_shots):
"""Visualize the outputs from the Qiskit Sampler primitive."""
zero_prob = res_counts.get(0, 0.0)
top_10 = dict(
sorted(res_counts.items(), key=lambda item: item[1], reverse=True)[
:10
]
)
top_10.update({0: zero_prob})
by_key = dict(sorted(top_10.items(), key=lambda item: item[0]))
x_vals, y_vals = list(zip(*by_key.items()))
x_vals = [bin(x_val)[2:].zfill(num_qubits) for x_val in x_vals]
y_vals_prob = []
for t in range(len(y_vals)):
y_vals_prob.append(y_vals[t] / num_shots)
y_vals = y_vals_prob
plt.bar(x_vals, y_vals)
plt.xticks(rotation=75)
plt.title("Results of sampling")
plt.xlabel("Measured bitstring")
plt.ylabel("Probability")
plt.show()
def get_training_data():
"""Read the training data."""
df = pd.read_csv("dataset_graph7.csv", sep=",", header=None)
training_data = df.values[:20, :]
ind = np.argsort(training_data[:, -1])
X_train = training_data[ind][:, :-1]
return X_train
ตัวอย่างด้วย simulator ขนาดเล็ก
ในส่วนนี้ เราจะอธิบายสี่ขั้นตอนของ Qiskit pattern บนปัญหา labeling-cosets-with-error แบบเจ็ด qubit และประเมินค่าเดียวในเมทริกซ์ kernel โดยใช้ StatevectorSampler primitive จาก Qiskit simulator แบบ statevector มีความแม่นยำสูง (ไม่นับ shot noise) และช่วยให้เราเห็นภาพรวมของวิธีการโดยไม่ต้องใช้เวลา QPU จากนั้นเราจะทำซ้ำกรณีเดียวกันบน hardware จริงในส่วนตัวอย่าง hardware
ขั้นตอนที่ 1: แมป input แบบ classical ไปยังปัญหา quantum
- Input: ชุดข้อมูลสำหรับการฝึก
- Output: วงจรแบบ abstract สำหรับคำนวณค่าในเมทริกซ์ kernel
ปัญหาการจำแนกแบบ binary ที่เราต้องการแก้ไขนี้เรียกว่า "labeling cosets with error" ชุดข้อมูลฝึกที่เป็น input มีโครงสร้างกลุ่ม ประกอบด้วย coset สองชุดที่เกิดจากกลุ่มและกลุ่มย่อย กลุ่มถูกกำหนดให้เป็น สำหรับ qubit ซึ่งเป็นกลุ่ม special unitary ของเมทริกซ์ และมีการประยุกต์ใช้อย่างกว้างขวางในธรรมชาติ เช่น ใน Standard Model ของฟิสิกส์อนุภาค เรานำกลุ่มย่อย (graph-stabilizer) ที่มี สำหรับกราฟที่มีเส้น และจุด โปรดสังเกตว่า stabilizers จะ fix stabilizer state เช่นที่ สุดท้าย เรากำหนด left-cosets สองชุด โดยการสุ่ม สองค่า
สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับชุดข้อมูลและวิธีสร้าง ดูที่ notebook นี้ จาก Quantum Kernel Training Toolkit
เราสร้าง quantum circuit ที่ใช้ในการประเมินค่าหนึ่งในเมทริกซ์ kernel
ข้อมูล input ถูกใช้เพื่อกำหนดมุมหมุนสำหรับ gate แบบ parametrized ในวงจร
เพื่อความเรียบง่าย เราจะใช้ตัวอย่างข้อมูล x1=14 และ x2=19
หมายเหตุ: ชุดข้อมูลที่ใช้ในบทช่วยสอนนี้สามารถดาวน์โหลดได้ ที่นี่
# Prepare training data
X_train = get_training_data()
# Empty kernel matrix
num_samples = np.shape(X_train)[0]
kernel_matrix = np.full((num_samples, num_samples), np.nan)
# Prepare feature map for computing overlap
num_features = np.shape(X_train)[1]
num_qubits = int(num_features / 2)
entangler_map = [[0, 2], [3, 4], [2, 5], [1, 4], [2, 3], [4, 6]]
fm = QuantumCircuit(num_qubits)
training_param = Parameter("θ")
feature_params = ParameterVector("x", num_qubits * 2)
fm.ry(training_param, fm.qubits)
for cz in entangler_map:
fm.cz(cz[0], cz[1])
for i in range(num_qubits):
fm.rz(-2 * feature_params[2 * i + 1], i)
fm.rx(-2 * feature_params[2 * i], i)
# Assign tunable parameter to known optimal value and set the data params for
# first two samples
x1 = 14
x2 = 19
unitary1 = fm.assign_parameters(list(X_train[x1]) + [np.pi / 2])
unitary2 = fm.assign_parameters(list(X_train[x2]) + [np.pi / 2])
# Create the overlap circuit
overlap_circ = unitary_overlap(unitary1, unitary2)
overlap_circ.measure_all()
overlap_circ.draw("mpl", scale=0.6, style="iqp")
ขั้นตอนที่ 2: ปรับปรุงปัญหาสำหรับการรันบน quantum hardware
- Input: วงจรแบบ abstract ที่ยังไม่ได้ปรับให้เหมาะสมกับ backend ใดโดยเฉพาะ
- Output: วงจรเป้าหมายที่ถูกปรับให้เหมาะสมกับ QPU ที่เลือก
สำหรับเส้นทาง statevector simulator ที่ใช้ในส่วนนี้ ไม่จำเป็นต้องมีการ optimize เฉพาะ backend: วงจรแบบ abstract สามารถสุ่มตัวอย่างได้โดยตรง เราจะฝึกขั้นตอนนี้ในตัวอย่าง hardware ด้านล่าง ซึ่งวงจรจะถูก transpile กับ QPU จริงโดยใช้ generate_preset_pass_manager พร้อม optimization_level=3
ขั้นตอนที่ 3: รันด้วย Qiskit primitives
- Input: วงจรแบบ abstract
- Output: การกระจายแบบ quasi-probability
ใช้ StatevectorSampler primitive จาก Qiskit เพื่อสร้างการกระจายแบบ quasi-probability ของสถานะที่ได้จากการสุ่มตัวอย่างวงจร สำหรับงานสร้างเมทริกซ์ kernel เราสนใจเป็นพิเศษในความน่าจะเป็นของการวัดสถานะ |0>
sampler = StatevectorSampler()
# Execute and get counts
num_shots = 10_000
results = sampler.run([overlap_circ], shots=num_shots).result()
counts = results[0].data.meas.get_int_counts()
# Plot counts
visualize_counts(counts, num_qubits, num_shots)
ขั้นตอนที่ 4: ประมวลผลหลังการรันและคืนผลลัพธ์ในรูปแบบ classical
- Input: การกระจายความน่าจะเป็น
- Output: ค่าเดียวในเมทริกซ์ kernel
คำนวณความน่าจะเป็นของการวัด บน overlap circuit และเติมค่าในเมทริกซ์ kernel ในตำแหน่งที่สอดคล้องกับตัวอย่างที่แทนด้วย overlap circuit นี้ (แถวที่ 15, คอลัมน์ที่ 20)
kernel_matrix[x1, x2] = counts.get(0, 0.0) / num_shots
print(f"Fidelity (simulator): {kernel_matrix[x1, x2]}")
Fidelity (simulator): 0.8261
ตัวอย่าง hardware
เมทริกซ์ quantum kernel มีค่า สำหรับตัวอย่างฝึก ตัวอย่าง และแต่ละค่าต้องการการรันวงจร overlap ที่มีความลึกของ two-qubit-gate เพิ่มขึ้นตามขนาดของ feature map ด้วยเหตุนี้ การขยายบทช่วยสอนนี้ไปสู่ปัญหาที่ใหญ่ขึ้นจึงมีต้นทุนสองส่วนที่ทบกัน: เวลา QPU ต่อเมทริกซ์ kernel เพิ่มขึ้นแบบกำลังสองกับ และความลึกของ unitary_overlap (ซึ่งประกอบ feature map กับ adjoint ของมัน) ลดความเที่ยงตรงที่ขนาดระบบและการเชื่อมต่อของ hardware ปัจจุบัน เพื่อให้การสาธิตสั้นและเปรียบเทียบได้อย่างชัดเจน เราจึงรันกรณีเจ็ด qubit เดียวกัน จากตัวอย่าง simulator บน QPU จริง และเปรียบเทียบ fidelity ของค่าเดียวในเมทริกซ์ kernel กับค่า simulator ที่คำนวณด้านบน
# ------------------------------ Step 1 ------------------------------
# Prepare training data
X_train = get_training_data()
# Empty kernel matrix
num_samples = np.shape(X_train)[0]
kernel_matrix = np.full((num_samples, num_samples), np.nan)
# Prepare feature map for computing overlap
num_features = np.shape(X_train)[1]
num_qubits = int(num_features / 2)
entangler_map = [[0, 2], [3, 4], [2, 5], [1, 4], [2, 3], [4, 6]]
fm = QuantumCircuit(num_qubits)
training_param = Parameter("θ")
feature_params = ParameterVector("x", num_qubits * 2)
fm.ry(training_param, fm.qubits)
for cz in entangler_map:
fm.cz(cz[0], cz[1])
for i in range(num_qubits):
fm.rz(-2 * feature_params[2 * i + 1], i)
fm.rx(-2 * feature_params[2 * i], i)
# Assign tunable parameter to known optimal value and
# set the data params for first two samples
x1 = 14
x2 = 19
unitary1 = fm.assign_parameters(list(X_train[x1]) + [np.pi / 2])
unitary2 = fm.assign_parameters(list(X_train[x2]) + [np.pi / 2])
# Create the overlap circuit
overlap_circ = unitary_overlap(unitary1, unitary2)
overlap_circ.measure_all()
# ------------------------------ Step 2 ------------------------------
service = QiskitRuntimeService()
# backend = service.least_busy(
# operational=True, simulator=False, min_num_qubits=overlap_circ.num_qubits
# )
backend = service.backend("ibm_pittsburgh")
print(f"Using backend: {backend.name}")
pm = generate_preset_pass_manager(optimization_level=3, backend=backend)
overlap_ibm = pm.run(overlap_circ)
# ------------------------------ Step 3 ------------------------------
sampler = Sampler(mode=backend)
sampler.options.environment.job_tags = ["TUT_QKT"]
num_shots = 10_000
results = sampler.run([overlap_ibm], shots=num_shots).result()
counts = results[0].data.meas.get_int_counts()
visualize_counts(counts, num_qubits, num_shots)
# ------------------------------ Step 4 ------------------------------
kernel_matrix[x1, x2] = counts.get(0, 0.0) / num_shots
print(f"Fidelity (hardware): {kernel_matrix[x1, x2]}")
Using backend: ibm_pittsburgh
Fidelity (hardware): 0.7517
เพื่อเติมเมทริกซ์ kernel ทั้งหมด เราต้องรันการทดลอง quantum สำหรับแต่ละค่า ที่ไม่ซ้ำกัน ภาพด้านล่างแสดงเมทริกซ์ที่ได้จากชุดข้อมูลนี้ โดยสีแดงเข้มขึ้นหมายถึง fidelity ที่ใกล้เคียง 1.0 มากขึ้น
ขั้นตอนต่อไป
ถ้าสนใจงานนี้ อาจสนใจเนื้อหาต่อไปนี้ด้วย:
- Quantum Kernel Training Toolkit - prototype repository ที่บทช่วยสอนนี้อ้างอิง
- Quantum Kernel Training for Machine Learning Applications - บทช่วยสอน Qiskit Machine Learning ที่แสดงวิธีฝึก trainable parameter
- Introduction to Quantum Machine Learning - คอร์สเกี่ยวกับ quantum machine learning
- Quantum Machine Learning from IBM Research - ภาพรวมงานวิจัย QML ของ IBM
- Covariant quantum kernels for data with group structure - บทความที่บทช่วยสอนนี้อ้างอิง