May 03, 2024 | 8 min read

\( \newcommand{\bra}[1]{\langle #1|} \) \( \newcommand{\ket}[1]{|#1\rangle} \) \( \newcommand{\braket}[2]{\langle #1|#2\rangle} \) \( \newcommand{\ketbra}[2]{| #1\rangle \langle #2|} \) \( \newcommand{\i}{{\color{blue} i}} \) \( \newcommand{\Hil}{{\mathbb H}} \) \( \newcommand{\boldn}{{\bf n}} \) \( \newcommand{\tr}{{\rm tr}}\) \( \newcommand{\bn}{{\bf n}} \)

Consulta la notaci贸n que se ha utilizado durante todo el documento en el siguiente enlace.

5. Quantum Kernels#

En esta secci贸n, se tratar谩n los m茅todos kernel. En primer lugar se presentar谩n los kernel cl谩sicos, para luego trasladar esta misma idea a la computaci贸n cu谩ntica. A su vez, se presentar谩n algunas implementaciones de kernel cu谩ntico y se mostrar谩 la matriz asociada a cada caso.

5.1. Introducci贸n a los m茅todos kernel#

Los m茅todos kernel representan los datos en un n煤mero de dimensiones mayor por lo que ayudan a encontrar nuevos patrones en los datos. Estas t茅cnicas son muy utilizadas en aprendizaje supervisado, ya que permiten transformar los problemas no lineales en lineales donde los datos son representandos en un espacio de mayor dimensi贸n.

La expresi贸n general de los kernel es \(k(\mathbf{x_{i}},\mathbf{x_{j}}) = \langle f(\mathbf{x_{i}}), f(\mathbf{x_{j}}) \rangle\) donde \(\mathbf{x_{i}}\) y \(\mathbf{x_{j}}\) corresponden a los datos de entradas de dimensi贸n \(n\), \(f\) representa la funci贸n que transforma los datos de entradas de dimensi贸n \(n\) en un espacio de dimensi贸n \(m\) y \(\langle \mathbf{a}, \mathbf{b} \rangle\) denota el producto interno. Considerando un conjunto de datos, la funci贸n kernel se puede representar mediante una matriz, conocida como matriz kernel, \(K_{ij} = K(\mathbf{x_{i}},\mathbf{x_{j}})\) [32].

A continuaci贸n,en la Fig. 9, se muestra un ejemplo visual para comprender la idea en la que se basan los kernel.

../../_images/EjemploDataset_kernel.PNG

Fig. 9 Visualizaci贸n del dataset de ejemplo en 2D [1].#

Este conjunto de datos (dataset en ingl茅s) cuenta con dos clases (azul y morada) y se aprecia una clara estructura en los datos de n dimensiones. Concretamente se distinguen dos circulos cada uno de ellos corresponde a una clase y uno est谩 dentro del otro. Por lo tanto, en dos dimensiones no se puede separar las clases linealmente, en otras palabras, la frontera de decisi贸n no ser谩 lineal. Se trata de trasladar los datos a un espacio de dimensi贸n mayor para as铆 poder separar ambas clases. En este caso en particular se define la tercera dimensi贸n como \(z = x^2+y^2\). En la Fig. 10 se muestra lo comentado:

../../_images/featureMap_KERNEL.PNG

Fig. 10 Figure 2. Visualizaci贸n del objetivo de los m茅todos kernel [32].#

Se observa que cuando los datos se representan en tres dimensiones existe un hiperplano que clasifica correctamente ambas clases. Proyectando el hiperplano de nuevo en las dimensiones originales la frontera de decisi贸n es no lineal. Cabe destacar que esta manera de trabajar con la no linealidad en los modelos proporcionan la posibilidad de reconocer patrones en el espacio de datos original.

Nota

En algunas fuentes de informaci贸n la expresi贸n del kernel se expresa \(K(\mathbf{x_{i}},\mathbf{x_{j}}) = \phi(\mathbf{x_{j}})^T \phi(\mathbf{x_{i}})\), en este caso la funci贸n que realiza el mapeo se denota mediante \(\phi()\). Esta funci贸n tambi茅n se conoce como feature map [14].

Los m茅todos kernel son muy utilizados junto al algoritmo support vector machine (SVM) en conjuntos de datos no lineales, debido a la transformaci贸n de los conjuntos de datos a lineales donde este algoritmo trata de encontrar el hiperplano \((\mathbf{w},b)\) que mejor separa las distintas clases. En este 4. Quantum Support Vector Machines (QSVM) se puede encontrar m谩s informaci贸n a cerca de esta t茅cnica de clasificaci贸n.

5.2. Introducci贸n al kernel cu谩ntico#

Una vez se ha comentado la idea que persiguen los m茅todos kernel en computaci贸n cl谩sica se aborda el funcionamiento de estas t茅cnicas en computaci贸n cu谩ntica. Para visualizar la idea general y el funcionamiento de ambos tipos de kernel se adjunta la Fig. 11:

../../_images/ClassicalKernel_QuantumKernel.PNG

Fig. 11 Comparaci贸n entre kernel cl谩sico y cu谩ntico [12].#

Como se aprecia en la Fig. 11 en ambos casos se trabaja con un feature map que se denota como \(\phi(\mathbf{x})\), se encarga de transformar los datos del espacio de datos original a un nuevo espacio de caracter铆sticas. No obstante, aunque existen similitudes en lo que se refiere al concepto, tambi茅n se aprecian diferencias en la expresi贸n de la funci贸n kernel o que la funci贸n kernel cu谩ntica adem谩s de llevar a cabo el cambio de dimensi贸n, transforma los datos en estados cu谩nticos.

Tal y como se adelantaba en la comparaci贸n representada en la Fig. 11, al tratar datos cl谩sicos medicante algoritmos de Quantum Machine Learning estos mismos deben encargarse de codificar los datos en estados cu谩nticos para posteriormente poder trabajar con ellos. Este proceso es equivalente a una funci贸n feature map que asigna los valores a estados cu谩nticos, concretamente \(\phi(\mathbf{x})\) mapea el vector de caracter铆sticas \(\mathbf{x}\) en el espacio de Hilbert \(\ket{\phi(\mathbf{x})}\bra{\phi(\mathbf{x})}\) [32]. Mediante la funci贸n kernel se lleva a cabo la codificaci贸n de los datos, conocida como data_encoding. El quantum kernel se puede interpretar como una medida de similitud, de forma que \(k(\mathbf{x_{i}},\mathbf{x_{j}})\) tomar谩 un valor elevado cuando \(\mathbf{x_{i}}\) y \(\mathbf{x_{j}}\) sean cercanos [18].

La codificaci贸n de los datos es una fase fundamental en QML y exiten varias t茅cnicas que abordan este reto, en este 2. Feature encoding se puede encontrar m谩s informaci贸n a cerca de esta tem谩tica.

Entender los modelos cu谩nticos como m茅todos kernel significa que la expresividad, optimizaci贸n y el comportamiento al generalizar los modelos est谩n determinados en gran medida por la estrategia de codificaci贸n, la cual viene fijada por el m茅todo kernel [35]. Adem谩s significa que aunque el propio kernel puede explorar espacios de datos de dimensionalidad alta en el sistema cu谩ntico y los modelos cu谩nticos pueden entrenar y operar en subespacios de dimensiones m谩s bajas.

Al igual que en el caso cl谩sico, el puente entre el QML y los m茅todos kernel esta formado por la observaci贸n de que los modelos cu谩nticos mapean los datos en una dimensi贸n superior en la cual la medida define una frontera de decisi贸n lineal.

5.3. Distintas implementaciones de kernel#

El entrenamiento basado en m茅todos kernel pasan por alto el procesado y la medici贸n que implementan los circuitos variacionales, de manera que solo depender谩 de la codificaci贸n de los datos [17].

A continuaci贸n se adjunta una implementeaci贸n de distintos tipos de m茅todos kernel. Por un lado, se muestran dos ejemplos de Quantum Kernel Estimation (QKE). Por otro lado, se adjunta el c贸digo para el denominado swap test. Para comprobar el correcto funcionamiento de estos ejemplos, se har谩 uso del dataset iris, ya que se trata de un problema de clasificaci贸n sencillo.

## Se cargan las librerias necesarias para porder ejecutar las pr贸ximas celdas
import numpy as np

from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split

from qibo import callbacks, gates, hamiltonians, models
from qibo.models import Circuit
from qibo.symbols import X, Y, Z, I

import seaborn as sns

from qibo import set_backend
#Uso de backend de numpy en Qibo
set_backend("numpy")
[Qibo 0.1.12.dev0|INFO|2024-06-11 12:06:48]: Using numpy backend on /CPU:0
# Generamos el dataset mediante la funci贸n "load_iris".
# Almacenamos los datos de entrada (inputs) en X y la etiqueta (label) correspondiente en y.
X, y = load_iris(return_X_y=True)

# Seleccionamos unicamente los inputs y labels de las dos primeras clases,
# esto corresponde a seleccionar las primeras 100 instancias
X = X[:100]
y = y[:100]

# Estandarizar los valores de los datos de entrada es importante
scaler = StandardScaler().fit(X)
X_scaled = scaler.transform(X)

# Cambiamos los valores de las etiquetas a -1, 1. Se trata de un proceso importante para el clasificador SVM
# y la definici贸n de la funci贸n de coste.
y_scaled = 2 * (y - 0.5)

X_train, X_test, y_train, y_test = train_test_split(X_scaled, y_scaled, random_state=123)

Se adjunta la funci贸n kernel_matrix, esta ser谩 la que se utilice para calcular la matriz kernel. Todas las implementaciones finalizan obteniendo la matriz kernel y mostrandola gr谩ficamente.

def kernel_matrix(kernel,A, B, nqubits):

    return np.array([[kernel(a, b, nqubits) for b in B] for a in A])

5.3.1. SWAP test#

Para implementar el kernel se preparan los estados \(\ket{\phi(\mathbf{x_{i}})},\ket{\phi(\mathbf{x_{j}})}\) en conjuntos de c煤bits diferentes mediante rutinas de codificaci贸n, \(U(\mathbf{x_{i}}), U(\mathbf{x_{j}})\). Generalmente este primer paso se suele llevar a cabo mediante rotaciones, en el ejemplo que se muestra a continuaci贸n se trabaja con rotaciones en el eje Y. Tras codificar los datos cl谩sicos en estado cu谩nticos, se mide el solapamiento con una rutina que se denomina SWAP test [34].

../../_images/SwapTest_kernel.PNG

Fig. 12 Circuito asociado a la rutina SWAP test.#

En la Fig. 12 anterior se muestra el circuito necesario para implementar esta rutina y a continuaci贸n se implementa esta rutina.

# Definimos el n煤mero de qubits necesarios
nqubits=5

def circ_kernel_swap(x1, x2, nqubits):
    # Inicializamos el circuito con "nqubits"
    c= Circuit(nqubits=nqubits)
    
    # Generamos el Feature map mediante puertas RY
    c.add(gates.RY(q=1, theta=x1[0]))
    c.add(gates.RY(q=2, theta=x1[1]))
    c.add(gates.RY(q=3, theta=x2[0]))
    c.add(gates.RY(q=4, theta=x2[1]))
    
    # Kernel swap    
    c.add(gates.H(q=0))
    c.add(gates.SWAP(1,3).controlled_by(0))
    c.add(gates.SWAP(2,4).controlled_by(0))
    c.add(gates.H(q=0))
    
    # A帽adimos la medida en el qubit 0
    c.add(gates.M(0))
    
    return c


# Definimos el observable necesario para calcular el valor esperado
def hamiltonian():
    Obj = np.prod([ Z(0), I(1), I(2), I(3), I(4)])
    h = hamiltonians.SymbolicHamiltonian(Obj)
    return h

# Calculamos el valor esperado que produce el circuito
def expVal_swap_test(x1, x2, nqubits, nshots=10000):
    c = circ_kernel_swap(x1, x2, nqubits)
    h = hamiltonian()
    expected_value = h.expectation(c.execute().state())
    
    return expected_value

En la siguiente celda se comprueba el correcto funcionamiento de la funci贸n kernel_swap, la comprobaci贸n consiste en medir el solapamiento de un ejemplo con el mismo, por lo que el resultado debe ser 1.

# Se comprueba que el funcionamiento es adecuado.
expVal_swap_test(X_train[0], X_train[0], nqubits) 
0.9999999999999997

Se analiza la matriz kernel

# Calculamos la matriz kernel al completo
matriz_swap = kernel_matrix(expVal_swap_test, X_train, X_train, nqubits)
# Mostrar la matriz kernel mediante un mapa de calor.

sns.set(rc = {'figure.figsize':(12,8)})
sns.heatmap(matriz_swap, vmin = 0, vmax = 1, cmap=sns.color_palette("Blues", as_cmap=True));
../../_images/cc657f2f10ea14033b602237ffaa31fdd950785756c4a8cbb43e543d8c98900c.png

Se puede observar de la matriz kernel lo siguiente:

  1. Cada fila / columna representa la amplitud de transici贸n de una muestra, con todos las dem谩s muestras del conjunto de datos.

  2. La amplitud de transici贸n de una muestra consigo mismo es 1, por lo que la matriz tiene una diagonal unitaria.

  3. La matriz es sim茅trica, la amplitud de transici贸n de x \(\rightarrow\) y es igual y \(\rightarrow\) x

5.3.2. Quantum Kernel Estimator#

El Quantum Kernel Estimator, QKE, necesita la mitad de c煤bits comparado con la versi贸n de SWAP test y consiste en aplicar el operador unitario de codificaci贸n \(\ket{U(\mathbf{x_{i}})}\) y su inverso en los mismos c煤bits \(\bra{U^{\dagger}(\mathbf{x_{j}})}\) como se visualiza en la Fig. 8.

../../_images/kernel_circuit_ejemplo.png

Fig. 13 Circuito asociado a los Quantum Kernel Estimator [41].#

Por tanto, la f贸rmula del kernel, K, se define como,

\[ K(\mathbf{x_{i}},\mathbf{x_{j}}) = |\braket{\phi(\mathbf{x_{j}})}{\phi(\mathbf{x_{i}})}|^2 = |\bra{0..0}U(\mathbf{x_{j}})^{\dagger}U(\mathbf{x_{i}})\ket{0..0}|^2\]

El QKE se puede implementar en dos versiones de circuitos que se expone a continuaci贸n:

  1. proyector

  2. probabilidades

En las siguientes celdas se implementa el mismo kernel de dos formas distintas. En ambos casos la codificaci贸n se lleva a cabo mediante angle embedding y luego se aplica el adjunto tal y como se comentaba. La diferencia viene a la hora de calcular el solapamiento, en el primer caso se utiliza el proyector y en el segundo se calcula la probabilidad de \(\ket{0}\).

Se hace uso de la codificaci贸n angle embedding por lo que ser谩n necesarios tantos c煤bits como car谩cteristicas tiene el dataset, se puede obtener m谩s informaci贸n a cerca de esta codificaci贸n en el siguiente 2. Feature encoding.

En primer lugar, se obtiene el n煤mero de caracter铆sticas de cada muestra en el dataset Iris, con el que se est谩 trabajando en este ejemplo. Por ello, el n煤mero de c煤bits ser谩 el n煤mero de caracter铆stica por muestra del conjunto de datos.

n_qubits = len(X_train[0])
print("N煤mero de qubits:", n_qubits)
N煤mero de qubits: 4

5.3.2.1. Quantum Kernel Estimator (QKE) - proyector#

nqubits = len(X_train[0]) 

def circ_kernel_QKE(x, y, nqubits):
    
    # cuatro c煤bits: cuatro caracter铆sticas
    n_shots = 8000

    # Inicializar el circuito, generar un circuito vacio
    circuit = Circuit(n_qubits)

    # Codificaci贸n cu谩ntica en puertas RY y medir todos los qubits
    for pos in range(n_qubits):
        circuit.add(gates.RY(pos, y[pos]))
        circuit.add(gates.RY(pos, x[pos]).dagger())
        circuit.add(gates.M(pos))
    
    return circuit


# Definir el observable
def hamiltonian():
    Obj = np.prod([ Z(0), I(1), I(2), I(3)])
    h = hamiltonians.SymbolicHamiltonian(Obj)
    return h

# Ejecutar el circuito y calcular el valor esperado
def expVal_swap_QKE(x1, x2, nqubits, nshots=10000):
    c = circ_kernel_QKE(x1, x2, nqubits)
    h = hamiltonian()
    expected_value = h.expectation(c.execute().state())
    
    return expected_value

Se verifica que funciona correctamente el kernel cu谩ntico con un dato consigo mismo. Tal y como se ha comentado anteriormente, el resultado deber铆a ser 1.

# Se comprueba que el funcionamiento es adecuado.
expVal_swap_QKE(X_train[0], X_train[0],nqubits)
0.9999999999999996

Se analiza la matriz kernel

# Calculamos la matriz kernel al completo
matriz_proyector = kernel_matrix(expVal_swap_QKE, X_train, X_train, nqubits)
sns.set(rc = {'figure.figsize':(12,8)})
sns.heatmap(matriz_proyector, vmin = 0, vmax = 1, cmap=sns.color_palette("Blues", as_cmap=True));
../../_images/8ca170a7f4f161b4fcbdfad337cf1cb326ed03eb9a3e52df6e3c92fb14896af1.png

5.3.2.2. Quantum Kernel Estimator (QKE) - probabilidades#

En este caso sin embargo, en lugar de utilizar el proyector se hace uso de la probabilidad del \(\ket{0}\) para calcular el solapamiento.

# kernel cu谩ntico
def distancia_circuit(x,y,n_qubits):
    
    # cuatro c煤bits: cuatro caracter铆sticas
    n_shots = 8000

    # Create an empty circuit
    circuit = Circuit(n_qubits)

    # Codificaci贸n cu谩ntica en puertas RY 
    for pos in range(n_qubits):
        circuit.add(gates.RY(pos, y[pos]))
        circuit.add(gates.RY(pos, x[pos]).dagger())
        circuit.add(gates.M(pos))

    # ejecuci贸n del circuito n veces (n_shots)
    result = circuit.execute(nshots=n_shots)

    # Devuelve las probabilidades anal铆ticas
    return result.probabilities()
       
# Se devuelve el probabilidad del base computacional "0000"
kernel = lambda x1, x2, n_qubits: distancia_circuit(x1, x2, n_qubits)[0]

Se verifica que funciona correctamente el kernel cu谩ntico con un dato consigo mismo. El resultado deber铆a ser 1.

#Se comprueba que el funcionamiento es adecuado.
kernel(X_train[0], X_train[0], nqubits) 
0.9999999999999996

Se analiza la matriz kernel

# Calculamos la matriz kernel al completo
matriz_prob = kernel_matrix(kernel,X_train,X_train,n_qubits)
sns.set(rc = {'figure.figsize':(12,8)})
sns.heatmap(matriz_prob, vmin = 0, vmax = 1, cmap=sns.color_palette("Blues", as_cmap=True));
../../_images/69a55c30c5dca5f39c93c58929a6e1583f93c6cadcdc9344bb8fe04ad5f11426.png

Como se puede ver es indiferente calcular el solapamiento mediante proyectores o calculando la probabilidad de \(\ket{0}\), se puede observar que la matriz kernel es la misma siempre y cuando se aplique el mismo m茅todo de codificaci贸n.

Nota (Anexo notaci贸n)

Para que la comprensi贸n de los notebooks sea mejor se ha unificado la notaci贸n utilizada en los mismos. Para diferenciar un vector de un valor 煤nico se har谩 uso de la negrita. De manera que \(\mathbf{x}\) corresponde a un vector y \(z\) ser谩 una variable de una 煤nica componente.

Si se quiere hacer referencia a dos vectores distintos pero que pertenecen al mismo dataset se utilizar谩 un sub铆ndice, es decir, \(\mathbf{x_i}\) har谩 referencia al i-茅simo vector del dataset. Si se quiere referenciar una caracter铆stica concreta del vector se a帽adir谩 un nuevo sub铆ndice, de manera que \(\mathbf{x_{i_j}}\) har谩 referencia a la j-茅sima variable del i-茅simo vector.


Autores:

Carmen Calvo (SCAYLE), Antoni Alou (PIC), Carlos Hernani (UV), Nahia Iriarte (NASERTIC) y Carlos Luque (IAC)

../../_images/LOGO-SCAILE.png ../../_images/Logo_pic.png ../../_images/Logo_UV.jpg ../../_images/Logo_Nasertic.png ../../_images/Logo_IAC.jpg
https://quantumspain-project.es/wp-content/uploads/2022/11/Logo_QS_EspanaDigital.png
Licencia Creative Commons

License: Licencia Creative Commons Atribuci贸n-CompartirIgual 4.0 Internacional.

This work has been financially supported by the Ministry for Digital Transformation and of Civil Service of the Spanish Government through the QUANTUM ENIA project call - Quantum Spain project, and by the European Union through the Recovery, Transformation and Resilience Plan - NextGenerationEU within the framework of the Digital Spain 2026 Agenda.