Mga Quantum Kernel
Panimula sa mga quantum kernel
Ang "pamamaraan ng quantum kernel" ay tumutukoy sa anumang pamamaraan na gumagamit ng mga quantum computer upang tantiyahin ang isang kernel. Sa kontekstong ito, ang "kernel" ay tumutukoy sa kernel matrix o sa mga indibidwal na elemento nito. Alalahanin na ang feature mapping na ay isang pagmamapa mula sa patungo sa kung saan karaniwan ay at ang layunin ng pagmamagang ito ay gawing mapaghihiwalay ng isang hyperplane ang mga kategorya ng data. Ang kernel function ay tumatanggap ng mga vector sa feature-mapped na espasyo bilang mga argumento at ibinalik ang kanilang inner product, ibig sabihin, na may . Sa klasikal na paraan, interesado tayo sa mga feature map kung saan madaling suriin ang kernel function. Kadalasan, nangangahulugan ito ng paghahanap ng kernel function kung saan ang inner product sa feature-mapped na espasyo ay maaaring isulat sa pamamagitan ng mga orihinal na vector ng data, nang hindi na kailangang itayo ang at . Sa pamamaraan ng mga quantum kernel, ginagawa ang feature mapping sa pamamagitan ng isang quantum circuit, at tinatantiya ang kernel gamit ang mga sukat sa circuit na iyon at ang mga kamag-anak na posibilidad ng pagsukat.
Sa araling ito, susuriin natin ang mga lalim ng mga pre-coded encoding circuit na gumagamit ng malawak na entanglement at ihahambing ang mga ito sa mga lalim ng mga circuit na ating sariling ginawa. Hindi ito upang itaguyod ang isang pamamaraan kaysa sa isa pa. Maaaring matuklasan mo na ang mga pre-coded circuit ay masyadong malalim, at ang entanglement sa custom-built circuit ay hindi sapat upang maging kapaki-pakinabang. Muli, ipinakita lamang ang mga ito upang mapadali ang iyong pag-explore.
Bago talakayin nang detalyado ang pagtatantiya ng kernel matrix, balangkasin natin ang workflow gamit ang wika ng mga Qiskit pattern.
Hakbang 1: I-map ang mga klasikal na input sa isang quantum na problema
- Input: Training dataset
- Output: Abstract circuit para sa pagkalkula ng isang entry ng kernel matrix
Batay sa dataset, ang panimulang punto ay ang i-encode ang data sa isang quantum circuit. Sa madaling salita, kailangan nating i-map ang ating data sa Hilbert space ng mga estado ng ating quantum computer. Ginagawa natin ito sa pamamagitan ng pagbuo ng isang data-dependent circuit. Maraming paraan ng paggawa nito, at binanggit ng nakaraang aralin ang ilang mga pagpipilian. Maaari kang bumuo ng sarili mong circuit upang i-encode ang iyong data, o maaari kang gumamit ng pre-made na feature map tulad ng zz_feature_map. Sa araling ito, gagawin nating pareho.
Tandaan na upang makalkula ang isang solong elemento ng kernel matrix, gusto nating i-encode ang dalawang magkaibang punto, upang matantiya natin ang kanilang inner product. Ang isang buong quantum kernel workflow ay syempre nagsasangkot ng maraming ganitong inner product sa pagitan ng mga nakaprosesong data vector, pati na rin ang mga klasikal na pamamaraan ng machine learning. Ngunit ang pangunahing hakbang na inuulit ay ang pagtatantiya ng isang solong elemento ng kernel matrix. Para dito, pipiliin natin ang isang data-dependent quantum circuit at magma-map ng dalawang data vector sa feature space.

Para sa gawain ng pagbuo ng kernel matrix, partikular tayong interesado sa posibilidad ng pagsukat sa estado na , kung saan ang lahat ng qubit ay nasa estado ng . Upang makita ito, isaalang-alang na ang circuit na responsable sa pag-encode at pagmamapa ng isang data vector na ay maaaring isulat bilang , at ang isa na responsable sa pag-encode at pagmamapa ng ay , at tukuyin ang mga nakaprosesong estado
Ang mga estado na ito ay ang pagmamapa ng data sa mas mataas na mga dimensyon, kaya ang ating ninanais na entry ng kernel ay ang inner product
Kung ino-operate natin ang default na panimulang estado na gamit ang parehong circuit na at , ang posibilidad ng pagsukat sa estado na ay
Ito ay eksakto ang value na gusto natin (hanggang ). Ang measurement layer ng ating circuit ay magbabalik ng mga posibilidad ng pagsukat (o tinatawag na "quasi-probabilities", kung ginagamit ang ilang paraan ng error mitigation). Ang posibilidad na pinakainteresante ay ang posibilidad ng zero state, .
Hakbang 2: I-optimize ang problema para sa quantum na pagpapatupad
- Input: Abstract circuit, hindi na-optimize para sa isang partikular na backend
- Output: Target circuit at observable, na-optimize para sa napiling QPU
Sa hakbang na ito, gagamitin natin ang function na generate_preset_pass_manager mula sa Qiskit upang tukuyin ang isang optimization routine para sa ating circuit kaugnay ng tunay na quantum computer kung saan natin plano na patakbuhin ang eksperimento. Itinakda natin ang optimization_level=3, na nangangahulugang gagamitin natin ang preset pass manager na nagbibigay ng pinakamataas na antas ng optimization. Sa kontekstong ito, ang "optimization" ay tumutukoy sa pag-optimize ng pagpapatupad ng circuit sa isang tunay na quantum computer. Kabilang dito ang mga konsiderasyon tulad ng pagpili ng mga pisikal na qubit upang tumugma sa mga qubit sa abstract quantum circuit na magpapababa ng gate depth, o pagpili ng mga pisikal na qubit na may pinakamababang available na error rate. Hindi ito direktang may kaugnayan sa optimization ng machine learning problem (tulad ng mga klasikal na optimizer na COBYLA).
Depende sa kung paano mo ipinapatupad ang hakbang 2, maaaring kailangan mong i-optimize ang circuit nang higit sa isang beses, dahil ang bawat pares ng mga punto na kasangkot sa isang elemento ng matrix ay nagbubunga ng ibang circuit na susukatin.
Hakbang 3: Isagawa gamit ang Qiskit Runtime Primitives
- Input: Target circuit
- Output: Distribusyon ng posibilidad
Gamitin ang Sampler primitive mula sa Qiskit Runtime upang muling itayo ang distribusyon ng posibilidad ng mga estado na nakuha mula sa pag-sample ng circuit. Tandaan na maaari mong makita ang ito na tinutukoy bilang "quasi-probability distribution", isang terminong naaangkop kung saan ang ingay ay isang isyu at kapag may mga dagdag na hakbang na isinasagawa, tulad ng sa error mitigation. Sa ganitong mga kaso, ang kabuuan ng lahat ng posibilidad ay maaaring hindi eksaktong katumbas ng 1; kaya "quasi-probability".
Hakbang 4: Post-process, ibalik ang resulta sa klasikal na format
- Input: Distribusyon ng posibilidad
- Output: Isang solong elemento ng kernel matrix, o isang kernel matrix kung inuulit
Kalkulahin ang posibilidad ng pagsukat sa sa quantum circuit, at punan ang kernel matrix sa posisyong tumutugma sa dalawang data vector na ginamit. Upang mapunan ang buong kernel matrix, kailangan nating magpatakbo ng quantum experiment para sa bawat entry. Kapag mayroon na tayong kernel matrix, maaari nating gamitin ito sa maraming klasikal na algorithm ng machine learning na tumatanggap ng pre-calculated kernels. Halimbawa: qml_svc = SVC(kernel="precomputed"). Maaari nating gamitin ang mga klasikal na workstream upang ilapat ang ating modelo sa ating testing data, at makakuha ng accuracy score. Depende sa ating kasiyahan sa ating accuracy score, maaaring kailangang balikan natin ang ilang aspeto ng ating kalkulasyon, tulad ng ating feature map.
Balangkas ng aralin
Sa araling ito, isasagawa natin ang mga hakbang na ito sa maraming paraan upang mapakinabangan nang mabuti ang iyong oras sa mga tunay na quantum computer. Ilalapat natin ang isang quantum kernel method sa
- Isang solong entry ng kernel matrix para sa data na may medyo kakaunting feature, gamit ang isang tunay na backend, upang madali nating masundan ang nangyayari sa bawat hakbang.
- Isang buong dataset na may medyo kakaunting feature, gamit ang isang simulated na backend, upang makita natin kung paano kumokonekta ang quantum workstream sa mga klasikal na pamamaraan ng machine learning.
- Isang solong entry ng kernel matrix para sa data na may maraming feature, gamit ang isang tunay na quantum computer. Hindi natin tatantiyahin ang buong kernel matrix para sa isang malaking dataset, upang maigalang ang oras sa mga IBM® quantum computer.
# 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
Solong entry ng kernel matrix
Hakbang 1: I-map ang mga klasikal na input sa isang quantum na problema
Unahin nating isaalang-alang ang isang dataset na may kakaunting feature lamang, sabihing 10. Ang dataset ay maaaring kasing laki ng gusto mo, dahil kinakalkula natin ang mga elemento ng kernel matrix nang isa-isa. Kailangan natin ng kahit dalawang punto, kaya magsisimula tayo sa iyon (sa susunod na halimbawa, mag-iimport tayo ng buong dataset). I-import natin ang ilang kinakailangang pakete:
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]]
Maaari nating subukan ang paggamit ng 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])
Ang dalawang unitary sa itaas ay eksaktong tumutugma sa at na inilarawan sa panimula. Maaari nating pagsamahin ang mga ito gamit ang unitary_overlap. Gaya ng lagi, gusto nating bantayan ang ating circuit depth.
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
Hakbang 2: I-optimize ang problema para sa quantum na pagpapatupad
Magsisimula tayo sa pamamagitan ng pagpili ng pinaka-hindi abala na backend, pagkatapos ay i-optimize ang ating circuit para sa pagpapatakbo nito sa backend na iyon.
# 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)
Para sa mga kumplikadong circuit, ang hakbang na ito ay malaki ang maiaambag sa pagtaas ng circuit depth habang nima-map ito sa mga native gate para sa mga tunay na quantum computer, at maaaring kailangang ilipat ang impormasyon mula sa qubit patungo sa qubit. Sa simpleng kaso na ito, halos hindi naaapektuhan ang depth.
print("circuit depth = ", overlap_ibm.decompose().depth())
overlap_ibm.decompose().depth(lambda instr: len(instr.qubits) > 1)
circuit depth = 10
1
Hakbang 3: Isagawa gamit ang Qiskit Runtime Primitives
Ang syntax para sa pagpapatakbo sa isang simulator ay naka-comment out sa ibaba. Para sa dataset na ito, na may maliit na bilang ng feature, ang pagpapatakbo sa isang simulator ay opsyon pa rin. Para sa mga kalkulasyon sa utility-scale, ang simulation ay karaniwang hindi posible. Ang mga simulator ay dapat gamitin lamang upang mag-debug ng pinaikling code.
# 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()
Hakbang 4: Post-process, ibalik ang resulta sa klasikal na format
Gaya ng inilarawan sa panimula, ang pinaka-kapaki-pakinabang na pagsukat dito ay ang posibilidad ng pagsukat sa zero state na .
counts.get(0, 0.0) / num_shots
0.6525
Ito ang resulta na gusto natin: isang tantiya ng inner product (hanggang mod squared) ng mga vector na tumutugma sa dalawang data point. Kung gusto nating tingnan ang buong distribusyon ng mga posibilidad ng pagsukat (o quasiprobabilities), magagawa natin ito gamit ang function na plot_distribution gaya ng ipinapakita sa ibaba. Makikita na para sa malaking bilang ng qubit, ang mga larawan na ganito ay mabilis na nagiging hindi praktikal.
from qiskit.visualization import plot_distribution
plot_distribution(counts_bit)

Bilang alternatibo, maaaring magtukoy ng visualization tulad ng nasa ibaba upang tingnan lamang ang pinakamataas na 10 pinakamalamang na mga pagsukat. Maaaring mahalaga ito para sa troubleshooting o pagsubok na makakuha ng mas maraming intuisyon para sa data. Ngunit ang posibilidad ng pagsukat sa zero state ang ating elemento ng kernel matrix.
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)
Mula sa impormasyong ito tungkol sa isang inner product lamang sa pagitan ng dalawang data point sa mas mataas na dimensyonal na feature space, ang masasabi lamang natin ay ang kanilang overlap ay medyo malaki kumpara sa pinakamataas na overlap (na magiging 1.0). Maaari itong maging tanda na ang dalawang data point na ito ay magkaparehong katangian at ikategorya sa parehong klase. O maaari itong maging tanda na ang ating feature map ay hindi epektibo sa pagmamapa sa isang espasyo kung saan ang magkaparehong data ay may malakas na overlap at ang magkaibang data ay may maliit na overlap. Upang malaman kung alin ang totoo, kailangan nating ilapat ang ating feature map sa buong hanay ng data at tingnan kung ang resultang kernel matrix ay maaaring manipulahin upang epektibong paghiwalayin ang mga klase nang may mataas na katumpakan.
Kapaki-pakinabang na tandaan na ginamit natin ang z_feature_map na nagresulta sa mababang transpiled na two-qubit depth (depth 1, sa katunayan). Kung nagiging masyadong malalim ang iyong mga circuit, tiyak na magdudulot ito ng maraming ingay, at mababawasan nito ang posibilidad ng pagsukat sa zero state, kahit na ang iyong feature map ay magkaayon sa iyong data. Halimbawa, ang pag-ulit ng proseso sa itaas gamit ang zz_feature_map at , entanglement='linear', reps=1 ay nagbunga ng dist.get(0,0.0) = 0.0015 gamit ang parehong mga data point. Ito ay dahil sa mas malalim na circuit depth at two-qubit depth mula sa zz_feature_map. Ang larawan sa ibaba ay nagpapakita ng distribusyon ng posibilidad para sa kalkulasyong iyon.

Kapaki-pakinabang na mag-eksperimento gamit ang ilang data point mula sa parehong kategorya upang makita kung gaano kabababa ang kailangang maging depth mo upang makakuha ng magagandang resulta. Ang sumusunod ay isang magaspang na payo na tiyak may mga eksepsyon. Sa pangkalahatan, ang isang two-qubit, transpiled depth na 10 o mas mababa ay walang problema. Ang isang two-qubit, transpiled depth na 50-60 ay state-of-the-art at mangangailangan ng advanced na error mitigation kasama ang iba pang mga kasangkapan. Sa pagitan, ang iyong mga resulta ay maaaring mag-iba depende sa pagkakatulad ng data, expressivity ng feature map, lapad ng circuit, at iba pang mga salik. Sa karaniwang sitwasyon, ang post-processing na hakbang ay kasama rin ang mga klasikal na proseso ng machine learning. Sa susunod na seksyon, palawakin natin ang prosesong ito sa isang buong dataset, at ipakita ang workflow ng klasikal na machine learning.
Suriin ang iyong pag-unawa
Basahin ang mga tanong sa ibaba, isipin ang iyong mga sagot, pagkatapos ay i-click ang mga tatsulok upang matuklasan ang mga solusyon.
Sa isang 10-qubit quantum circuit, sa pangkalahatan, ilang iba't ibang estado ang maaaring masukatan?
Sagot:
o 1024.
Ipagpalagay natin na ang isang taong baguhan sa quantum computing ay sumusubok na gumamit ng isang quantum circuit na may napakataas na two-qubit depth, at hindi sila gumagamit ng error mitigation. Ipagpalagay pa natin na nagresulta ito sa isang error rate na 10% sa bawat qubit. Kung ang tunay na (walang-error) na elemento ng kernel matrix na tumutugma sa circuit na ito ay napakalaki, sabihing 1.0, ano ang magiging posibilidad ng pagsukat ng lahat ng 10 qubit na nasa estado kung saan ang bawat qubit ay |0>?
Sagot:
Ang posibilidad ng bawat qubit na tamang makita sa estado na |0> ay 0.90. Ang posibilidad na ang lahat ng 10 qubit ay makita sa tamang estado ay o humigit-kumulang 35%.
Ipaliwanag sa iyong sariling mga salita kung bakit napakahalaga ng pagbabantay sa mga circuit depth. Ito ay totoo sa pangkalahatan, ngunit ipaliwanag ito sa konteksto ng quantum kernel estimation.
Sagot:
Sa QKE workflow na ito, ang ating mga tantiya ay batay sa mga pagsukat sa zero state, ibig sabihin, ang estado kung saan ang bawat qubit ay matatagpuan sa estado na . Ang mga napakalalim na circuit ay magpapakilala ng mataas na error rate. Kapag ang error rate na iyon ay pinagsama-sama sa maraming qubit, mababawasan nito ang posibilidad ng pagsukat sa zero state nang malaki.
Buong kernel matrix
Sa seksyong ito, palawakin natin ang proseso sa itaas para sa binary classification ng isang buong dataset. Dalawang mahalagang bahagi ang idinaragdag nito: (1) maaari na tayong mag-implement ng classical machine learning sa post-processing, at (2) makakakuha tayo ng mga accuracy score para sa ating pagsasanay.
Hakbang 1: I-map ang mga classical na input sa quantum na problema
Mag-import na tayo ng isang existing na dataset para sa ating classification. Ang dataset na ito ay binubuo ng 128 row (data point) at 14 na feature sa bawat punto. May ika-15 na element na nagpapakita ng binary category ng bawat punto (). Ini-import ang dataset sa ibaba, o maaari mong i-access ang dataset at tingnan ang istraktura nito dito.
Gagamitin natin ang unang 90 na data point para sa pagsasanay, at ang susunod na 30 na punto para sa pagsubok.
!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]
Ihahanda na rin natin ang pag-iimbak ng maraming output sa pamamagitan ng pagbuo ng kernel matrix at test matrix na may angkop na mga dimensyon.
# 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)
Ngayon gagawa tayo ng feature map para sa pag-encode at pag-map ng ating classical na data sa isang quantum circuit. Maaari tayong gumawa ng sariling feature map o gumamit ng handa nang feature map. Huwag mag-atubiling baguhin ang feature map sa ibaba, o bumalik sa ZFeatureMap. Laging bantayan ang circuit depth. Tandaang sa nakaraang halimbawa na may 6 na qubit, ang transpiled circuit depth ay hindi mapapamahalaan nang ginagamit ang zz_feature_map. Habang lumalaki at nagiging mas kumplikado ang circuit, mabilis na maaaring lumaki ang depth sa puntong nilalamon na ng ingay ang ating mga resulta. Kapag may alam ka tungkol sa istraktura ng iyong dataset na maaaring makatulong sa pagpili ng feature map, mainam na gumawa ng sariling custom feature map na sinasamantala ang kaalamang iyon.
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)
Mga Hakbang 2 at 3: I-optimize ang problema at i-execute gamit ang mga primitive
Gagawa tayo ng overlap circuit, at kung tatakbo tayo sa isang tunay na quantum computer sa halimbawang ito, ia-optimize natin ito para sa execution tulad ng dati. Ngunit sa kasong ito, binalak nating ulitin ang proseso para sa lahat ng data point at kalkulahin ang buong kernel matrix. Para sa bawat pares ng data vector na at , gumagawa tayo ng ibang overlap circuit. Kaya naman, dapat na ia-optimize ang ating circuit para sa bawat pares ng data point. Kaya ang mga Hakbang 2 at 3 ay isasagawa nang magkasama sa maraming ulit.
Ang code cell sa ibaba ay ginagawa ang eksaktong parehong proseso tulad ng dati para sa isang pares ng data point. Sa pagkakataong ito, inilalagay lamang ito sa loob ng dalawang for loop, at may karagdagang linya sa dulo na kernel_matrix[x_1,x_2] = ... para i-store ang mga resulta ng bawat kalkulasyon. Pansinin na ginamit natin ang simmetry ng kernel matrix para mabawasan ang bilang ng kalkulasyon ng 1/2. Itinakda rin natin ang mga diagonal na elemento sa 1, dahil ganoon dapat ang halaga nito kung walang ingay. Depende sa iyong implementasyon at kinakailangang katumpakan, maaari mo ring gamitin ang mga diagonal na elemento para tantiyahin o matuto tungkol sa ingay para sa error mitigation.
Kapag natapos nang punan ang kernel matrix, inuulit natin ang proseso para sa test data at pinupunan ang test_matrix. Kernel matrix rin ito sa katunayan; binibigyan lamang natin ito ng ibang pangalan para makilala ang dalawa.
# 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
Hakbang 4: Post-process, ibalik ang resulta sa classical na format
Ngayong mayroon na tayong kernel matrix at katulad na test_matrix mula sa mga quantum kernel method, maaari na nating ilapat ang mga classical machine learning algorithm para gumawa ng mga hula tungkol sa ating test data at suriin ang katumpakan nito. Magsisimula tayo sa pag-import ng sklearn.svc ng Scikit-Learn, isang support vector classifier (SVC). Dapat nating tukuyin na gusto nating gamitin ng SVC ang ating precomputed kernel gamit ang 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")
Gamit ang SVC.fit, maaari na nating ipasok ang kernel matrix at ang mga training label para makakuha ng fit. Ang SVC.score ay susuriin ang ating test data laban sa fit na iyon gamit ang ating test_matrix, at ibabalik ang ating katumpakan.
# 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
Makikita natin na ang katumpakan ng ating trained na modelo ay 100%. Napakagaling nito, at nagpapakita na gumagana ang QKE. Ngunit ibang-iba iyon mula sa quantum advantage. Malamang na kaya rin ng classical kernel na malutas ang problemang ito ng classification nang may 100% na katumpakan. Marami pang gawaing dapat gawin sa pag-uuri ng iba't ibang uri ng data at relasyon ng data para malaman kung saan magiging pinakakapaki-pakinabang ang mga quantum kernel sa kasalukuyang panahon ng utility.
Iniiwan namin sa mambabasa ang pagbabago ng ilang bahagi ng workflow na ito at pag-aaral ng bisa ng iba't ibang quantum feature map. Narito ang ilang bagay na dapat isaalang-alang:
- Gaano katatag ang katumpakan? Nananatili ba ito para sa malawak na uri ng data o sa partikular na training data lamang na ito?
- Anong istraktura sa iyong data ang nagpapahiwatig na kapaki-pakinabang ang quantum feature map?
- Paano naapektuhan ang katumpakan sa pagdaragdag o pagbabawas ng dami ng training data?
- Anong mga feature map ang maaari mong gamitin at paano nag-iiba-iba ang mga resulta depende sa feature map?
- Paano naapektuhan ang katumpakan at oras ng pagpapatakbo sa pagdaragdag ng bilang ng mga feature?
- Anong mga trend, kung mayroon man, ang inaasahan mong mananatili sa mga tunay na quantum computer?
Pag-scale sa mas maraming feature at qubit
Sa seksyong ito, uulitin natin ang kalkulasyon ng isang matrix element, ngunit para sa mas malaking bilang ng mga feature, na nagbabalangkas ng landas patungo sa utility. Ang paghihigpit sa isang matrix element ay ginagawa para maipakita ang proseso nang hindi nasasaid ang iyong inilaan na oras sa mga quantum computer.
Hakbang 1: I-map ang mga classical na input sa quantum na problema
Ipagpalagay nating nagsisimula tayo mula sa isang dataset kung saan ang bawat data point ay may 42 na feature. Tulad ng sa unang halimbawa, magkakalkula tayo ng isang kernel matrix element, na nangangailangan ng dalawang data point. Ang dalawang punto sa ibaba ay may 42 na feature at isang category variable ().
# 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]]
Tandaang ang zz_feature_map ay nagdulot ng medyo malalim na mga circuit sa kaso ng medyo kaunting feature (14 na feature). Habang pinapalaki natin ang bilang ng mga feature, kailangan nating maingat na bantayan ang circuit depth. Para ipakita ito, subukan muna nating gamitin ang zz_feature_map at suriin ang depth ng resultang 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
Tulad ng nabanggit kanina, ang pagtukoy kung gaano kalalim ang masyadong malalim ay medyo komplikado. Ngunit ang two-qubit depth na higit sa 100, kahit bago pa ang transpilation, ay hindi na mapapamahalaan. Kaya naman binibigyang-diin sa buong aralin na ito ang mga custom feature map. Kung may alam ka tungkol sa istraktura ng iyong buong dataset, dapat mong idisenyong ang entanglement map na isinasaalang-alang ang istrukturang iyon. Dito, dahil kino-compute lamang natin ang inner product sa pagitan ng dalawang data point, inuna natin ang mababang circuit depth kaysa sa anumang detalyadong pagsasaalang-alang ng istraktura ng 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()
Hindi muna natin susuriin ang mga depth dito, dahil ang tunay na mahalaga ay ang transpiled two-qubit depth.
Hakbang 2: I-optimize ang problema para sa quantum execution
Magsisimula tayo sa pagpili ng pinaka-kaunting abala na Backend, pagkatapos ay ia-optimize ang ating circuit para patakbuhin sa Backend na iyon.
# 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')>
Sa maliliit na trabaho, ang preset pass manager ay madalas na nagbabalik ng parehong circuit na may parehong depth, nang maaasahan. Ngunit sa napakalalaki at kumplikadong mga circuit, ang pass manager ay maaaring magbalik ng iba't ibang transpiled circuit sa bawat pagpapatakbo. Ito ay dahil gumagamit ito ng mga heuristic, at dahil ang napakalalaking mga circuit ay magkakaroon ng kumplikadong landscape ng mga posibleng optimization. Kadalasang kapaki-pakinabang na mag-transpile ng ilang beses at gamitin ang pinakamabanayad na circuit. Nagdadagdag lamang ito ng classical overhead at maaaring makabuluhang mapabuti ang mga resulta mula sa quantum computer.
Dito, ini-transpile natin ang unitary overlap circuit nang 20 beses, at titingnan ang mga depth ng mga circuit na nakuha.
# 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]
Makikita dito na may ilang pagkakaiba-iba sa kabuuang gate depth sa iba't ibang transpilation pass. Hindi pa sapat ang lalim/lapad ng ating circuit para makita ang pagkakaiba-iba sa two-qubit transpiled depths. Gagamitin natin ang transpiled_qcs[1], na may depth na 60, bahagyang mas mababa kaysa sa depth ng pinakamalim na circuit na nakuha, na 77.
overlap_ibm = transpiled_qcs[1]
Hakbang 3: I-execute gamit ang Qiskit Runtime Primitives
Habang nagsisimula tayong lumapit sa utility, hindi na magiging kapaki-pakinabang ang mga simulator. Ang syntax para sa mga tunay na quantum computer lamang ang ipinakita dito.
# 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()
Hakbang 4: Post-process, ibalik ang resulta sa classical na format
Tulad ng inilarawan sa panimula, ang pinakakapaki-pakinabang na sukat dito ay ang probabilidad ng pagsukat sa zero state na .
counts.get(0, 0.0) / num_shots
0.0138
Ang prosesong ito para sa isang kernel matrix element ay maaaring ulitin sa pagitan ng ibang mga pares ng data sa iyong set para makuha ang buong kernel matrix. Ang dimensyon ng kernel matrix ay tinutukoy ng bilang ng mga punto sa iyong training data, hindi ng bilang ng mga feature. Kaya naman ang gastos sa pag-compute ng pagmamanipula ng kernel matrix para maging isang predictive model ay hindi nag-scale ayon sa bilang ng mga feature o qubit. Kahit para sa medyo maliliit na dataset na may malaking bilang ng mga feature, ang data ay kailangan pa ring itugma sa isang feature map na nagbubunga ng epektibong classification.
Pag-scale at mga gawain sa hinaharap
Ang kernel method ay nangangailangan na masukat nating ang nang tama hangga't maaari. Ngunit ang mga gate error at readout error ay nangangahulugang may hindi zero na probabilidad na na ang anumang partikular na qubit ay maling masukat sa na estado. Kahit na sa oversimplification na ang probabilidad ng ay dapat na , para sa maraming feature na naka-encode sa, halimbawa, na bit, ang probabilidad ng tamang pagsukat sa lahat ng bit bilang ay nababawasan sa . Habang lumalaki ang , ang metodong ito ay nagiging hindi gaanong maaasahan. Ang pagtagumpayan ng kahirapang ito at ang pag-scale ng kernel estimation sa mas marami at mas maraming feature ay isang larangan ng kasalukuyang pananaliksik. Para matuto pa tungkol sa isyung ito, tingnan ang gawaing ito ni Thanasilp, Wang, Cerezo, at Holmes. Inirerekomenda namin na tuklasin mo kung ano ang magagawa sa kasalukuyang mga quantum computer, at abangan din kung ano ang magiging posible sa panahon ng error correction.
Pagsusuri
Ang pagkalkula ng quantum kernel ay kinabibilangan ng:
- pagkalkula ng mga kernel matrix entry, gamit ang mga pares ng training data point
- pag-encode ng data at pag-map nito sa pamamagitan ng feature mapping
- pag-optimize ng iyong Circuit para patakbuhin sa mga tunay na quantum computer / Backend
Ang quantum kernel ay maaaring gamitin sa mga classical machine learning algorithm, tulad ng sa araling ito.
Ilang mahahalagang bagay na dapat tandaan kapag gumagamit ng mga quantum kernel:
- Malamang bang makinabang ang dataset sa mga quantum kernel method?
- Subukan ang iba't ibang feature map at entanglement scheme.
- Katanggap-tanggap ba ang circuit depth?
- Subukang patakbuhin ang pass manager nang maraming beses at gamitin ang pinakamababang-depth na circuit na makukuha mo.
Ang mga quantum kernel method ay potensyal na makapangyarihang kasangkapan kapag may tamang pagtutugma sa pagitan ng mga dataset na may quantum-amenable na feature, at isang angkop na quantum feature map. Para mas maunawaan kung saan malamang na maging kapaki-pakinabang ang mga quantum kernel, inirerekomenda naming basahin ang Liu, Arunachalam & Temme (2021).