Investigar el trabajo ganador del Premio Nobel de Geoffrey Hinton y construirlo desde cero con Pytorch

Un destinatario del Premio Nobel de Física 2024 fue Geoffrey Hinton por sus contribuciones en el campo de la IA y el aprendizaje automático. Mucha gente sabe que trabajó en redes neuronales y se denomina «padrino de IA», pero pocos entienden sus obras. En particular, fue pionero en las máquinas Boltzmann restringidas (RBMS) hace décadas.

Este artículo será un tutorial de RBMS y, con suerte, proporcionará cierta intuición detrás de estas complejas máquinas matemáticas. Proporcionaré algún código sobre la implementación de RBMS desde cero en Pytorch después de pasar por las derivaciones.

Los RBM son una forma de aprendizaje no supervisado (solo las entradas se utilizan para no aprender, no se utilizan etiquetas de salida). Esto significa que podemos extraer automáticamente características significativas en los datos sin depender de las salidas. Un RBM es una red con dos tipos diferentes de neuronas con entradas binarias: visible, incógnitay escondido, H. Las neuronas visibles toman los datos de entrada y las neuronas ocultas aprenden a detectar características/patrones.

RBM con entrada incógnita y capa oculta Y. Fuente: [1]

En términos más técnicos, decimos que un RBM es un modelo gráfico bipartito no dirigido con variables binarias estocásticas visibles y ocultas. El objetivo principal de un RBM es minimizar la energía de la configuración de la junta. MI(X, H) a menudo Uso de aprendizaje contrastante (discutido más adelante).

Una función de energía no corresponde a la energía física, pero proviene de la física/estadísticas. Piense en ello como una función de puntuación. Una función de energía mi Asigna puntajes más bajos (energías) a las configuraciones incógnita Que queremos que nuestro modelo prefiera, y puntajes más altos a las configuraciones que queremos que evite. La función de energía es algo que podemos elegir como diseñadores de modelos.

Para RBMS, la función de energía es la siguiente (modelada después de la distribución de Boltzmann):

Función de energía RBM. Fuente: Autor

La función de energía consta de 3 términos. El primero es la interacción entre la capa oculta y visible con pesos, W. El segundo es la suma de los términos de sesgo para las unidades visibles. El tercero es la suma de los términos de sesgo para las unidades ocultas.

Con la función de energía, podemos calcular la probabilidad de la configuración de la junta dada por la distribución de Boltzmann. Con esta función de probabilidad, podemos modelar nuestras unidades:

Probabilidad para la configuración conjunta para RBMS. Fuente: Autor

Z es la función de partición (también conocida como la constante de normalización). Es la suma de e^(-e) sobre todas las configuraciones posibles de unidades visibles y ocultas. El gran desafío con Z es que generalmente es computacionalmente intratable calcular exactamente porque necesita sumar todas las configuraciones posibles de V y H. Por ejemplo, con unidades binarias, si tienes metro unidades visibles y norte Unidades ocultas, debe sumar más de 2^(metro+ +norte) configuraciones. Por lo tanto, necesitamos una forma de evitar calcular Z.

Con esas funciones y distribuciones definidas, podemos repasar algunas derivaciones de inferencia antes de hablar sobre capacitación e implementación. Ya mencionamos la incapacidad para calcular Z En la distribución de probabilidad conjunta. Para evitar esto, podemos usar el muestreo Gibbs. El muestreo Gibbs es un algoritmo de la cadena de Markov Monte Carlo para el muestreo de una distribución de probabilidad multivariada especificada cuando el muestreo directo de la distribución de la articulación es difícil, pero el muestreo de la distribución condicional es más práctico [2]. Por lo tanto, necesitamos distribuciones condicionales.

La gran parte de un restringido Boltzmann versus un Totalmente conectado Boltzmann es el hecho de que no hay conexiones dentro de las capas. Esto significa que dada la capa visible, todas las unidades ocultas son condicionalmente independientes y viceversa. Veamos lo que eso simplifica para comenzar con pag(x | h):

Distribución condicional P (H | X). Fuente: Autor

Podemos ver que la distribución condicional se simplifica a una función sigmoidea donde J es la fila Jᵗʰ de W. Hay un cálculo mucho más riguroso que he incluido en el apéndice demostrando la primera línea de esta derivación. ¡Comuníquese si está interesado! Observemos ahora la distribución condicional pag(H | X):

Distribución condicional P (x | h). Fuente: Autor

Podemos ver que esta distribución condicional también se simplifica a una función sigmoidea donde k es la fila de kᵗʰ de W. Debido a los criterios restringidos en el RBM, las distribuciones condicionales se simplifican a cálculos fáciles para el muestreo de Gibbs durante la inferencia. Una vez que entendemos qué es exactamente el RBM tratando de aprender, implementaremos esto en Pytorch.

Como con la mayor parte del aprendizaje profundo, estamos tratando de minimizar la probabilidad negativa de log (NLL) para capacitar a nuestro modelo. Para el RBM:

NLL para RBM. Fuente: Autor

Tomando el derivado de este rendimiento:

Derivado de NLL. Fuente: Autor

El primer término en el lado izquierdo de la ecuación se llama fase positiva porque empuja el modelo a reducir la energía de los datos reales. Este término implica tomar la expectativa sobre las unidades ocultas H Dados los datos de entrenamiento reales incógnita. La fase positiva es fácil de calcular porque tenemos los datos de entrenamiento reales xᵗ y podemos calcular las expectativas sobre H debido a la independencia condicional.

El segundo término se llama fase negativa porque aumenta la energía de las configuraciones que el modelo cree que es probable. Este término implica tomar la expectativa sobre ambos incógnita y H bajo la distribución actual del modelo. Es difícil de calcular porque necesitamos probar de la distribución conjunta completa del modelo PAG(x, h) (Hacer esto requiere cadenas de Markov que serían ineficientes para hacer repetidamente en el entrenamiento). La otra alternativa requiere informática Z que ya consideramos inviable. Para resolver este problema de calcular la fase negativa, usamos divergencia contrastante.

La idea clave detrás de la divergencia contrastante es usar el muestreo de Gibbs truncados para obtener una estimación puntual después de K iteraciones. Podemos reemplazar la fase negativa expectativa con esta estimación de punto.

Divergencia contrastante. Fuente: [3]

Típicamente k = 1, pero cuanto más grande es, cuanto menos sesgada sea la estimación del gradiente. No mostraré la derivación de los diferentes parciales con respecto a la fase negativa (para las actualizaciones de peso/sesgo), pero se puede derivar tomando la derivada parcial de mi(x, h) con respecto a las variables. Existe un concepto de divergencia contrastante persistente donde, en lugar de inicializar la cadena a Xᵗ, inicializamos la cadena a la muestra negativa de la última iteración. Sin embargo, tampoco me profundizaré en eso, ya que la divergencia contrastante normal funciona lo suficiente.

Crear un RBM desde cero implica combinar todos los conceptos que hemos discutido en una sola clase. En el constructor __init__, inicializamos los pesos, el término de sesgo para la capa visible, el término de sesgo para la capa oculta y el número de iteraciones para la divergencia contrastante. Todo lo que necesitamos es el tamaño de los datos de entrada, el tamaño de la variable oculta y k.

También necesitamos definir una distribución de Bernoulli a la muestra de. La distribución de Bernoulli se sujeta para evitar un gradiente explosivo durante el entrenamiento. Ambas distribuciones se usan en el pase hacia adelante (divergencia contrastante).

class RBM(nn.Module):
"""Restricted Boltzmann Machine template."""

def __init__(self, D: int, F: int, k: int):
"""Creates an instance RBM module.

Args:
D: Size of the input data.
F: Size of the hidden variable.
k: Number of MCMC iterations for negative sampling.

The function initializes the weight (W) and biases (c & b).
"""
super().__init__()
self.W = nn.Parameter(torch.randn(F, D) * 1e-2) # Initialized from Normal(mean=0.0, variance=1e-4)
self.c = nn.Parameter(torch.zeros(D)) # Initialized as 0.0
self.b = nn.Parameter(torch.zeros(F)) # Initilaized as 0.0
self.k = k

def sample(self, p):
"""Sample from a bernoulli distribution defined by a given parameter."""
p = torch.clamp(p, 0, 1)
return torch.bernoulli(p)

Los siguientes métodos para construir la clase RBM son las distribuciones condicionales. Derivamos ambos condicionales anteriormente:

def P_h_x(self, x):
"""Stable conditional probability calculation"""
linear = torch.sigmoid(F.linear(x, self.W, self.b))
return linear

def P_x_h(self, h):
"""Stable visible unit activation"""
return self.c + torch.matmul(h, self.W)

Los métodos finales implican la implementación del pase hacia adelante y la función de energía libre. La función de energía representa una energía efectiva para unidades visibles después de resumir todas las configuraciones de unidades ocultas posibles. La función de avance es la divergencia contrastante clásica para el muestreo Gibbs. Inicializamos x_negative, luego para K iteraciones: obtenemos h_k de p_h_x y x_negative, muestree h_k de un bernoulli, obtenga x_k de p_x_h y h_k, y luego obtenga un nuevo x_negative.

def free_energy(self, x):
"""Numerically stable free energy calculation"""
visible = torch.sum(x * self.c, dim=1)
linear = F.linear(x, self.W, self.b)
hidden = torch.sum(torch.log(1 + torch.exp(linear)), dim=1)
return -visible - hidden

def forward(self, x):
"""Contrastive divergence forward pass"""
x_negative = x.clone()

for _ in range(self.k):
h_k = self.P_h_x(x_negative)
h_k = self.sample(h_k)
x_k = self.P_x_h(h_k)
x_negative = self.sample(x_k)

return x_negative, x_k

Esperemos que esto proporcionara una base sobre la teoría detrás de RBMS, así como una clase de implementación de codificación básica que puede usarse para capacitar a un RBM. Con cualquier código o derviaciones adicionales, ¡no dude en comunicarse con más información!

Derivación para general pag(H | X) Siendo el producto de cada distribución condicional individual:

Fuente: Autor

[1] Montufar, Guido. «Máquinas Boltzmann restringidas: introducción y revisión». ARXIV: 1806.07066V1 (Junio ​​de 2018).

[2] https://en.wikipedia.org/wiki/gibbs_sampling

[3] Hinton, Geoffrey. «Capacitación de productos de expertos minimizando la divergencia contrastante». Cálculo neural (2002).

Por automata