Vai al contenuto principale

Addestramento del kernel quantistico

Stima di utilizzo: meno di un minuto su un processore Eagle r3 (NOTA: Questa è solo una stima. Il tempo di esecuzione effettivo potrebbe variare.)

Contesto​

Questo tutorial mostra come costruire un pattern Qiskit per valutare le voci in una matrice kernel quantistica utilizzata per la classificazione binaria. Per ulteriori informazioni sui pattern Qiskit e su come Qiskit Serverless può essere utilizzato per distribuirli nel cloud per un'esecuzione gestita, visitate la nostra pagina della documentazione su IBM Quantum® Platform.

Requisiti​

Prima di iniziare questo tutorial, assicuratevi di avere installato quanto segue:

  • Qiskit SDK v1.0 o successiva, con supporto per la visualizzazione
  • Qiskit Runtime v0.22 o successiva (pip install qiskit-ibm-runtime)

Configurazione​

# 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

Passaggio 1: Mappare gli input classici a un problema quantistico​

  • Input: Dataset di addestramento.
  • Output: Circuito astratto per calcolare una voce della matrice kernel.

Create il circuito quantistico utilizzato per valutare una voce nella matrice kernel. Utilizziamo i dati di input per determinare gli angoli di rotazione per i gate parametrizzati del circuito. Useremo i campioni di dati x1=14 e x2=19.

Nota: Il dataset utilizzato in questo tutorial può essere scaricato qui.

# 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

Passaggio 2: Ottimizzare il problema per l'esecuzione su hardware quantistico​

  • Input: Circuito astratto, non ottimizzato per un particolare backend
  • Output: Circuito target e osservabile, ottimizzati per la QPU selezionata

Utilizzate la funzione generate_preset_pass_manager di Qiskit per specificare una routine di ottimizzazione per il nostro circuito rispetto alla QPU su cui pianifichiamo di eseguire l'esperimento. Impostiamo optimization_level=3, il che significa che utilizzeremo il pass manager preimpostato che fornisce il livello più alto di ottimizzazione.

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

Passaggio 3: Eseguire utilizzando le primitive Qiskit​

  • Input: Circuito target
  • Output: Distribuzione di quasi-probabilità

Utilizzate la primitiva Sampler di Qiskit Runtime per ricostruire una distribuzione di quasi-probabilità degli stati ottenuti dal campionamento del circuito. Per il compito di generare una matrice kernel, siamo particolarmente interessati alla probabilità di misurare lo stato |0>.

Per questa demo, eseguiremo su una QPU con le primitive qiskit-ibm-runtime. Per eseguire con le primitive basate su statevector di qiskit, sostituite il blocco di codice che utilizza le primitive IBM® Runtime con il blocco commentato.

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

Passaggio 4: Post-elaborare e restituire il risultato nel formato classico desiderato​

  • Input: Distribuzione di probabilità
  • Output: Un singolo elemento della matrice kernel

Calcolate la probabilità di misurare |0> sul circuito di sovrapposizione e popolate la matrice kernel nella posizione corrispondente ai campioni rappresentati da questo particolare circuito di sovrapposizione (riga 15, colonna 20). In questa visualizzazione, il rosso più scuro indica fedeltà più vicine a 1.0. Per completare l'intera matrice kernel, dobbiamo eseguire un esperimento quantistico per ogni voce.

# 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

Distribuire il pattern Qiskit nel cloud​

Per fare ciò, spostate il codice sorgente sopra in un file, ./source/generate_kernel_entry.py, racchiudete il codice in uno script che accetta input e restituisce la soluzione finale, e infine caricatelo su un cluster remoto utilizzando la classe QiskitFunction di Qiskit Serverless. Per indicazioni su come specificare le dipendenze esterne, passare argomenti di input e altro, consultate le guide di Qiskit Serverless.

L'input al Pattern è una coppia di campioni di dati, x1 e x2. L'output è la fedeltà tra i due campioni. Questo valore verrà utilizzato per popolare la voce della matrice kernel corrispondente a questi due campioni.

serverless = QiskitServerless()

kernel_entry_pattern = QiskitFunction(
title="generate-kernel-entry",
entrypoint="generate_kernel_entry.py",
working_dir="./source/",
)

serverless.upload(kernel_entry_pattern)

Eseguire il pattern Qiskit come servizio gestito​

Una volta caricato il pattern nel cloud, possiamo eseguirlo facilmente utilizzando il client IBMServerlessProvider. Per semplicità, utilizzeremo un simulatore quantistico esatto nell'ambiente cloud, quindi la fedeltà che calcoliamo sarà esatta.

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

Sondaggio sul tutorial​

Per favore, compilate questo breve sondaggio per fornire feedback su questo tutorial. Le vostre opinioni ci aiuteranno a migliorare i nostri contenuti e l'esperienza utente.

Link al sondaggio