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

เคอร์เนลควอนตัม

บทนำเกี่ยวกับเคอร์เนลควอนตัม

"วิธีเคอร์เนลควอนตัม" หมายถึงวิธีการใดก็ตามที่ใช้คอมพิวเตอร์ควอนตัมในการประมาณค่าเคอร์เนล ในบริบทนี้ "เคอร์เนล" จะหมายถึงเมทริกซ์เคอร์เนลหรือสมาชิกแต่ละตัวในนั้น จำไว้ว่าการแมปฟีเจอร์ Φ(x)\Phi(\vec{x}) คือการแมปจาก xRd\vec{x}\in \mathbb{R}^d ไปยัง Φ(x)Rd,\Phi(\vec{x})\in \mathbb{R}^{d'}, โดยมักจะมี d>dd'>d และเป้าหมายของการแมปนี้คือทำให้หมวดหมู่ของข้อมูลสามารถแยกออกจากกันได้ด้วยไฮเปอร์เพลน ฟังก์ชันเคอร์เนลรับเวกเตอร์ในพื้นที่ที่ถูกแมปฟีเจอร์มาเป็นอาร์กิวเมนต์และคืนค่าผลคูณภายใน นั่นคือ K:Rd×RdRK:\mathbb{R}^d\times\mathbb{R}^d\rightarrow \mathbb{R} โดยที่ K(x,y)=Φ(x)Φ(y)K(x,y) = \langle \Phi(x)|\Phi(y)\rangle ในเชิงคลาสสิก เราสนใจการแมปฟีเจอร์ที่ทำให้ประเมินฟังก์ชันเคอร์เนลได้ง่าย ซึ่งมักหมายถึงการหาฟังก์ชันเคอร์เนลที่สามารถเขียนผลคูณภายในในพื้นที่ที่ถูกแมปฟีเจอร์ได้ในรูปของเวกเตอร์ข้อมูลต้นฉบับ โดยไม่ต้องสร้าง Φ(x)\Phi(x) และ Φ(y)\Phi(y) ก่อน ในวิธีเคอร์เนลควอนตัม การแมปฟีเจอร์ทำโดย Circuit ควอนตัม และเคอร์เนลจะถูกประมาณโดยใช้การวัดบน Circuit นั้นและความน่าจะเป็นสัมพัทธ์ของการวัด

ในบทเรียนนี้ เราจะสำรวจความลึกของ Circuit การเข้ารหัสที่เขียนไว้ล่วงหน้าซึ่งใช้การพัวพันอย่างมาก และเปรียบเทียบกับความลึกของ Circuit ที่เราเขียนเอง ไม่ใช่เพื่อสนับสนุนวิธีใดวิธีหนึ่ง คุณอาจพบว่า Circuit ที่เขียนไว้ล่วงหน้ามีความลึกมากเกินไป และการพัวพันใน Circuit ที่สร้างเองก็ไม่เพียงพอที่จะมีประโยชน์ สิ่งเหล่านี้แสดงขึ้นเพื่อให้คุณสามารถสำรวจได้เท่านั้น

ก่อนที่จะอธิบายขั้นตอนการประมาณเมทริกซ์เคอร์เนลโดยละเอียด มาสรุปขั้นตอนการทำงานโดยใช้ภาษาของ Qiskit patterns กัน

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

  • อินพุต: ชุดข้อมูลสำหรับฝึก
  • เอาต์พุต: Circuit นามธรรมสำหรับคำนวณค่าสมาชิกในเมทริกซ์เคอร์เนล

จากชุดข้อมูลที่มี จุดเริ่มต้นคือการเข้ารหัสข้อมูลลงใน Circuit ควอนตัม กล่าวคือเราต้องแมปข้อมูลไปยังปริภูมิฮิลเบิร์ตของสถานะในคอมพิวเตอร์ควอนตัม เราทำสิ่งนี้โดยสร้าง Circuit ที่ขึ้นกับข้อมูล มีหลายวิธีในการทำเช่นนี้ และบทเรียนก่อนหน้าได้สรุปตัวเลือกต่างๆ ไว้แล้ว คุณสามารถสร้าง Circuit เองเพื่อเข้ารหัสข้อมูล หรือใช้แผนที่ฟีเจอร์ที่สร้างไว้แล้วอย่าง zz_feature_map ในบทเรียนนี้ เราจะทำทั้งสองแบบ

โปรดทราบว่าในการคำนวณค่าสมาชิกเมทริกซ์เคอร์เนลเพียงค่าเดียว เราต้องการเข้ารหัสจุดสองจุดที่แตกต่างกัน เพื่อที่เราจะได้ประมาณผลคูณภายในได้ ขั้นตอนการทำงานของเคอร์เนลควอนตัมทั้งหมดจะเกี่ยวข้องกับผลคูณภายในระหว่างเวกเตอร์ข้อมูลที่ถูกแมปหลายค่า รวมถึงวิธีการเรียนรู้ของเครื่องแบบคลาสสิก แต่ขั้นตอนหลักที่ทำซ้ำคือการประมาณค่าสมาชิกเมทริกซ์เคอร์เนลเพียงค่าเดียว สำหรับสิ่งนี้เราเลือก Circuit ควอนตัมที่ขึ้นกับข้อมูล และแมปเวกเตอร์ข้อมูลสองตัวไปยังพื้นที่ฟีเจอร์

Classical_Review_background_kernel_circuit

สำหรับการสร้างเมทริกซ์เคอร์เนล เราสนใจเป็นพิเศษในความน่าจะเป็นของการวัดสถานะ 0N|0\rangle^{\otimes N} ซึ่ง Qubit ทั้ง NN ตัวอยู่ในสถานะ 0|0\rangle เพื่อให้เข้าใจสิ่งนี้ สมมติว่า Circuit ที่รับผิดชอบการเข้ารหัสและการแมปเวกเตอร์ข้อมูล xi\vec{x}_i สามารถเขียนเป็น Φ(xi)\Phi(\vec{x}_i) และ Circuit สำหรับเข้ารหัสและแมป xj\vec{x}_j คือ Φ(xj)\Phi(\vec{x}_j) และกำหนดสถานะที่ถูกแมปว่า

ψ(xi)=Φ(xi)0N|\psi(\vec{x}_i)\rangle = \Phi(\vec{x}_i)|0\rangle^{\otimes N} ψ(xj)=Φ(xj)0N.|\psi(\vec{x}_j)\rangle = \Phi(\vec{x}_j)|0\rangle^{\otimes N}.

สถานะเหล่านี้ คือ การแมปข้อมูลไปยังมิติที่สูงขึ้น ดังนั้นค่าสมาชิกเคอร์เนลที่เราต้องการคือผลคูณภายใน

ψ(xj)ψ(xi)=0NΦ(xj)Φ(xi)0N.\langle\psi(\vec{x}_j)|\psi(\vec{x}_i)\rangle = \langle 0 |^{\otimes N}\Phi^\dagger(\vec{x}_j)\Phi(\vec{x}_i)|0\rangle^{\otimes N}.

ถ้าเราดำเนินการบนสถานะเริ่มต้นดีฟอลต์ 0N|0\rangle^{\otimes N} ด้วย Circuit ทั้งสอง Φ(xj)\Phi^\dagger(\vec{x}_j) และ Φ(xi)\Phi(\vec{x}_i) ความน่าจะเป็นในการวัดสถานะ 0N|0\rangle^{\otimes N} คือ

P0=0NΦ(xj)Φ(xi)0N2.P_0 = |\langle0|^{\otimes N}\Phi^\dagger(\vec{x}_j)\Phi(\vec{x}_i)|0\rangle^{\otimes N}|^2.

นี่คือค่าที่เราต้องการ (ถึงค่า 2||^2) เลเยอร์การวัดของ Circuit จะคืนค่าความน่าจะเป็นของการวัด (หรือที่เรียกว่า "quasi-probabilities" หากใช้วิธีการลดข้อผิดพลาดบางอย่าง) ความน่าจะเป็นที่เราสนใจคือของสถานะศูนย์ 0N|0\rangle^{\otimes N}

ขั้นตอนที่ 2: ปรับปัญหาให้เหมาะสมสำหรับการประมวลผลควอนตัม

  • อินพุต: Circuit นามธรรม ที่ยังไม่ได้ปรับสำหรับ Backend เฉพาะ
  • เอาต์พุต: Circuit เป้าหมายและ observable ที่ปรับให้เหมาะสมกับ QPU ที่เลือก

ในขั้นตอนนี้ เราจะใช้ฟังก์ชัน generate_preset_pass_manager จาก Qiskit เพื่อกำหนดรูทีนการปรับให้เหมาะสมสำหรับ Circuit เทียบกับคอมพิวเตอร์ควอนตัมจริงที่เราวางแผนจะทดลอง เราตั้งค่า optimization_level=3 ซึ่งหมายความว่าเราจะใช้ preset pass manager ที่ให้ระดับการปรับสูงสุด ในบริบทนี้ "การปรับ" หมายถึงการปรับการนำ Circuit ไปใช้งานบนคอมพิวเตอร์ควอนตัมจริง ซึ่งรวมถึงการพิจารณาต่างๆ เช่น การเลือก Qubit ทางกายภาพที่จะลดความลึกของ Gate หรือการเลือก Qubit ทางกายภาพที่มีอัตราข้อผิดพลาดต่ำสุด ซึ่งไม่เกี่ยวข้องโดยตรงกับการปรับปัญหาการเรียนรู้ของเครื่อง (เช่น optimizer แบบคลาสสิกอย่าง COBYLA)

ขึ้นอยู่กับวิธีการที่คุณนำขั้นตอนที่ 2 ไปใช้ คุณอาจต้องปรับ Circuit มากกว่าหนึ่งครั้ง เนื่องจากแต่ละคู่ของจุดที่เกี่ยวข้องในสมาชิกเมทริกซ์จะสร้าง Circuit ที่แตกต่างกันสำหรับการวัด

ขั้นตอนที่ 3: ประมวลผลโดยใช้ Qiskit Runtime Primitives

  • อินพุต: Circuit เป้าหมาย
  • เอาต์พุต: การกระจายความน่าจะเป็น

ใช้ primitive Sampler จาก Qiskit Runtime เพื่อสร้างการกระจายความน่าจะเป็นของสถานะที่ได้จากการสุ่มตัวอย่าง Circuit โปรดทราบว่าคุณอาจเห็นสิ่งนี้เรียกว่า "quasi-probability distribution" ซึ่งเป็นคำที่ใช้ได้ในกรณีที่มีสัญญาณรบกวนและมีการนำขั้นตอนเพิ่มเติมมาใช้ เช่น ในการลดข้อผิดพลาด ในกรณีเหล่านี้ ผลรวมของความน่าจะเป็นทั้งหมดอาจไม่เท่ากับ 1 พอดี จึงเรียกว่า "quasi-probability"

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

  • อินพุต: การกระจายความน่าจะเป็น
  • เอาต์พุต: ค่าสมาชิกเมทริกซ์เคอร์เนลเพียงค่าเดียว หรือเมทริกซ์เคอร์เนลทั้งหมดหากทำซ้ำ

คำนวณความน่าจะเป็นของการวัด 0N|0\rangle^{\otimes N} บน Circuit ควอนตัม และเติมค่าเมทริกซ์เคอร์เนลในตำแหน่งที่สอดคล้องกับเวกเตอร์ข้อมูลสองตัวที่ใช้ เพื่อเติมเมทริกซ์เคอร์เนลทั้งหมด เราต้องทำการทดลองควอนตัมสำหรับแต่ละสมาชิก เมื่อมีเมทริกซ์เคอร์เนลแล้ว เราสามารถใช้ในอัลกอริทึมการเรียนรู้ของเครื่องแบบคลาสสิกหลายอย่างที่รับ pre-calculated kernels ตัวอย่างเช่น: qml_svc = SVC(kernel="precomputed") จากนั้นเราสามารถใช้ขั้นตอนการทำงานแบบคลาสสิกเพื่อนำโมเดลไปใช้กับข้อมูลทดสอบและได้คะแนนความแม่นยำ ขึ้นอยู่กับความพอใจของเราต่อคะแนนความแม่นยำ เราอาจต้องทบทวนส่วนต่างๆ ของการคำนวณ เช่น แผนที่ฟีเจอร์

โครงร่างบทเรียน

ในบทเรียนนี้ เราจะดำเนินการตามขั้นตอนเหล่านี้หลายวิธีเพื่อใช้เวลาบนคอมพิวเตอร์ควอนตัมจริงได้อย่างมีประสิทธิภาพ เราจะนำวิธีเคอร์เนลควอนตัมไปใช้กับ

  • ค่าสมาชิกเมทริกซ์เคอร์เนลเพียงค่าเดียวสำหรับข้อมูลที่มีฟีเจอร์จำนวนน้อย โดยใช้ Backend จริง เพื่อให้เราสามารถติดตามสิ่งที่เกิดขึ้นในแต่ละขั้นตอนได้ง่าย
  • ชุดข้อมูลทั้งหมดที่มีฟีเจอร์จำนวนน้อย โดยใช้ Backend จำลอง เพื่อให้เราเห็นว่าขั้นตอนการทำงานควอนตัมเชื่อมต่อกับวิธีการเรียนรู้ของเครื่องแบบคลาสสิกอย่างไร
  • ค่าสมาชิกเมทริกซ์เคอร์เนลเพียงค่าเดียวสำหรับข้อมูลที่มีฟีเจอร์จำนวนมาก โดยใช้คอมพิวเตอร์ควอนตัมจริง เราจะไม่ประมาณเมทริกซ์เคอร์เนลทั้งหมดสำหรับชุดข้อมูลขนาดใหญ่ เพื่อเคารพเวลาบนคอมพิวเตอร์ควอนตัมของ IBM®
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy pandas qiskit qiskit-ibm-runtime scikit-learn
# If you have not already, install scikit learn
#!pip install scikit-learn

ค่าสมาชิกเมทริกซ์เคอร์เนลเพียงค่าเดียว

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

มาเริ่มพิจารณาชุดข้อมูลที่มีฟีเจอร์เพียงไม่กี่ตัว สมมติว่า 10 ตัว ชุดข้อมูลสามารถมีขนาดใหญ่ตามต้องการ เนื่องจากเราคำนวณค่าสมาชิกเมทริกซ์เคอร์เนลทีละค่า เราต้องการอย่างน้อยสองจุด ดังนั้นเราจะเริ่มด้วยนั้น (ในตัวอย่างถัดไป เราจะนำเข้าชุดข้อมูลเต็มรูปแบบ) มาดึงแพ็กเกจที่จำเป็นไม่กี่ตัวก่อน:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# Two mock data points, including category labels, as in training
small_data = [
[-0.194, 0.114, -0.006, 0.301, -0.359, -0.088, -0.156, 0.342, -0.016, 0.143, 1],
[-0.1, 0.002, 0.244, 0.127, -0.064, -0.086, 0.072, 0.043, -0.053, 0.02, -1],
]

# Data points with labels removed, for inner product
train_data = [small_data[0][:-1], small_data[1][:-1]]

เราสามารถลองใช้ z_feature_map ได้

# from qiskit.circuit.library import zz_feature_map
# fm = zz_feature_map(feature_dimension=np.shape(train_data)[1], entanglement='linear', reps=1)

from qiskit.circuit.library import z_feature_map

fm = z_feature_map(feature_dimension=np.shape(train_data)[1])

unitary1 = fm.assign_parameters(train_data[0])
unitary2 = fm.assign_parameters(train_data[1])

ยูนิทารีสองตัวข้างต้นสอดคล้องกับ U1U_1 และ U2U_2 ที่อธิบายไว้ในบทนำ เราสามารถรวมกันโดยใช้ unitary_overlap และอย่างเคย เราต้องคอยดูความลึกของ Circuit เสมอ

from qiskit.circuit.library import unitary_overlap

overlap_circ = unitary_overlap(unitary1, unitary2)
overlap_circ.measure_all()

print("circuit depth = ", overlap_circ.decompose().depth())
overlap_circ.decompose().draw("mpl", scale=0.6, style="iqp")
circuit depth =  9

Output of the previous code cell

ขั้นตอนที่ 2: ปรับปัญหาให้เหมาะสมสำหรับการประมวลผลควอนตัม

เราเริ่มต้นด้วยการเลือก Backend ที่ว่างที่สุด จากนั้นปรับ Circuit ของเราสำหรับการรันบน Backend นั้น

# Import needed packages
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService

# Get the least busy backend
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=fm.num_qubits
)
print(backend)
<IBMBackend('ibm_brisbane')>
# Apply level 3 optimization to our overlap circuit
pm = generate_preset_pass_manager(optimization_level=3, backend=backend)
overlap_ibm = pm.run(overlap_circ)

สำหรับ Circuit ที่ซับซ้อน ขั้นตอนนี้จะเพิ่มความลึกของ Circuit อย่างมากเมื่อแมปไปยัง Gate แบบเนทีฟสำหรับคอมพิวเตอร์ควอนตัมจริง และข้อมูลอาจต้องถูกย้ายจาก Qubit หนึ่งไปยังอีก Qubit หนึ่ง ในกรณีง่ายๆ นี้ ความลึกแทบไม่ได้รับผลกระทบเลย

print("circuit depth = ", overlap_ibm.decompose().depth())
overlap_ibm.decompose().depth(lambda instr: len(instr.qubits) > 1)
circuit depth =  10
1

ขั้นตอนที่ 3: ประมวลผลโดยใช้ Qiskit Runtime Primitives

ซินแท็กซ์สำหรับการรันบนซิมูเลเตอร์ถูกแสดงเป็นคอมเมนต์ด้านล่าง สำหรับชุดข้อมูลนี้ที่มีฟีเจอร์จำนวนน้อย การรันบนซิมูเลเตอร์ยังเป็นตัวเลือกได้อยู่ สำหรับการคำนวณระดับ utility การจำลองมักไม่สามารถทำได้จริง ควรใช้ซิมูเลเตอร์เพื่อดีบักโค้ดในระดับขนาดเล็กเท่านั้น

# Run this for a simulator
# from qiskit.primitives import StatevectorSampler

# from qiskit_ibm_runtime import Options, Session, Sampler

# num_shots = 10000

# Evaluate the problem using state vector-based primitives from Qiskit
# sampler = StatevectorSampler()
# results = sampler.run([overlap_circ], shots=num_shots).result()
# .get_counts() returns counts associated with a state labeled by bit results such as |001101...01>.
# counts_bit = results[0].data.meas.get_counts()
# .get_int_counts returns the same counts, but labeled by integer equivalent of the above bit string.
# counts = results[0].data.meas.get_int_counts()
# Benchmarked on an Eagle processor, 7-11-24, took 4 sec.

# Import our runtime primitive
from qiskit_ibm_runtime import Session, SamplerV2 as Sampler

num_shots = 10000

# Use sampler and get the counts

sampler = Sampler(mode=backend)
results = sampler.run([overlap_ibm], shots=num_shots).result()
# .get_counts() returns counts associated with a state labeled by bit results such as |001101...01>.
counts_bit = results[0].data.meas.get_counts()
# .get_int_counts returns the same counts, but labeled by integer equivalent of the above bit string.
counts = results[0].data.meas.get_int_counts()

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

ตามที่อธิบายไว้ในบทนำ การวัดที่มีประโยชน์ที่สุดในที่นี้คือความน่าจะเป็นของการวัดสถานะศูนย์ 00000|00000\rangle

counts.get(0, 0.0) / num_shots
0.6525

นี่คือผลลัพธ์ที่เราต้องการ: การประมาณค่าผลคูณภายใน (ถึงค่า mod กำลังสอง) ของเวกเตอร์ที่สอดคล้องกับจุดข้อมูลสองจุด หากต้องการดูการกระจายความน่าจะเป็น (หรือ quasiprobability) ทั้งหมดของการวัด เราสามารถทำได้โดยใช้ฟังก์ชัน plot_distribution ดังที่แสดงด้านล่าง จะเห็นว่าสำหรับ Qubit จำนวนมาก ภาพเช่นนี้จะซับซ้อนเกินกว่าจะจัดการได้อย่างรวดเร็ว

from qiskit.visualization import plot_distribution

plot_distribution(counts_bit)

Output of the previous code cell

อีกทางหนึ่ง เราอาจกำหนดการแสดงผลแบบด้านล่างเพื่อดูเฉพาะ 10 การวัดที่มีความน่าจะเป็นสูงสุด ซึ่งอาจมีความสำคัญสำหรับการแก้ปัญหาหรือพยายามทำความเข้าใจข้อมูลให้ดีขึ้น แต่ความน่าจะเป็นการวัดของสถานะศูนย์คือค่าสมาชิกเมทริกซ์เคอร์เนลของเรา

def visualize_counts(probs, num_qubits):
"""Visualize the outputs from the Qiskit Sampler primitive."""
zero_prob = probs.get(0, 0.0)
top_10 = dict(sorted(probs.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]))
xvals, yvals = list(zip(*by_key.items()))
xvals = [bin(xval)[2:].zfill(num_qubits) for xval in xvals]
plt.bar(xvals, yvals)
plt.xticks(rotation=75)
plt.title("Results of sampling")
plt.xlabel("Measured bitstring")
plt.ylabel("Counts")
plt.show()

visualize_counts(counts, overlap_circ.num_qubits)

Output of the previous code cell

จากข้อมูลเกี่ยวกับผลคูณภายในระหว่างจุดข้อมูลสองจุดในพื้นที่ฟีเจอร์มิติสูงเพียงค่าเดียว สิ่งที่เราบอกได้คือการซ้อนทับของพวกมันค่อนข้างมากเมื่อเทียบกับการซ้อนทับสูงสุด (ซึ่งจะเป็น 1.0) นี่อาจเป็นตัวบ่งชี้ว่าจุดข้อมูลสองจุดนี้มีความคล้ายคลึงกันในบางลักษณะและจะถูกจัดหมวดหมู่ในกลุ่มเดียวกัน หรืออาจเป็นตัวบ่งชี้ว่าแผนที่ฟีเจอร์ของเราไม่มีประสิทธิภาพในการแมปไปยังพื้นที่ที่ข้อมูลที่คล้ายกันมีการซ้อนทับสูงและข้อมูลที่ต่างกันมีการซ้อนทับต่ำ เพื่อทราบว่าสิ่งใดเป็นจริง เราต้องนำแผนที่ฟีเจอร์ไปใช้กับชุดข้อมูลทั้งหมดและดูว่าเมทริกซ์เคอร์เนลที่ได้สามารถนำไปใช้แยกหมวดหมู่ด้วยความแม่นยำสูงได้หรือไม่

เป็นที่น่าสังเกตว่าเราใช้ z_feature_map ซึ่งทำให้ความลึก two-qubit transpiled ต่ำ (ความลึก 1 จริงๆ) หาก Circuit ของคุณลึกเกินไป จะทำให้มีสัญญาณรบกวนมาก ซึ่งจะทำให้ความน่าจะเป็นของการวัดสถานะศูนย์ต่ำมาก แม้ว่าแผนที่ฟีเจอร์ของคุณจะเหมาะกับข้อมูลก็ตาม ตัวอย่างเช่น การทำซ้ำกระบวนการข้างต้นโดยใช้ zz_feature_map และ , entanglement='linear', reps=1 ให้ผล dist.get(0,0.0) = 0.0015 โดยใช้จุดข้อมูลเดียวกัน ซึ่งเกิดจากความลึกของ Circuit และความลึก two-qubit ที่มากกว่าจาก zz_feature_map ภาพด้านล่างแสดงการกระจายความน่าจะเป็นสำหรับการคำนวณนั้น

Bad results from a zz feature map.

คุ้มค่าที่จะลองเล่นกับจุดข้อมูลไม่กี่จุดจากหมวดหมู่เดียวกันเพื่อดูว่าความลึกต้องน้อยแค่ไหนจึงจะได้ผลลัพธ์ที่ดี ต่อไปนี้คือคำแนะนำโดยประมาณที่แน่นอนว่ามีข้อยกเว้น โดยทั่วไปแล้ว ความลึก two-qubit transpiled ที่ 10 หรือต่ำกว่าไม่ควรมีปัญหา ความลึก two-qubit transpiled ที่ 50-60 ถือเป็นระดับ state-of-the-art และต้องใช้การลดข้อผิดพลาดขั้นสูงและเครื่องมืออื่นๆ ในระหว่างนั้น ผลลัพธ์ของคุณอาจแตกต่างกันตามความคล้ายคลึงของข้อมูล ความสามารถในการแสดงออกของแผนที่ฟีเจอร์ ความกว้างของ Circuit และปัจจัยอื่นๆ โดยปกติแล้ว ขั้นตอนการประมวลผลหลังการวัดยังรวมถึงกระบวนการเรียนรู้ของเครื่องแบบคลาสสิกด้วย ในส่วนถัดไป เราจะขยายกระบวนการนี้ไปยังชุดข้อมูลทั้งหมดและแสดงขั้นตอนการทำงานของการเรียนรู้ของเครื่องแบบคลาสสิก

ทดสอบความเข้าใจ

อ่านคำถามด้านล่าง คิดเกี่ยวกับคำตอบ แล้วคลิกที่สามเหลี่ยมเพื่อเปิดเผยคำตอบ

ใน Circuit ควอนตัม 10 Qubit โดยทั่วไปมีสถานะที่แตกต่างกันกี่สถานะที่อาจวัดได้?

คำตอบ:

2102^{10} หรือ 1024.

สมมติว่ามีคนที่เพิ่งเริ่มเรียนรู้การประมวลผลควอนตัมพยายามใช้ Circuit ควอนตัมที่มีความลึก two-qubit สูงมาก และไม่ใช้การลดข้อผิดพลาด สมมติต่อไปว่าผลลัพธ์คืออัตราข้อผิดพลาด 10% บนแต่ละ Qubit ถ้าค่าสมาชิกเมทริกซ์เคอร์เนลจริง (ปราศจากข้อผิดพลาด) ที่สอดคล้องกับ Circuit นี้มีค่ามากมาย สมมติว่า 1.0 ความน่าจะเป็นที่จะวัด Qubit ทั้ง 10 ตัวให้อยู่ในสถานะที่ทุก Qubit เป็น |0> จะเป็นเท่าไร?

คำตอบ:

ความน่าจะเป็นที่แต่ละ Qubit จะถูกพบในสถานะ |0> อย่างถูกต้องคือ 0.90 ความน่าจะเป็นที่ Qubit ทั้ง 10 ตัวจะถูกพบในสถานะที่ถูกต้องคือ 0.90100.90^{10} หรือประมาณ 35%

อธิบายด้วยคำพูดของคุณเองว่าทำไมการติดตามความลึกของ Circuit จึงสำคัญมาก สิ่งนี้เป็นความจริงโดยทั่วไป แต่อธิบายในบริบทของการประมาณเคอร์เนลควอนตัม

คำตอบ:

ในขั้นตอนการทำงาน QKE นี้ การประมาณของเราขึ้นอยู่กับการวัดของสถานะศูนย์ หมายความว่าสถานะที่ทุก Qubit ถูกพบในสถานะ 0|0\rangle Circuit ที่ลึกมากจะทำให้มีอัตราข้อผิดพลาดสูง เมื่ออัตราข้อผิดพลาดนั้นสะสมบน Qubit จำนวนมาก จะทำให้ความน่าจะเป็นของการวัดสถานะศูนย์ลดลงอย่างมาก

เมทริกซ์เคอร์เนลเต็มรูปแบบ

ในส่วนนี้ เราจะขยายกระบวนการข้างต้นไปยังการจำแนกประเภทไบนารีของชุดข้อมูลทั้งหมด สิ่งนี้จะนำเสนอสององค์ประกอบสำคัญ: (1) ตอนนี้เราสามารถนำการเรียนรู้ของเครื่องแบบคลาสสิกมาใช้ในขั้นตอนหลังการวัดได้ และ (2) เราสามารถได้คะแนนความแม่นยำสำหรับการฝึกของเรา

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

ตอนนี้เราจะนำเข้าชุดข้อมูลที่มีอยู่สำหรับการจำแนกประเภท ชุดข้อมูลนี้ประกอบด้วย 128 แถว (จุดข้อมูล) และ 14 ฟีเจอร์ในแต่ละจุด มีองค์ประกอบที่ 15 ที่บ่งบอกหมวดหมู่ไบนารีของแต่ละจุด (±1\pm 1) ชุดข้อมูลถูกนำเข้าด้านล่าง หรือคุณสามารถเข้าถึงชุดข้อมูลและดูโครงสร้าง ที่นี่

เราจะใช้จุดข้อมูล 90 จุดแรกสำหรับการฝึก และ 30 จุดถัดไปสำหรับการทดสอบ

!wget https://raw.githubusercontent.com/qiskit-community/prototype-quantum-kernel-training/main/data/dataset_graph7.csv

df = pd.read_csv("dataset_graph7.csv", sep=",", header=None)

# Prepare training data

train_size = 90
X_train = df.values[0:train_size, :-1]
train_labels = df.values[0:train_size, -1]

# Prepare testing data
test_size = 30
X_test = df.values[train_size : train_size + test_size, :-1]
test_labels = df.values[train_size : train_size + test_size, -1]
--2024-07-11 23:05:22--  https://raw.githubusercontent.com/qiskit-community/prototype-quantum-kernel-training/main/data/dataset_graph7.csv
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.110.133, 185.199.111.133, 185.199.109.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.110.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 49405 (48K) [text/plain]
Saving to: ‘dataset_graph7.csv.15’

dataset_graph7.csv. 100%[===================>] 48.25K --.-KB/s in 0.02s

2024-07-11 23:05:23 (2.11 MB/s) - ‘dataset_graph7.csv.15’ saved [49405/49405]

เราจะเตรียมการจัดเก็บเอาต์พุตหลายรายการล่วงหน้าโดยสร้างเมทริกซ์เคอร์เนลและเมทริกซ์ทดสอบที่มีขนาดเหมาะสม

# Empty kernel matrix
num_samples = np.shape(X_train)[0]
kernel_matrix = np.full((num_samples, num_samples), np.nan)
test_matrix = np.full((test_size, num_samples), np.nan)

ตอนนี้เราสร้างแผนที่ฟีเจอร์สำหรับการเข้ารหัสและแมปข้อมูลคลาสสิกใน Circuit ควอนตัม เราสามารถสร้างแผนที่ฟีเจอร์เองหรือใช้แผนที่ฟีเจอร์สำเร็จรูปได้ อย่าลังเลที่จะแก้ไขแผนที่ฟีเจอร์ด้านล่าง หรือสลับกลับไปใช้ ZFeatureMap แต่ให้ระวังความลึกของ Circuit เสมอ จำไว้ว่าในตัวอย่าง 6 Qubit ก่อนหน้า ความลึกของ Circuit transpiled มีค่าสูงเกินไปเมื่อใช้ zz_feature_map เมื่อขนาดและความซับซ้อนของ Circuit เพิ่มขึ้น ความลึกอาจเพิ่มขึ้นอย่างรวดเร็วจนสัญญาณรบกวนท่วมผลลัพธ์ของเรา เมื่อใดก็ตามที่คุณรู้บางอย่างเกี่ยวกับโครงสร้างข้อมูลที่อาจบอกว่าโครงสร้างแผนที่ฟีเจอร์ใดจะมีประโยชน์ที่สุด ขอแนะนำให้สร้างแผนที่ฟีเจอร์แบบกำหนดเองที่ใช้ความรู้นั้น

from qiskit.circuit import Parameter, ParameterVector, QuantumCircuit

# Prepare feature map for computing overlap
num_features = np.shape(X_train)[1]
num_qubits = int(num_features / 2)

# To use a custom feature map use the lines below.
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)

ขั้นตอนที่ 2 และ 3: ปรับปัญหาและประมวลผลโดยใช้ primitives

เราจะสร้าง Circuit overlap และถ้าเราจะรันบนคอมพิวเตอร์ควอนตัมจริงในตัวอย่างนี้ เราจะปรับให้เหมาะสมสำหรับการประมวลผลเหมือนก่อนหน้า แต่ในกรณีนี้ เราตั้งใจจะผ่านจุดข้อมูลทั้งหมดและคำนวณเมทริกซ์เคอร์เนลเต็มรูปแบบ สำหรับแต่ละคู่ของเวกเตอร์ข้อมูล xi\vec{x}_i และ xj\vec{x}_j เราสร้าง Circuit overlap ที่แตกต่างกัน ดังนั้นเราต้องปรับ Circuit สำหรับแต่ละคู่จุดข้อมูล ดังนั้นขั้นตอนที่ 2 และ 3 จะทำร่วมกันในการวนซ้ำหลายครั้ง

เซลล์โค้ดด้านล่างทำกระบวนการเดิมทุกอย่างสำหรับคู่จุดข้อมูลเดียว ครั้งนี้เพียงแต่ทำซ้ำภายใน for loop สองวง และมีบรรทัดเพิ่มเติมในตอนท้าย kernel_matrix[x_1,x_2] = ... เพื่อเก็บผลลัพธ์ของแต่ละการคำนวณ โปรดทราบว่าเราได้ใช้ประโยชน์จากความสมมาตรของเมทริกซ์เคอร์เนลเพื่อลดจำนวนการคำนวณลง 1/2 นอกจากนี้ เราได้ตั้งค่าองค์ประกอบแนวทแยงให้เป็น 1 ตามที่ควรเป็นโดยไม่มีสัญญาณรบกวน ขึ้นอยู่กับการนำไปใช้งานและความแม่นยำที่ต้องการ คุณยังสามารถใช้องค์ประกอบแนวทแยงเพื่อประมาณสัญญาณรบกวนหรือเรียนรู้เกี่ยวกับมันสำหรับวัตถุประสงค์การลดข้อผิดพลาด

เมื่อเมทริกซ์เคอร์เนลถูกเติมเต็มแล้ว เราจะทำกระบวนการซ้ำสำหรับข้อมูลทดสอบและเติม test_matrix ซึ่งเป็นเมทริกซ์เคอร์เนลเช่นกัน เราเพียงแต่ให้ชื่อต่างกันเพื่อแยกแยะทั้งสอง

# To use a simulator
from qiskit.primitives import StatevectorSampler

# Remember to insert your token in the QiskitRuntimeService constructor to use real quantum computers
# service = QiskitRuntimeService()
# backend = service.least_busy(
# operational=True, simulator=False, min_num_qubits=fm.num_qubits
# )

num_shots = 10000

# Evaluate the problem using state vector-based primitives from Qiskit.
sampler = StatevectorSampler()

for x1 in range(0, train_size):
for x2 in range(x1 + 1, train_size):
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()

# These lines run the qiskit sampler primitive.
counts = (
sampler.run([overlap_circ], shots=num_shots)
.result()[0]
.data.meas.get_int_counts()
)

# Assign the probability of the 0 state to the kernel matrix, and the transposed element (since this is an inner product)
kernel_matrix[x1, x2] = counts.get(0, 0.0) / num_shots
kernel_matrix[x2, x1] = counts.get(0, 0.0) / num_shots
# Fill in on-diagonal elements with 1, again, since this is an inner-product corresponding to probability (or alter the code to check these entries and verify they yield 1)
kernel_matrix[x1, x1] = 1

print("training done")

# Similar process to above, but for testing data.
for x1 in range(0, test_size):
for x2 in range(0, train_size):
unitary1 = fm.assign_parameters(list(X_test[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()

counts = (
sampler.run([overlap_circ], shots=num_shots)
.result()[0]
.data.meas.get_int_counts()
)

test_matrix[x1, x2] = counts.get(0, 0.0) / num_shots

print("test matrix done")
training done
test matrix done

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

ตอนนี้ที่เรามีเมทริกซ์เคอร์เนลและ test_matrix ที่มีรูปแบบคล้ายกันจากวิธีเคอร์เนลควอนตัม เราสามารถนำอัลกอริทึมการเรียนรู้ของเครื่องแบบคลาสสิกมาทำนายข้อมูลทดสอบและตรวจสอบความแม่นยำได้ เราจะเริ่มด้วยการนำเข้า sklearn.svc ของ Scikit-Learn ซึ่งเป็น support vector classifier (SVC) เราต้องระบุว่าต้องการให้ SVC ใช้เคอร์เนลที่คำนวณไว้ล่วงหน้าโดยใช้ kernel = precomputed

# import a support vector classifier from a classical ML package.
from sklearn.svm import SVC

# Specify that you want to use a pre-computed kernel matrix
qml_svc = SVC(kernel="precomputed")

โดยใช้ SVC.fit เราสามารถป้อนเมทริกซ์เคอร์เนลและ label การฝึกเพื่อได้การ fit SVC.score จะให้คะแนนข้อมูลทดสอบเทียบกับการ fit นั้นโดยใช้ test_matrix และคืนค่าความแม่นยำ

# Feed in the pre-computed matrix and the labels of the training data. The classical algorithm gives you a fit.
qml_svc.fit(kernel_matrix, train_labels)

# Now use the .score to test your data, using the matrix of test data, and test labels as your inputs.
qml_score_precomputed_kernel = qml_svc.score(test_matrix, test_labels)
print(f"Precomputed kernel classification test score: {qml_score_precomputed_kernel}")
Precomputed kernel classification test score: 1.0

เราเห็นว่าความแม่นยำของโมเดลที่ฝึกแล้วอยู่ที่ 100% ซึ่งเป็นเรื่องดีและแสดงให้เห็นว่า QKE สามารถทำงานได้ แต่นั่นแตกต่างมากจากข้อได้เปรียบเชิงควอนตัม เคอร์เนลแบบคลาสสิกน่าจะสามารถแก้ปัญหาการจำแนกประเภทนี้ด้วยความแม่นยำ 100% ได้เช่นกัน ยังมีงานอีกมากในการกำหนดลักษณะประเภทข้อมูลและความสัมพันธ์ของข้อมูลต่างๆ เพื่อดูว่าเคอร์เนลควอนตัมจะมีประโยชน์มากที่สุดในยุค utility ปัจจุบัน เราปล่อยให้ผู้เรียนแก้ไขส่วนต่างๆ ของขั้นตอนการทำงานนี้และศึกษาประสิทธิภาพของแผนที่ฟีเจอร์ควอนตัมต่างๆ ต่อไปนี้คือสิ่งที่ควรพิจารณา:

  • ความแม่นยำมีความแข็งแกร่งแค่ไหน? มันคงที่สำหรับข้อมูลประเภทต่างๆ หรือเฉพาะข้อมูลการฝึกนี้เท่านั้น?
  • โครงสร้างใดในข้อมูลของคุณทำให้คุณสงสัยว่าแผนที่ฟีเจอร์ควอนตัมมีประโยชน์?
  • ความแม่นยำได้รับผลกระทบอย่างไรจากการเพิ่ม/ลดจำนวนข้อมูลการฝึก?
  • แผนที่ฟีเจอร์ใดที่คุณสามารถใช้ได้และผลลัพธ์แตกต่างกันอย่างไรตามแผนที่ฟีเจอร์?
  • ความแม่นยำและเวลาในการรันได้รับผลกระทบอย่างไรจากการเพิ่มจำนวนฟีเจอร์?
  • แนวโน้มใด ถ้ามี ที่คุณคาดว่าจะคงอยู่บนคอมพิวเตอร์ควอนตัมจริง?

การขยายไปยังฟีเจอร์และ Qubit จำนวนมากขึ้น

ในส่วนนี้ เราจะทำซ้ำการคำนวณค่าสมาชิกเมทริกซ์เพียงค่าเดียว แต่สำหรับจำนวนฟีเจอร์ที่มากขึ้นอย่างมาก เพื่อร่างเส้นทางในการขยายไปสู่ระดับ utility การจำกัดให้เหลือค่าสมาชิกเมทริกซ์เพียงค่าเดียวเพื่อให้สามารถแสดงกระบวนการได้โดยไม่ต้องใช้เวลาบนคอมพิวเตอร์ควอนตัมที่จัดสรรมากเกินไป

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

เราจะสมมติจุดเริ่มต้นของชุดข้อมูลที่แต่ละจุดข้อมูลมี 42 ฟีเจอร์ เช่นเดียวกับตัวอย่างแรก เราจะคำนวณค่าสมาชิกเมทริกซ์เคอร์เนลเพียงค่าเดียว ซึ่งต้องใช้จุดข้อมูลสองจุด จุดสองจุดด้านล่างมี 42 ฟีเจอร์และตัวแปรหมวดหมู่เดียว (±1\pm 1)

# Two mock data points, including category labels, as in training

large_data = [
[
-0.028,
-1.49,
-1.698,
0.107,
-1.536,
-1.538,
-1.356,
-1.514,
-0.109,
-1.8,
-0.122,
-1.651,
-1.955,
-0.123,
-1.732,
0.091,
-0.048,
-0.128,
-0.026,
0.082,
-1.263,
0.065,
0.004,
-0.055,
-0.08,
-0.173,
-1.734,
-0.39,
-1.451,
0.078,
-1.578,
-0.025,
-0.184,
-0.119,
-1.336,
0.055,
-0.204,
-1.578,
0.132,
-0.121,
-1.599,
-0.187,
-1,
],
[
-1.414,
-1.439,
-1.606,
0.246,
-1.673,
0.002,
-1.317,
-1.262,
-0.178,
-1.814,
0.013,
-1.619,
-1.86,
-0.25,
-0.212,
-0.214,
-0.033,
0.071,
-0.11,
-1.607,
0.441,
-0.143,
-0.009,
-1.655,
-1.579,
0.381,
-1.86,
-0.079,
-0.088,
-0.058,
-1.481,
-0.064,
-0.065,
-1.507,
0.177,
-0.131,
-0.153,
0.07,
-1.627,
0.593,
-1.547,
-0.16,
-1,
],
]
train_data = [large_data[0][:-1], large_data[1][:-1]]

จำไว้ว่า zz_feature_map สร้าง Circuit ที่ค่อนข้างลึกในกรณีที่มีฟีเจอร์จำนวนน้อย (14 ฟีเจอร์) เมื่อเราเพิ่มจำนวนฟีเจอร์ เราต้องติดตามความลึกของ Circuit อย่างใกล้ชิด เพื่อแสดงให้เห็นสิ่งนี้ เราจะลองใช้ zz_feature_map ก่อนและตรวจสอบความลึกของ Circuit ที่ได้

from qiskit.circuit.library import zz_feature_map

fm = zz_feature_map(
feature_dimension=np.shape(train_data)[1], entanglement="linear", reps=1
)

unitary1 = fm.assign_parameters(train_data[0])
unitary2 = fm.assign_parameters(train_data[1])
from qiskit.circuit.library import unitary_overlap

overlap_circ = unitary_overlap(unitary1, unitary2)
overlap_circ.measure_all()

print("circuit depth = ", overlap_circ.decompose(reps=2).depth())
print(
"two-qubit depth",
overlap_circ.decompose().depth(lambda instr: len(instr.qubits) > 1),
)
# overlap_circ.draw("mpl", scale=0.6, style="iqp")
circuit depth =  251
two-qubit depth 165

ตามที่อธิบายไว้ก่อนหน้า การกำหนดว่าลึกแค่ไหนถือว่ามากเกินไปนั้นมีความซับซ้อน แต่ความลึก two-qubit ที่มากกว่า 100 แม้ก่อนการ transpilation ก็เป็นสิ่งที่เริ่มต้นไม่ได้ นี่คือเหตุผลที่เน้นแผนที่ฟีเจอร์แบบกำหนดเองตลอดบทเรียนนี้ หากคุณรู้บางอย่างเกี่ยวกับโครงสร้างของชุดข้อมูลทั้งหมด คุณควรออกแบบแผนที่ entanglement โดยคำนึงถึงโครงสร้างนั้น ที่นี่ เนื่องจากเราคำนวณผลคูณภายในระหว่างจุดข้อมูลสองจุดเท่านั้น เราได้ให้ความสำคัญกับความลึกของ Circuit ต่ำมากกว่าการพิจารณาโครงสร้างข้อมูลโดยละเอียด

from qiskit.circuit import Parameter, ParameterVector, QuantumCircuit

# Prepare feature map for computing overlap

entangler_map = [
[3, 4],
[2, 5],
[1, 4],
[2, 3],
[4, 6],
[7, 9],
[10, 11],
[9, 12],
[8, 11],
[9, 10],
[11, 13],
[14, 16],
[17, 18],
[16, 19],
[15, 18],
[16, 17],
[18, 20],
]
# Use the entangler map above to build a feature map

num_features = np.shape(train_data)[1]
num_qubits = int(num_features / 2)

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)
from qiskit.circuit.library import unitary_overlap

# Assign features of each data point to a unitary, an instance of the general feature map.

unitary1 = fm.assign_parameters(list(train_data[0]) + [np.pi / 2])
unitary2 = fm.assign_parameters(list(train_data[1]) + [np.pi / 2])

# Create the overlap circuit

overlap_circ = unitary_overlap(unitary1, unitary2)
overlap_circ.measure_all()

เราจะไม่ตรวจสอบความลึกตอนนี้ เนื่องจากสิ่งที่สำคัญจริงๆ คือความลึก two-qubit transpiled

ขั้นตอนที่ 2: ปรับปัญหาให้เหมาะสมสำหรับการประมวลผลควอนตัม

เราเริ่มต้นด้วยการเลือก Backend ที่ว่างที่สุด จากนั้นปรับ Circuit ของเราสำหรับการรันบน Backend นั้น

# Import needed packages
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService

# Get the least busy backend
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=fm.num_qubits
)
print(backend)
<IBMBackend('ibm_brisbane')>

สำหรับงานขนาดเล็ก preset pass manager มักจะคืน Circuit เดิมที่มีความลึกเท่าเดิมอย่างน่าเชื่อถือ แต่ใน Circuit ที่ใหญ่และซับซ้อนมาก pass manager อาจคืน Circuit transpiled ที่แตกต่างกันในแต่ละครั้ง เนื่องจากใช้ heuristics และเพราะว่า Circuit ขนาดใหญ่มากจะมีภูมิทัศน์ของการปรับที่เป็นไปได้ที่ซับซ้อน มักมีประโยชน์ที่จะทำการ transpile หลายครั้งและใช้ Circuit ที่ตื้นที่สุด สิ่งนี้เพิ่มเฉพาะ overhead แบบคลาสสิกและอาจปรับปรุงผลลัพธ์จากคอมพิวเตอร์ควอนตัมได้อย่างมาก

ที่นี่ เราทำการ transpile Circuit overlap unitary 20 ครั้ง และดูความลึกของ Circuit ที่ได้

# Apply level 3 optimization to our overlap circuit
transpiled_qcs = []
transpiled_depths = []
transpiled_twoqubit_depths = []
for i in range(1, 20):
pm = generate_preset_pass_manager(optimization_level=3, backend=backend)
overlap_ibm = pm.run(overlap_circ)
transpiled_qcs.append(overlap_ibm)
transpiled_depths.append(overlap_ibm.decompose().depth())
transpiled_twoqubit_depths.append(
overlap_ibm.decompose().depth(lambda instr: len(instr.qubits) > 1)
)

print("circuit depth = ", overlap_ibm.decompose().depth())
circuit depth =  61
print(transpiled_depths)
print(transpiled_twoqubit_depths)
[61, 60, 60, 69, 60, 60, 60, 65, 60, 60, 69, 61, 77, 77, 65, 60, 60, 77, 61]
[13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13]

ที่นี่คุณจะเห็นว่ามีความแตกต่างในความลึกของ Gate ทั้งหมดกับการ transpilation ที่แตกต่างกัน Circuit ของเรายังไม่ลึก/กว้างพอที่จะเห็นความแตกต่างในความลึก two-qubit transpiled เราจะใช้ transpiled_qcs[1] ซึ่งมีความลึก 60 ซึ่งต่ำกว่าความลึกของ Circuit ที่ลึกที่สุดที่ได้คือ 77 เล็กน้อย

overlap_ibm = transpiled_qcs[1]

ขั้นตอนที่ 3: ประมวลผลโดยใช้ Qiskit Runtime Primitives

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

# Run on ibm_osaka, 7-12-24, required 22 sec.

# Import our runtime primitive
from qiskit_ibm_runtime import SamplerV2 as Sampler

# Open a Runtime session:
session = Session(backend=backend)
num_shots = 10000
# Use sampler and get the counts

sampler = Sampler(mode=session)
options = sampler.options
options.dynamical_decoupling.enable = True
options.twirling.enable_gates = True
counts = (
sampler.run([overlap_ibm], shots=num_shots).result()[0].data.meas.get_int_counts()
)

# Close session after done
session.close()

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

ตามที่อธิบายไว้ในบทนำ การวัดที่มีประโยชน์ที่สุดในที่นี้คือความน่าจะเป็นของการวัดสถานะศูนย์ 00000|00000\rangle

counts.get(0, 0.0) / num_shots
0.0138

กระบวนการสำหรับค่าสมาชิกเมทริกซ์เคอร์เนลเพียงค่าเดียวนี้สามารถทำซ้ำระหว่างคู่ข้อมูลอื่นๆ ในชุดข้อมูลของคุณเพื่อได้เมทริกซ์เคอร์เนลเต็มรูปแบบ มิติของเมทริกซ์เคอร์เนลถูกกำหนดโดยจำนวนจุดในข้อมูลการฝึก ไม่ใช่จำนวนฟีเจอร์ ดังนั้นต้นทุนการคำนวณในการจัดการเมทริกซ์เคอร์เนลให้เป็นโมเดลเชิงพยากรณ์จะไม่ขยายตามจำนวนฟีเจอร์หรือ Qubit แม้สำหรับชุดข้อมูลขนาดค่อนข้างเล็กที่มีฟีเจอร์จำนวนมาก ข้อมูลก็ยังต้องถูกจับคู่กับแผนที่ฟีเจอร์ที่ให้การจำแนกประเภทที่มีประสิทธิภาพ

การขยายและงานในอนาคต

วิธีเคอร์เนลต้องการให้เราวัด 0|0\rangle ได้อย่างแม่นยำที่สุด แต่ข้อผิดพลาดของ Gate และข้อผิดพลาดการอ่านค่าหมายความว่ามีความน่าจะเป็นที่ไม่เป็นศูนย์ pp ที่ Qubit ใดๆ จะถูกวัดผิดพลาดให้อยู่ในสถานะ 1|1\rangle แม้จะมีการทำให้ง่ายขึ้นว่าความน่าจะเป็นของ 0|0\rangle ควรเป็น 100% สำหรับฟีเจอร์จำนวนมากที่เข้ารหัสบน NN บิต ความน่าจะเป็นของการวัดบิตทั้งหมดให้เป็น 0|0\rangle อย่างถูกต้องจะลดลงเหลือ (1p)N(1-p)^N เมื่อ NN มีขนาดใหญ่ขึ้น วิธีการนี้จะเชื่อถือได้น้อยลงและน้อยลง การเอาชนะความยากลำบากนี้และขยายการประมาณเคอร์เนลไปสู่ฟีเจอร์มากขึ้นเรื่อยๆ เป็นพื้นที่ของการวิจัยปัจจุบัน หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับปัญหานี้ ดูงานของ Thanasilp, Wang, Cerezo, and Holmes. เราแนะนำให้คุณสำรวจสิ่งที่สามารถทำได้กับคอมพิวเตอร์ควอนตัมปัจจุบัน และมองไปข้างหน้าถึงสิ่งที่จะเป็นไปได้ในยุคของการแก้ไขข้อผิดพลาด

ทบทวน

การคำนวณเคอร์เนลควอนตัมเกี่ยวข้องกับ

  • การคำนวณค่าสมาชิกเมทริกซ์เคอร์เนล โดยใช้คู่จุดข้อมูลการฝึก
  • การเข้ารหัสข้อมูลและแมปผ่านการแมปฟีเจอร์
  • การปรับ Circuit ของคุณสำหรับการรันบนคอมพิวเตอร์ควอนตัม/Backend จริง

เคอร์เนลควอนตัมสามารถนำไปใช้ในอัลกอริทึมการเรียนรู้ของเครื่องแบบคลาสสิกได้ ดังที่แสดงในบทเรียนนี้

สิ่งสำคัญที่ควรคำนึงเมื่อใช้เคอร์เนลควอนตัม:

  • ชุดข้อมูลน่าจะได้ประโยชน์จากวิธีเคอร์เนลควอนตัมหรือไม่?
  • ลองใช้แผนที่ฟีเจอร์และรูปแบบ entanglement ต่างๆ
  • ความลึกของ Circuit เป็นที่ยอมรับได้หรือไม่?
  • ลองรัน pass manager หลายครั้งและใช้ Circuit ที่มีความลึกน้อยที่สุดที่คุณหาได้

วิธีเคอร์เนลควอนตัมเป็นเครื่องมือที่มีศักยภาพสูงเมื่อมีการจับคู่ที่เหมาะสมระหว่างชุดข้อมูลที่มีฟีเจอร์ที่เหมาะกับควอนตัมและแผนที่ฟีเจอร์ควอนตัมที่เหมาะสม หากต้องการเข้าใจดีขึ้นว่าเคอร์เนลควอนตัมจะมีประโยชน์ที่ใด แนะนำให้อ่าน Liu, Arunachalam & Temme (2021)

Source: IBM Quantum docs — updated 17 เม.ย. 2569
English version on doQumentation — updated 7 พ.ค. 2569
This translation based on the English version of approx. 26 มี.ค. 2569