Antrenarea kernelului cuantic
Estimare de utilizare: sub un minut pe un procesor Eagle r3 (NOTĂ: Aceasta este doar o estimare. Timpul tău de execuție poate varia.)
Fundal
Acest tutorial arată cum să construiești un Qiskit pattern pentru evaluarea intrărilor într-o matrice de kernel cuantic utilizată pentru clasificare binară. Pentru mai multe informații despre Qiskit patterns și cum poate fi folosit Qiskit Serverless pentru a le implementa în cloud pentru execuție gestionată, vizitează pagina noastră de documentație despre IBM Quantum® Platform.
Cerințe
Înainte de a începe acest tutorial, asigură-te că ai instalate următoarele:
- Qiskit SDK v1.0 sau mai recent, cu suport pentru vizualizare
- Qiskit Runtime v0.22 sau mai recent (
pip install qiskit-ibm-runtime)
Configurare
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy pandas qiskit qiskit-ibm-catalog qiskit-ibm-runtime
!wget https://raw.githubusercontent.com/qiskit-community/prototype-quantum-kernel-training/main/data/dataset_graph7.csv
# General Imports and helper functions
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from qiskit.circuit import Parameter, ParameterVector, QuantumCircuit
from qiskit.circuit.library import UnitaryOverlap
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService, Sampler
# from qiskit_serverless import IBMServerlessClient, QiskitFunction
from qiskit_ibm_catalog import QiskitServerless, QiskitFunction
def visualize_counts(res_counts, num_qubits, num_shots):
"""Visualize the outputs from the Qiskit Sampler primitive."""
zero_prob = res_counts.get(0, 0.0)
top_10 = dict(
sorted(res_counts.items(), key=lambda item: item[1], reverse=True)[
:10
]
)
top_10.update({0: zero_prob})
by_key = dict(sorted(top_10.items(), key=lambda item: item[0]))
x_vals, y_vals = list(zip(*by_key.items()))
x_vals = [bin(x_val)[2:].zfill(num_qubits) for x_val in x_vals]
y_vals_prob = []
for t in range(len(y_vals)):
y_vals_prob.append(y_vals[t] / num_shots)
y_vals = y_vals_prob
plt.bar(x_vals, y_vals)
plt.xticks(rotation=75)
plt.title("Results of sampling")
plt.xlabel("Measured bitstring")
plt.ylabel("Probability")
plt.show()
def get_training_data():
"""Read the training data."""
df = pd.read_csv("dataset_graph7.csv", sep=",", header=None)
training_data = df.values[:20, :]
ind = np.argsort(training_data[:, -1])
X_train = training_data[ind][:, :-1]
return X_train
7[1A[1G[27G[Files: 0 Bytes: 0 [0 B/s] Re]87[2A[1G[27G[https://raw.githubusercontent.]87[1S[3A[1G[0JSaving 'dataset_graph7.csv.1'
87[2A[1Gdataset_graph7.csv.1 100% [=============================>] 20.25K --.-KB/s87[1S[3A[1G[0JHTTP response 200 [https://raw.githubusercontent.com/qiskit-community/prototype-quantum-kernel-training/main/data/dataset_graph7.csv]
87[2A[1Gdataset_graph7.csv.1 100% [=============================>] 20.25K --.-KB/s87[1A[1G[27G[Files: 1 Bytes: 20.25K [93.33]8[m[m[m[m
Pasul 1: Mapează intrările clasice la o problemă cuantică
- Intrare: Set de date de antrenament.
- Ieșire: Circuit abstract pentru calculul unei intrări în matricea de kernel.
Creează circuitul cuantic utilizat pentru evaluarea unei intrări din matricea de kernel. Folosim datele de intrare pentru a determina unghiurile de rotație ale porților parametrizate ale circuitului. Vom folosi eșantioanele de date x1=14 și x2=19.
Notă: Setul de date utilizat în acest tutorial poate fi descărcat aici.
# Prepare training data
X_train = get_training_data()
# Empty kernel matrix
num_samples = np.shape(X_train)[0]
kernel_matrix = np.full((num_samples, num_samples), np.nan)
# Prepare feature map for computing overlap
num_features = np.shape(X_train)[1]
num_qubits = int(num_features / 2)
entangler_map = [[0, 2], [3, 4], [2, 5], [1, 4], [2, 3], [4, 6]]
fm = QuantumCircuit(num_qubits)
training_param = Parameter("θ")
feature_params = ParameterVector("x", num_qubits * 2)
fm.ry(training_param, fm.qubits)
for cz in entangler_map:
fm.cz(cz[0], cz[1])
for i in range(num_qubits):
fm.rz(-2 * feature_params[2 * i + 1], i)
fm.rx(-2 * feature_params[2 * i], i)
# Assign tunable parameter to known optimal value and set the data params for first two samples
x1 = 14
x2 = 19
unitary1 = fm.assign_parameters(list(X_train[x1]) + [np.pi / 2])
unitary2 = fm.assign_parameters(list(X_train[x2]) + [np.pi / 2])
# Create the overlap circuit
overlap_circ = UnitaryOverlap(unitary1, unitary2)
overlap_circ.measure_all()
overlap_circ.draw("mpl", scale=0.6, style="iqp")
Pasul 2: Optimizează problema pentru execuția pe hardware cuantic
- Intrare: Circuit abstract, neoptimizat pentru un anumit Backend
- Ieșire: Circuit țintă și observabil, optimizat pentru QPU-ul selectat
Folosește funcția generate_preset_pass_manager din Qiskit pentru a specifica o rutină de optimizare pentru circuitul nostru în raport cu QPU-ul pe care plănuim să rulăm experimentul. Setăm optimization_level=3, ceea ce înseamnă că vom folosi managerul de treceri preset care oferă cel mai înalt nivel de optimizare.
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=overlap_circ.num_qubits
)
pm = generate_preset_pass_manager(optimization_level=3, backend=backend)
overlap_ibm = pm.run(overlap_circ)
overlap_ibm.draw("mpl", scale=0.6, idle_wires=False, fold=-1, style="iqp")
Pasul 3: Execută folosind primitivele Qiskit
- Intrare: Circuit țintă
- Ieșire: Distribuție quasi-probabilistică
Folosește primitiva Sampler din Qiskit Runtime pentru a reconstitui o distribuție quasi-probabilistică a stărilor obținute prin eșantionarea circuitului. Pentru sarcina de generare a unei matrice de kernel, suntem în special interesați de probabilitatea de a măsura starea |0>.
Pentru această demonstrație, vom rula pe un QPU cu primitivele qiskit-ibm-runtime. Pentru a rula cu primitivele bazate pe vectorul de stare din qiskit, înlocuiește blocul de cod care folosește primitivele Qiskit IBM® Runtime cu blocul comentat.
num_shots = 10_000
## Evaluate the problem using statevector-based primitives from Qiskit
# from qiskit.primitives import StatevectorSampler
# sampler = StatevectorSampler()
# results = sampler.run([overlap_circ]).result()
# counts = results[0].data.meas.get_int_counts()
# Evaluate the problem using a QPU via Qiskit IBM Runtime
sampler = Sampler(mode=backend)
results = sampler.run([overlap_ibm]).result()
counts = results[0].data.meas.get_int_counts()
visualize_counts(counts, num_qubits, num_shots)
Pasul 4: Post-procesează și returnează rezultatul în formatul clasic dorit
- Intrare: Distribuție de probabilitate
- Ieșire: Un singur element din matricea de kernel
Calculează probabilitatea de a măsura |0> pe circuitul de suprapunere și populează matricea de kernel în poziția corespunzătoare eșantioanelor reprezentate de acest circuit de suprapunere particular (rândul 15, coloana 20). În această vizualizare, roșul mai închis indică fidelități mai aproape de 1.0. Pentru a completa întreaga matrice de kernel, trebuie să rulăm un experiment cuantic pentru fiecare intrare.
# Calculate the fidelity, or the probability to measure 0
kernel_matrix[x1, x2] = counts.get(0, 0.0) / num_shots
print(f"Fidelity: {kernel_matrix[x1, x2]}")
Fidelity: 0.1279
Implementează pattern-ul Qiskit în cloud
Pentru a face acest lucru, mută codul sursă de mai sus într-un fișier, ./source/generate_kernel_entry.py, înfășoară codul într-un script care primește intrări și returnează soluția finală, și în cele din urmă încarcă-l pe un cluster la distanță folosind clasa QiskitFunction din Qiskit Serverless. Pentru îndrumări privind specificarea dependențelor externe, transmiterea argumentelor de intrare și altele, consultă ghidurile Qiskit Serverless.
Intrarea în Pattern este o pereche de eșantioane de date, x1 și x2. Ieșirea este fidelitatea dintre cele două eșantioane. Această valoare va fi folosită pentru a popula intrarea din matricea de kernel corespunzătoare acestor două eșantioane.
serverless = QiskitServerless()
kernel_entry_pattern = QiskitFunction(
title="generate-kernel-entry",
entrypoint="generate_kernel_entry.py",
working_dir="./source/",
)
serverless.upload(kernel_entry_pattern)
Rulează pattern-ul Qiskit ca un serviciu gestionat
Odată ce am încărcat pattern-ul în cloud, îl putem rula cu ușurință folosind clientul IBMServerlessProvider. Pentru simplitate, vom folosi un simulator cuantic exact în mediul cloud, deci fidelitatea pe care o calculăm va fi exactă.
generate_kernel_entry = serverless.load("generate-kernel-entry")
job = generate_kernel_entry.run(
sample1=list(X_train[x1]), sample2=list(X_train[x2])
)
kernel_matrix[x1, x2] = job.result()["fidelity"]
print(f"fidelity: {kernel_matrix[x1, x2]}")
Sondaj tutorial
Te rog să completezi acest scurt sondaj pentru a oferi feedback despre acest tutorial. Părerile tale ne vor ajuta să îmbunătățim ofertele de conținut și experiența utilizatorului.
Note: This survey is provided by IBM Quantum and relates to the original English content. To give feedback on doQumentation's website, translations, or code execution, please open a GitHub issue.