Sari la conținutul principal

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[Files: 0  Bytes: 0  [0 B/s] Re]87[https://raw.githubusercontent.]87Saving 'dataset_graph7.csv.1'
87dataset_graph7.csv.1 100% [=============================>] 20.25K --.-KB/s87HTTP response 200 [https://raw.githubusercontent.com/qiskit-community/prototype-quantum-kernel-training/main/data/dataset_graph7.csv]
87dataset_graph7.csv.1 100% [=============================>] 20.25K --.-KB/s87[Files: 1 Bytes: 20.25K [93.33]8

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

Output of the previous code cell

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

Output of the previous code cell

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)

Output of the previous code cell

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

kernel_matrix.png

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.

Link către sondaj

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.