Lewati ke konten utama

Kernel Kuantum

Pengenalan kernel kuantum

"Metode kernel kuantum" mengacu pada metode apa pun yang menggunakan komputer kuantum untuk mengestimasi sebuah kernel. Dalam konteks ini, "kernel" mengacu pada matriks kernel atau entri individual di dalamnya. Ingat bahwa pemetaan fitur Φ(x)\Phi(\vec{x}) adalah pemetaan dari xRd\vec{x}\in \mathbb{R}^d ke Φ(x)Rd,\Phi(\vec{x})\in \mathbb{R}^{d'}, di mana biasanya d>dd'>d dan tujuan pemetaan ini adalah membuat kategori data dapat dipisahkan oleh sebuah hyperplane. Fungsi kernel mengambil vektor dalam ruang yang telah dipetakan fiturnya sebagai argumen dan mengembalikan hasil kali dalam mereka, yaitu K:Rd×RdRK:\mathbb{R}^d\times\mathbb{R}^d\rightarrow \mathbb{R} dengan K(x,y)=Φ(x)Φ(y)K(x,y) = \langle \Phi(x)|\Phi(y)\rangle. Secara klasik, kita tertarik pada pemetaan fitur yang fungsi kernelnya mudah dievaluasi. Ini sering berarti menemukan fungsi kernel yang hasil kali dalamnya di ruang yang dipetakan fitur bisa ditulis dalam bentuk vektor data asli, tanpa perlu membangun Φ(x)\Phi(x) dan Φ(y)\Phi(y). Dalam metode kernel kuantum, pemetaan fitur dilakukan oleh Circuit kuantum, dan kernel diestimasi menggunakan pengukuran pada Circuit tersebut beserta probabilitas pengukuran relatifnya.

Dalam pelajaran ini kita akan memeriksa kedalaman Circuit encoding yang sudah dikodekan sebelumnya yang menggunakan entanglement substansial dan membandingkannya dengan kedalaman Circuit yang kita kodekan sendiri. Ini bukan untuk mengadvokasi satu metode di atas yang lain. Kamu mungkin menemukan bahwa Circuit yang sudah dikodekan terlalu dalam, dan entanglement dalam Circuit yang dibuat sendiri tidak cukup untuk berguna. Lagi-lagi, ini ditunjukkan hanya untuk memungkinkan eksplorasi kamu.

Sebelum menelusuri estimasi matriks kernel secara detail, mari kita uraikan alur kerja menggunakan bahasa pola Qiskit.

Langkah 1: Pemetaan input klasik ke masalah kuantum

  • Input: Dataset pelatihan
  • Output: Circuit abstrak untuk menghitung entri matriks kernel

Dengan dataset yang ada, titik awalnya adalah mengkodekan data ke dalam Circuit kuantum. Dengan kata lain, kita perlu memetakan data kita ke dalam ruang Hilbert dari state komputer kuantum kita. Kita melakukan ini dengan membangun Circuit yang bergantung pada data. Ada banyak cara melakukan ini, dan pelajaran sebelumnya menguraikan sejumlah pilihan. Kamu bisa membangun Circuit sendiri untuk mengkodekan data, atau menggunakan peta fitur yang sudah jadi seperti zz_feature_map. Dalam pelajaran ini, kita akan melakukan keduanya.

Perlu diingat bahwa untuk menghitung satu elemen matriks kernel, kita perlu mengkodekan dua titik yang berbeda, sehingga kita bisa mengestimasi hasil kali dalamnya. Alur kerja kernel kuantum penuh tentu saja melibatkan banyak hasil kali dalam antara vektor data yang dipetakan, serta metode machine learning klasik. Namun langkah inti yang diiterasi adalah estimasi satu elemen matriks kernel. Untuk ini kita pilih Circuit kuantum yang bergantung pada data dan memetakan dua vektor data ke dalam ruang fitur.

Classical_Review_background_kernel_circuit

Untuk tugas menghasilkan matriks kernel, kita sangat tertarik pada probabilitas mengukur state 0N|0\rangle^{\otimes N}, di mana semua NN Qubit berada dalam state 0|0\rangle. Untuk memahami ini, pertimbangkan bahwa Circuit yang bertanggung jawab untuk encoding dan pemetaan satu vektor data xi\vec{x}_i dapat ditulis sebagai Φ(xi)\Phi(\vec{x}_i), dan yang bertanggung jawab untuk encoding dan pemetaan xj\vec{x}_j adalah Φ(xj)\Phi(\vec{x}_j), dan notasikan state yang dipetakan sebagai

ψ(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}.

State-state ini adalah pemetaan data ke dimensi yang lebih tinggi, sehingga entri kernel yang kita inginkan adalah hasil kali dalam

ψ(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}.

Jika kita mengoperasikan state awal default 0N|0\rangle^{\otimes N} dengan kedua Circuit Φ(xj)\Phi^\dagger(\vec{x}_j) dan Φ(xi)\Phi(\vec{x}_i), probabilitas mengukur state 0N|0\rangle^{\otimes N} adalah

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

Ini persis nilai yang kita inginkan (hingga 2||^2). Lapisan pengukuran Circuit kita akan mengembalikan probabilitas pengukuran (atau yang disebut "kuasi-probabilitas", jika metode mitigasi error tertentu digunakan). Probabilitas yang menjadi perhatian kita adalah probabilitas state nol, 0N|0\rangle^{\otimes N}.

Langkah 2: Optimasi masalah untuk eksekusi kuantum

  • Input: Circuit abstrak, belum dioptimalkan untuk Backend tertentu
  • Output: Circuit target dan observable, dioptimalkan untuk QPU yang dipilih

Dalam langkah ini, kita akan menggunakan fungsi generate_preset_pass_manager dari Qiskit untuk menentukan rutinitas optimasi untuk Circuit kita sehubungan dengan komputer kuantum nyata yang kita rencanakan untuk menjalankan eksperimen. Kita mengatur optimization_level=3, yang berarti kita akan menggunakan pass manager preset yang memberikan tingkat optimasi tertinggi. Dalam konteks ini, "optimasi" mengacu pada pengoptimalan implementasi Circuit pada komputer kuantum nyata. Ini mencakup pertimbangan seperti memilih Qubit fisik yang sesuai dengan Qubit dalam Circuit kuantum abstrak yang akan meminimalkan kedalaman Gate, atau memilih Qubit fisik dengan tingkat error terendah yang tersedia. Ini tidak secara langsung terkait dengan optimasi masalah machine learning (seperti optimizer klasik seperti COBYLA).

Tergantung pada bagaimana kamu mengimplementasikan langkah 2, kamu mungkin harus mengoptimalkan Circuit lebih dari sekali, karena setiap pasang titik yang terlibat dalam elemen matriks menghasilkan Circuit berbeda yang perlu diukur.

Langkah 3: Eksekusi menggunakan Qiskit Runtime Primitives

  • Input: Circuit target
  • Output: Distribusi probabilitas

Gunakan primitive Sampler dari Qiskit Runtime untuk merekonstruksi distribusi probabilitas state yang dihasilkan dari sampling Circuit. Perhatikan bahwa kamu mungkin melihat ini disebut sebagai "distribusi kuasi-probabilitas", istilah yang berlaku di mana noise menjadi masalah dan ketika langkah-langkah tambahan diperkenalkan, seperti dalam mitigasi error. Dalam kasus seperti itu, jumlah semua probabilitas mungkin tidak persis sama dengan 1; oleh karena itu "kuasi-probabilitas".

Langkah 4: Post-processing, kembalikan hasil dalam format klasik

  • Input: Distribusi probabilitas
  • Output: Satu elemen matriks kernel, atau matriks kernel jika diulang

Hitung probabilitas mengukur 0N|0\rangle^{\otimes N} pada Circuit kuantum, dan isi matriks kernel pada posisi yang sesuai dengan dua vektor data yang digunakan. Untuk mengisi seluruh matriks kernel, kita perlu menjalankan eksperimen kuantum untuk setiap entri. Setelah kita memiliki matriks kernel, kita bisa menggunakannya dalam banyak algoritma machine learning klasik yang menerima pre-calculated kernels. Misalnya: qml_svc = SVC(kernel="precomputed"). Kita kemudian bisa menggunakan alur kerja klasik untuk menerapkan model kita pada data pengujian, dan mendapatkan skor akurasi. Bergantung pada kepuasan kita dengan skor akurasi, kita mungkin perlu meninjau kembali aspek-aspek perhitungan kita, seperti peta fitur kita.

Garis besar pelajaran

Dalam pelajaran ini kita akan melakukan langkah-langkah ini dengan beberapa cara untuk memanfaatkan waktu kamu secara optimal pada komputer kuantum nyata. Kita akan menerapkan metode kernel kuantum pada

  • Satu entri matriks kernel untuk data dengan relatif sedikit fitur, menggunakan Backend nyata, sehingga kita bisa dengan mudah mengikuti apa yang terjadi di setiap langkah.
  • Seluruh dataset dengan relatif sedikit fitur, menggunakan Backend simulasi, sehingga kita bisa melihat bagaimana alur kerja kuantum terhubung dengan metode machine learning klasik
  • Satu entri matriks kernel untuk data dengan banyak fitur, menggunakan komputer kuantum nyata. Kita tidak akan mengestimasi seluruh matriks kernel untuk dataset besar, demi menghormati waktu pada komputer kuantum 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

Entri matriks kernel tunggal

Langkah 1: Pemetaan input klasik ke masalah kuantum

Mari kita pertimbangkan dataset dengan hanya beberapa fitur, katakanlah 10. Dataset bisa sebesar yang kamu inginkan, karena kita menghitung elemen matriks kernel satu per satu. Kita butuh setidaknya dua titik, jadi kita mulai dengan itu (dalam contoh berikutnya, kita akan mengimpor dataset penuh). Mari kita impor beberapa paket yang diperlukan:

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]]

Kita bisa mencoba menggunakan 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])

Dua unitary di atas persis sesuai dengan U1U_1 dan U2U_2 yang dijelaskan dalam pendahuluan. Kita bisa menggabungkannya menggunakan unitary_overlap. Seperti biasa, kita ingin memperhatikan kedalaman Circuit kita.

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

Langkah 2: Optimasi masalah untuk eksekusi kuantum

Kita mulai dengan memilih Backend yang paling tidak sibuk, lalu mengoptimalkan Circuit kita untuk dijalankan pada Backend tersebut.

# 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)

Untuk Circuit yang kompleks, langkah ini akan meningkatkan kedalaman Circuit secara substansial karena memetakan ke Gate native untuk komputer kuantum nyata, dan informasi mungkin perlu dipindahkan dari Qubit ke Qubit. Dalam kasus sederhana ini, kedalamannya hampir tidak terpengaruh sama sekali.

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

Langkah 3: Eksekusi menggunakan Qiskit Runtime Primitives

Sintaks untuk berjalan pada simulator dikomentari di bawah. Untuk dataset ini, dengan jumlah fitur yang sedikit, menjalankan pada simulator masih merupakan pilihan. Untuk perhitungan skala utilitas, simulasi biasanya tidak layak dilakukan. Simulator hanya boleh digunakan untuk men-debug kode yang diperkecil skalanya.

# 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()

Langkah 4: Post-processing, kembalikan hasil dalam format klasik

Seperti yang dijelaskan dalam pendahuluan, pengukuran yang paling berguna di sini adalah probabilitas mengukur state nol 00000|00000\rangle.

counts.get(0, 0.0) / num_shots
0.6525

Ini adalah hasil yang kita inginkan: estimasi hasil kali dalam (hingga mod kuadrat) dari vektor yang sesuai dengan dua titik data. Jika kita ingin melihat distribusi lengkap probabilitas pengukuran (atau kuasi-probabilitas), kita bisa melakukannya menggunakan fungsi plot_distribution seperti yang ditunjukkan di bawah. Terlihat bahwa untuk sejumlah besar Qubit, gambar seperti ini dengan cepat menjadi tidak traktabel.

from qiskit.visualization import plot_distribution

plot_distribution(counts_bit)

Output of the previous code cell

Sebagai alternatif, seseorang mungkin mendefinisikan visualisasi seperti yang di bawah ini untuk hanya melihat 10 pengukuran paling probable teratas. Ini bisa penting untuk troubleshooting atau mencoba mendapatkan lebih banyak intuisi untuk data. Namun probabilitas pengukuran state nol adalah elemen matriks kernel kita.

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

Dari informasi tentang hanya satu hasil kali dalam antara dua titik data dalam ruang fitur berdimensi tinggi, yang bisa kita katakan adalah bahwa overlap mereka cukup besar dibandingkan dengan overlap maksimum (yang akan menjadi 1,0). Ini bisa menjadi indikator bahwa dua titik data ini entah bagaimana mirip secara alami dan akan dikategorikan dalam kelas yang sama. Atau bisa jadi indikator bahwa peta fitur kita tidak efektif dalam memetakan ke ruang di mana data yang serupa memiliki overlap yang kuat dan data yang tidak serupa memiliki overlap yang kecil. Untuk mengetahui mana yang benar, kita harus menerapkan peta fitur kita ke seluruh set data dan melihat apakah matriks kernel yang dihasilkan bisa dimanipulasi untuk memisahkan kelas dengan akurasi tinggi secara efektif.

Perlu dicatat bahwa kita menggunakan z_feature_map yang menghasilkan kedalaman transpilasi dua-Qubit yang rendah (kedalaman 1, sebenarnya). Jika Circuit kamu menjadi terlalu dalam, hal itu pasti akan menghasilkan banyak noise, dan ini akan membuat probabilitas mengukur state nol menjadi sangat rendah, bahkan jika peta fitur kamu cocok dengan data kamu. Misalnya, pengulangan proses di atas menggunakan zz_feature_map dan , entanglement='linear', reps=1 menghasilkan dist.get(0,0.0) = 0.0015 menggunakan titik data yang sama. Ini disebabkan oleh kedalaman Circuit dan kedalaman dua-Qubit yang jauh lebih besar dari zz_feature_map. Gambar di bawah menunjukkan distribusi probabilitas untuk perhitungan tersebut.

Bad results from a zz feature map.

Ada baiknya bermain-main dengan beberapa titik data dari kategori yang sama untuk melihat seberapa rendah kedalaman kamu harus untuk mendapatkan hasil yang baik. Berikut adalah saran kasar yang pasti memiliki pengecualian. Umumnya, kedalaman dua-Qubit yang ditranspilasi sebesar 10 atau kurang seharusnya tidak masalah. Kedalaman dua-Qubit yang ditranspilasi sebesar 50-60 adalah state-of-the-art dan akan memerlukan mitigasi error lanjutan di antara alat-alat lain. Di antaranya, hasilmu mungkin bervariasi dengan kemiripan data, ekspresivitas peta fitur, lebar Circuit, dan faktor-faktor lain. Biasanya langkah post-processing juga mencakup proses machine learning klasik. Pada bagian berikutnya kita akan memperluas proses ini ke seluruh dataset, dan menunjukkan alur kerja machine learning klasik.

Uji pemahamanmu

Baca pertanyaan-pertanyaan di bawah, pikirkan jawabanmu, lalu klik segitiga untuk mengungkap solusinya.

Dalam Circuit kuantum 10-Qubit, umumnya, berapa banyak state berbeda yang mungkin bisa diukur?

Jawaban:

2102^{10} atau 1024.

Misalkan seseorang yang baru mengenal komputasi kuantum mencoba menggunakan Circuit kuantum yang memiliki kedalaman dua-Qubit yang sangat tinggi, dan mereka tidak menggunakan mitigasi error. Misalkan lebih lanjut bahwa ini menghasilkan tingkat error 10% pada setiap Qubit. Jika elemen matriks kernel yang sebenarnya (bebas error) yang sesuai dengan Circuit ini sangat besar, katakanlah 1,0, berapa probabilitas mengukur semua 10 Qubit dalam state dengan setiap Qubit |0>?

Jawaban:

Probabilitas setiap Qubit ditemukan dengan benar dalam state |0> adalah 0,90. Probabilitas untuk semua 10 Qubit ditemukan dalam state yang benar adalah 0.90100.90^{10} atau sekitar 35%.

Jelaskan dengan kata-katamu sendiri mengapa sangat penting untuk memantau kedalaman Circuit. Ini berlaku secara umum, tetapi jelaskan dalam konteks estimasi kernel kuantum.

Jawaban:

Dalam alur kerja QKE ini, estimasi kita didasarkan pada pengukuran state nol, yang berarti state di mana setiap Qubit ditemukan dalam state 0|0\rangle. Circuit yang sangat dalam akan memperkenalkan tingkat error yang tinggi. Ketika tingkat error tersebut digabungkan di banyak Qubit, ini akan mengurangi probabilitas mengukur state nol secara substansial.

Matriks kernel penuh

Dalam bagian ini, kita akan memperluas proses di atas ke klasifikasi biner dari dataset penuh. Ini akan memperkenalkan dua komponen penting: (1) kita sekarang bisa mengimplementasikan machine learning klasik dalam post-processing, dan (2) kita bisa mendapatkan skor akurasi untuk pelatihan kita.

Langkah 1: Pemetaan input klasik ke masalah kuantum

Sekarang kita akan mengimpor dataset yang sudah ada untuk klasifikasi kita. Dataset ini terdiri dari 128 baris (titik data) dan 14 fitur pada setiap titik. Ada elemen ke-15 yang menunjukkan kategori biner dari setiap titik (±1\pm 1). Dataset diimpor di bawah, atau kamu bisa mengakses dataset dan melihat strukturnya di sini.

Kita akan menggunakan 90 titik data pertama untuk pelatihan, dan 30 titik berikutnya untuk pengujian.

!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]

Kita sudah akan mempersiapkan penyimpanan beberapa output dengan membangun matriks kernel dan matriks uji berdimensi yang sesuai.

# 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)

Sekarang kita membuat peta fitur untuk encoding dan pemetaan data klasik kita dalam Circuit kuantum. Kita bebas membangun peta fitur sendiri atau menggunakan yang sudah jadi. Jangan ragu untuk mengubah peta fitur di bawah, atau beralih kembali ke ZFeatureMap. Tapi selalu perhatikan kedalaman Circuit. Ingat bahwa dalam contoh 6-Qubit sebelumnya, kedalaman Circuit yang ditranspilasi tidak traktabel ketika menggunakan zz_feature_map. Seiring meningkatnya skala dan kompleksitas Circuit, kedalaman bisa meningkat pesat ke titik di mana noise menguasai hasil kita. Kapan pun kamu mengetahui sesuatu tentang struktur data yang mungkin menginformasikan struktur peta fitur apa yang paling berguna, disarankan untuk membuat peta fitur kustom sendiri yang memanfaatkan pengetahuan tersebut.

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)

Langkah 2 dan 3: Optimasi masalah dan eksekusi menggunakan primitives

Kita akan membangun Circuit overlap, dan jika kita menjalankan pada komputer kuantum nyata dalam contoh ini, kita akan mengoptimalkannya untuk eksekusi seperti sebelumnya. Namun dalam kasus ini, kita bermaksud melangkah ke semua titik data dan menghitung matriks kernel penuh. Untuk setiap pasang vektor data xi\vec{x}_i dan xj\vec{x}_j, kita membuat Circuit overlap yang berbeda. Oleh karena itu kita harus mengoptimalkan Circuit kita untuk setiap pasang titik data. Jadi langkah 2 dan 3 akan dilakukan bersama dalam beberapa iterasi.

Sel kode di bawah melakukan proses yang sama persis seperti sebelumnya untuk satu pasang titik data. Kali ini cukup dieksekusi di dalam dua loop for, dan ada baris tambahan di akhir kernel_matrix[x_1,x_2] = ... untuk menyimpan hasil setiap perhitungan. Perlu diingat bahwa kita telah memanfaatkan simetri matriks kernel untuk mengurangi jumlah perhitungan sebesar 1/2. Kita juga cukup menetapkan elemen diagonal ke 1, seperti yang seharusnya tanpa noise. Tergantung pada implementasi dan presisi yang diperlukan, kamu juga bisa menggunakan elemen diagonal untuk mengestimasi noise atau mempelajarinya untuk tujuan mitigasi error.

Setelah matriks kernel telah sepenuhnya terisi, kita ulangi proses untuk data pengujian dan isi test_matrix. Ini sebenarnya juga merupakan matriks kernel; kita hanya memberinya nama yang berbeda untuk membedakan keduanya.

# 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

Langkah 4: Post-processing, kembalikan hasil dalam format klasik

Sekarang kita memiliki matriks kernel dan test_matrix berformat serupa dari metode kernel kuantum, kita bisa menerapkan algoritma machine learning klasik untuk membuat prediksi tentang data pengujian kita dan memeriksa akurasinya. Kita akan mulai dengan mengimpor sklearn.svc dari Scikit-Learn, sebuah support vector classifier (SVC). Kita harus menentukan bahwa kita ingin SVC menggunakan kernel yang telah dihitung sebelumnya menggunakan 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")

Menggunakan SVC.fit, kita sekarang bisa memasukkan matriks kernel dan label pelatihan untuk mendapatkan fit. SVC.score kemudian akan menilai data pengujian kita terhadap fit tersebut menggunakan test_matrix kita, dan mengembalikan akurasi kita.

# 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

Kita melihat bahwa akurasi model yang terlatih adalah 100%. Ini bagus, dan menunjukkan bahwa QKE bisa bekerja. Tapi itu sangat berbeda dari keunggulan kuantum. Kernel klasik kemungkinan juga bisa menyelesaikan masalah klasifikasi ini dengan akurasi 100%. Masih banyak pekerjaan yang harus dilakukan untuk mengkarakterisasi berbagai jenis data dan hubungan data untuk melihat di mana kernel kuantum akan paling berguna dalam era utilitas saat ini. Kita serahkan kepada pelajar untuk memodifikasi bagian-bagian dari alur kerja ini dan mempelajari efektivitas berbagai peta fitur kuantum. Berikut beberapa hal yang perlu dipertimbangkan:

  • Seberapa robust akurasinya? Apakah berlaku untuk jenis data yang luas atau hanya data pelatihan spesifik ini?
  • Struktur apa dalam data kamu yang membuatmu curiga bahwa peta fitur kuantum berguna?
  • Bagaimana akurasi dipengaruhi oleh meningkatkan/mengurangi jumlah data pelatihan?
  • Peta fitur apa yang bisa kamu gunakan dan bagaimana hasilnya bervariasi dengan peta fitur?
  • Bagaimana akurasi dan waktu berjalan dipengaruhi oleh meningkatkan jumlah fitur?
  • Tren mana, jika ada, yang kamu harapkan berlaku pada komputer kuantum nyata?

Skalabilitas ke lebih banyak fitur dan qubit

Di bagian ini, kita akan mengulangi perhitungan satu elemen matriks, tapi untuk jumlah fitur yang jauh lebih besar, sebagai gambaran jalur menuju utilitas. Pembatasan pada satu elemen matriks dilakukan agar prosesnya bisa ditunjukkan tanpa menghabiskan terlalu banyak waktu yang kamu miliki di komputer kuantum.

Langkah 1: Peta input klasik ke masalah kuantum

Kita asumsikan titik awal berupa dataset di mana setiap titik data memiliki 42 fitur. Seperti pada contoh pertama, kita akan menghitung satu elemen matriks kernel, yang membutuhkan dua titik data. Dua titik di bawah ini memiliki 42 fitur dan satu variabel kategori (±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]]

Ingat bahwa zz_feature_map menghasilkan Circuit yang cukup dalam untuk jumlah fitur yang relatif sedikit (14 fitur). Seiring bertambahnya jumlah fitur, kita perlu memantau kedalaman Circuit dengan cermat. Untuk menggambarkan hal ini, kita akan mencoba menggunakan zz_feature_map terlebih dahulu dan memeriksa kedalaman Circuit yang dihasilkan.

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

Seperti yang telah disebutkan sebelumnya, menentukan seberapa dalam yang terlalu dalam itu cukup bernuansa. Tapi kedalaman dua-qubit lebih dari 100, bahkan sebelum transpilasi, sudah tidak layak dipakai. Itulah mengapa feature map kustom ditekankan sepanjang pelajaran ini. Jika kamu tahu sesuatu tentang struktur seluruh datasetmu, kamu sebaiknya merancang peta entanglement dengan struktur tersebut dalam pikiran. Di sini, karena kita hanya menghitung hasil kali dalam antara dua titik data, kita telah memprioritaskan kedalaman Circuit yang rendah di atas pertimbangan detail struktur data.

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()

Kita tidak perlu repot memeriksa kedalaman sekarang, karena yang benar-benar penting adalah kedalaman dua-qubit setelah transpilasi.

Langkah 2: Optimalkan masalah untuk eksekusi kuantum

Kita mulai dengan memilih Backend yang paling tidak sibuk, lalu mengoptimalkan Circuit kita untuk dijalankan di Backend tersebut.

# 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')>

Pada pekerjaan skala kecil, preset pass manager sering kali mengembalikan Circuit yang sama dengan kedalaman yang sama secara konsisten. Tapi pada Circuit yang sangat besar dan kompleks, pass manager bisa mengembalikan Circuit yang ditranspilasi berbeda setiap kali dijalankan. Ini karena menggunakan heuristik, dan karena Circuit yang sangat besar akan memiliki lanskap optimasi yang rumit. Seringkali berguna untuk melakukan transpilasi beberapa kali dan mengambil Circuit yang paling dangkal. Ini hanya menambah overhead klasik dan bisa secara substansial meningkatkan hasil dari komputer kuantum.

Di sini, kita mentranspilasi Circuit overlap unitary sebanyak 20 kali, dan melihat kedalaman Circuit yang diperoleh.

# 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]

Di sini kamu bisa melihat ada variasi dalam total kedalaman Gate dengan pass transpilasi yang berbeda. Circuit kita belum cukup dalam/lebar untuk melihat variasi pada kedalaman dua-qubit yang ditranspilasi. Kita akan menggunakan transpiled_qcs[1], yang memiliki kedalaman 60, sedikit lebih rendah dari kedalaman Circuit terdalam yang diperoleh, yaitu 77.

overlap_ibm = transpiled_qcs[1]

Langkah 3: Eksekusi menggunakan Qiskit Runtime Primitives

Seiring kita mendekati utilitas, simulator tidak akan berguna. Hanya sintaks untuk komputer kuantum nyata yang ditampilkan di sini.

# 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()

Langkah 4: Pasca-proses, kembalikan hasil dalam format klasik

Seperti yang dijelaskan di pengantar, pengukuran yang paling berguna di sini adalah probabilitas mengukur keadaan nol 00000|00000\rangle.

counts.get(0, 0.0) / num_shots
0.0138

Proses untuk satu elemen matriks kernel ini bisa diulang antara pasangan data lain dalam setmu untuk mendapatkan matriks kernel lengkap. Dimensi matriks kernel ditentukan oleh jumlah titik dalam data pelatihanmu, bukan jumlah fitur. Jadi biaya komputasi untuk memanipulasi matriks kernel menjadi model prediktif tidak berkembang seperti jumlah fitur atau qubit. Bahkan untuk dataset yang relatif kecil dengan jumlah fitur yang besar, data tetap perlu dicocokkan dengan feature map yang menghasilkan klasifikasi yang efektif.

Skalabilitas dan pekerjaan ke depan

Metode kernel mengharuskan kita mengukur 0|0\rangle seakurat mungkin. Tapi kesalahan Gate dan kesalahan pembacaan berarti ada probabilitas non-nol pp bahwa qubit tertentu akan terukur secara keliru berada dalam keadaan 1|1\rangle. Bahkan dengan penyederhanaan berlebihan bahwa probabilitas 0|0\rangle seharusnya 100%100\%, untuk banyak fitur yang dikodekan pada, katakanlah, NN bit, probabilitas mengukur semua bit dengan benar sebagai 0|0\rangle berkurang menjadi (1p)N(1-p)^N. Seiring NN membesar, metode ini menjadi semakin tidak dapat diandalkan. Mengatasi kesulitan ini dan menskalakan estimasi kernel ke lebih banyak fitur adalah area penelitian saat ini. Untuk mempelajari lebih lanjut tentang masalah ini, lihat karya Thanasilp, Wang, Cerezo, dan Holmes. Kami menyarankan kamu menjelajahi apa yang bisa dilakukan dengan komputer kuantum saat ini, dan juga menantikan apa yang akan mungkin dilakukan di era koreksi kesalahan.

Ulasan

Menghitung kernel kuantum melibatkan

  • menghitung entri matriks kernel, menggunakan pasangan titik data pelatihan
  • mengkodekan data dan memetakannya melalui feature mapping
  • mengoptimalkan Circuit kamu untuk dijalankan di komputer kuantum nyata / Backend

Kernel kuantum kemudian bisa digunakan dalam algoritma machine learning klasik, seperti dalam pelajaran ini.

Beberapa hal penting yang perlu diingat saat menggunakan kernel kuantum meliputi:

  • Apakah dataset kemungkinan akan mendapat manfaat dari metode kernel kuantum?
  • Coba berbagai feature map dan skema entanglement.
  • Apakah kedalaman Circuit dapat diterima?
  • Coba jalankan pass manager beberapa kali dan gunakan Circuit dengan kedalaman terkecil yang bisa kamu dapatkan.

Metode kernel kuantum berpotensi menjadi alat yang kuat bila ada kecocokan yang tepat antara dataset dengan fitur yang sesuai untuk kuantum, dan feature map kuantum yang cocok. Untuk lebih memahami di mana kernel kuantum kemungkinan akan berguna, kami menyarankan membaca Liu, Arunachalam & Temme (2021).

Source: IBM Quantum docs — updated 17 Apr 2026
English version on doQumentation — updated 7 Mei 2026
This translation based on the English version of approx. 27 Mar 2026