Treinamento de kernel quântico
Estimativa de uso: menos de um minuto em um processador Heron r3 (NOTA: Esta é apenas uma estimativa. Seu tempo de execução pode variar.)
Resultados de aprendizagem
Após concluir este tutorial, você poderá compreender as seguintes informações:
- Métodos de kernel e seus usos
- Kernels quânticos e como podem fornecer espaços de características aprimorados
- Construção de circuitos de kernel quântico
- Como treinar um kernel quântico usando um padrão Qiskit: mapear, otimizar, executar e pós-processar
Pré-requisitos
É recomendado que você se familiarize com kernels quânticos, por que são importantes e como são usados na prática.
- Covariant quantum kernels for data with group structure (artigo)
- Introduction to Quantum Kernels and Support Vector Machines (vídeo)
- Quantum Kernels in Practice (vídeo)
Também é útil ter uma compreensão básica de teoria de grupos.
Contexto
Os métodos de kernel são comuns em aplicações de aprendizado de máquina. Neste contexto, "kernel" refere-se à matriz de kernel ou às entradas individuais desta. Em geral, um kernel é uma medida de similaridade entre dados codificados em um espaço de características de alta dimensão e pode ser utilizado, por exemplo, em tarefas de classificação com máquinas de vetores de suporte.
Os métodos de kernel quântico são aqueles que utilizam computadores quânticos para estimar um kernel. É sabido que computadores quânticos podem codificar dados em espaços de características aprimorados quanticamente, substituindo efetivamente os análogos clássicos. Para e , tipicamente com , é um mapa de características, . O objetivo de é fazer com que as categorias de dados sejam separadas por um hiperplano. Tomando os vetores no espaço mapeado por características como argumentos, a função kernel retorna seu produto interno: . Classicamente, os mapas de características de interesse são aqueles nos quais a função kernel pode ser facilmente avaliada; ou seja, quando o produto interno no espaço mapeado por características pode ser escrito em termos dos vetores de dados originais e e não precisam ser construídos. No caso de kernels quânticos, o mapeamento de características é realizado por um circuito quântico, e o kernel é estimado usando as probabilidades de medição amostradas do circuito.
Este tutorial mostra como construir um padrão Qiskit para avaliar entradas em uma matriz de kernel quântico usada para classificação binária.
Requisitos
Antes de iniciar este tutorial, certifique-se de ter o seguinte instalado:
- Qiskit SDK v2.3.1 ou posterior, com suporte para visualização
- Qiskit Runtime v0.44.0 ou posterior (
pip install qiskit-ibm-runtime)
Configuração
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy pandas qiskit qiskit-ibm-runtime
# General Imports and helper functions
import urllib.request
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 unitary_overlap
from qiskit.primitives import StatevectorSampler
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService, Sampler
# Download the dataset (portable across platforms)
urllib.request.urlretrieve(
"https://raw.githubusercontent.com/qiskit-community/prototype-quantum-kernel-training/main/data/dataset_graph7.csv",
"dataset_graph7.csv",
)
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
Exemplo com simulador de pequena escala
Nesta seção, percorremos as quatro etapas do padrão Qiskit em uma instância de sete qubits do problema de rotulagem de cosets com erro e avaliamos uma única entrada da matriz de kernel usando a primitiva StatevectorSampler do Qiskit. Um simulador de vetor de estado é exato (exceto pelo ruído de shots) e nos mostra o método de ponta a ponta sem consumir tempo de QPU. Em seguida, repetimos a mesma instância em hardware real na seção de exemplo de hardware.
Etapa 1: Mapear entradas clássicas para um problema quântico
- Entrada: Conjunto de dados de treinamento.
- Saída: Circuito abstrato para calcular uma entrada da matriz de kernel.
O problema de classificação binária que buscamos resolver aqui é denominado "rotulagem de cosets com erro." O conjunto de dados de treinamento de entrada contém uma estrutura de grupo, consistindo em dois cosets formados por um grupo e subgrupo. O grupo é tomado como para qubits, que é o grupo unitário especial de matrizes e tem ampla aplicabilidade na natureza; por exemplo, o Modelo Padrão da física de partículas. Tomamos o subgrupo (estabilizador de grafo) com para um grafo com arestas e vértices . Observe que os estabilizadores fixam um estado estabilizador tal que . Por fim, definimos dois cosets esquerdos sorteando dois aleatoriamente.
Para mais detalhes sobre o conjunto de dados e como ele é gerado, consulte este notebook do Quantum Kernel Training Toolkit.
Criamos o circuito quântico usado para avaliar uma entrada na matriz de kernel.
Os dados de entrada são usados para determinar os ângulos de rotação para as portas parametrizadas do circuito.
Para simplificar, usaremos as amostras de dados x1=14 e x2=19.
Nota: O conjunto de dados usado neste tutorial pode ser baixado aqui.
# 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 = unitary_overlap(unitary1, unitary2)
overlap_circ.measure_all()
overlap_circ.draw("mpl", scale=0.6, style="iqp")
Etapa 2: Otimizar o problema para execução em hardware quântico
- Entrada: Circuito abstrato, não otimizado para um backend específico.
- Saída: Circuito alvo, otimizado para a QPU selecionada.
Para o caminho do simulador de vetor de estado usado nesta seção, nenhuma otimização específica para o backend é necessária: o circuito abstrato pode ser amostrado diretamente. Exercemos esta etapa no exemplo de hardware abaixo, onde o circuito é transpilado contra uma QPU real usando generate_preset_pass_manager com optimization_level=3.
Etapa 3: Executar usando primitivas Qiskit
- Entrada: Circuito abstrato.
- Saída: Distribuição de quasi-probabilidade.
Use a primitiva StatevectorSampler do Qiskit para reconstruir uma distribuição de quasi-probabilidade dos estados produzidos pela amostragem do circuito. Para a tarefa de gerar uma matriz de kernel, estamos particularmente interessados na probabilidade de medir o estado |0>.
sampler = StatevectorSampler()
# Execute and get counts
num_shots = 10_000
results = sampler.run([overlap_circ], shots=num_shots).result()
counts = results[0].data.meas.get_int_counts()
# Plot counts
visualize_counts(counts, num_qubits, num_shots)
Etapa 4: Pós-processar e retornar o resultado no formato clássico desejado
- Entrada: Distribuição de probabilidade.
- Saída: Um único elemento da matriz de kernel.
Calcule a probabilidade de medir no circuito de sobreposição e preencha a matriz de kernel na posição correspondente às amostras representadas por este circuito de sobreposição específico (linha 15, coluna 20).
kernel_matrix[x1, x2] = counts.get(0, 0.0) / num_shots
print(f"Fidelity (simulator): {kernel_matrix[x1, x2]}")
Fidelity (simulator): 0.8261
Exemplo de hardware
Uma matriz de kernel quântico tem entradas para amostras de treinamento, e cada entrada requer a execução de um circuito de sobreposição cuja profundidade de portas de dois qubits cresce com o tamanho do mapa de características. Como resultado, escalar este tutorial para um problema maior tem dois custos compostos: o tempo de QPU por matriz de kernel cresce quadraticamente com , e a profundidade de unitary_overlap (que compõe o mapa de características com seu adjunto) corrói a fidelidade no tamanho e conectividade do sistema do hardware atual. Para manter a demonstração curta e fazer uma comparação limpa, executamos portanto a mesma instância de sete qubits do exemplo de pequena escala em uma QPU real e comparamos a fidelidade de uma única entrada da matriz de kernel com o valor do simulador calculado acima.
# ------------------------------ Step 1 ------------------------------
# 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 = unitary_overlap(unitary1, unitary2)
overlap_circ.measure_all()
# ------------------------------ Step 2 ------------------------------
service = QiskitRuntimeService()
# backend = service.least_busy(
# operational=True, simulator=False, min_num_qubits=overlap_circ.num_qubits
# )
backend = service.backend("ibm_pittsburgh")
print(f"Using backend: {backend.name}")
pm = generate_preset_pass_manager(optimization_level=3, backend=backend)
overlap_ibm = pm.run(overlap_circ)
# ------------------------------ Step 3 ------------------------------
sampler = Sampler(mode=backend)
sampler.options.environment.job_tags = ["TUT_QKT"]
num_shots = 10_000
results = sampler.run([overlap_ibm], shots=num_shots).result()
counts = results[0].data.meas.get_int_counts()
visualize_counts(counts, num_qubits, num_shots)
# ------------------------------ Step 4 ------------------------------
kernel_matrix[x1, x2] = counts.get(0, 0.0) / num_shots
print(f"Fidelity (hardware): {kernel_matrix[x1, x2]}")
Using backend: ibm_pittsburgh
Fidelity (hardware): 0.7517
Para preencher toda a matriz de kernel, executaríamos um experimento quântico para cada uma de suas entradas únicas. A figura abaixo mostra a matriz resultante para este conjunto de dados; vermelho mais escuro indica fidelidades mais próximas de 1.0.
Próximos passos
Se você achou este trabalho interessante, pode se interessar pelo seguinte material:
- Quantum Kernel Training Toolkit - o repositório de protótipo no qual este tutorial é baseado
- Quantum Kernel Training for Machine Learning Applications - um tutorial de Qiskit Machine Learning mostrando como treinar o parâmetro treinável
- Introduction to Quantum Machine Learning - um curso sobre aprendizado de máquina quântico
- Quantum Machine Learning from IBM Research - uma visão geral da pesquisa de QML na IBM
- Covariant quantum kernels for data with group structure - o artigo no qual este tutorial é baseado