Autoencoder escaso: de la superposición a las características interpretables | por shuyang xiang | Febrero de 2025

Deshacer características en una red neuronal compleja con superposiciones

Redes neuronales complejascomo los modelos de idiomas grandes (LLM), sufren bastante a menudo de interpretabilidad desafíos. Una de las razones más importantes para tal dificultad es superposición – Un fenómeno de la red neuronal que tiene menos dimensiones que la cantidad de características que tiene que representar. Por ejemplo, un juguete LLM con 2 neuronas tiene que presentar 6 características de lenguaje diferentes. Como resultado, observamos a menudo que una sola neurona necesita activarse para múltiples características. Para obtener una explicación y definición más detallada de superposición, consulte mi anterior blog: “Superposición: lo que dificulta explicar la red neuronal”.

En esta publicación de blog, damos un paso más allá: intentemos desenredar algunas características de FSuperpuestas. Presentaré una metodología llamada Autoencoder Para descomponer la red neuronal compleja, especialmente LLM en características interpretables, con un ejemplo de las características del lenguaje.

A Autoencoderpor definición, es un autoencoder con dispersión introducida a propósito en las activaciones de sus capas ocultas. Con una estructura bastante simple y un proceso de entrenamiento de luz, su objetivo es descomponer una red neuronal compleja y descubrir las características de una manera más interpretable y más comprensible para los humanos.

Imaginemos que tiene una red neuronal capacitada. El autoencoder no es parte del proceso de entrenamiento del modelo en sí, sino que es una herramienta de análisis post-hoc. El modelo original tiene sus propias activaciones, y estas activaciones se recopilan después y luego se utilizan como datos de entrada para el autoencoder escaso.

Por ejemplo, suponemos que su modelo original es una red neuronal con una capa oculta de 5 neuronas. Además, tiene un conjunto de datos de entrenamiento de 5000 muestras. Debe recopilar todos los valores de la activación 5 dimensional de la capa oculta para todas sus 5000 muestras de entrenamiento, y ahora son la entrada para su autoencoder escasa.

Imagen del autor: Autoencoder para analizar un LLM

El autoencoder luego aprende una nueva representación escasa de estas activaciones. El codificador asigna las activaciones originales de MLP en un nuevo espacio vectorial con dimensiones de representación más altas. Mirando hacia atrás en mi ejemplo simple de 5 neuronas anteriores, podríamos considerarlo para asignarlo a un espacio vectorial con 20 características. Con suerte, obtendremos un autoencoder escaso descomponiendo efectivamente las activaciones originales de MLP en una representación, más fácil de interpretar y analizar.

Sparsity es importante en el autoencoder porque es necesario que el autoencoder “desenrede” las características, con más “libertad” que en un espacio denso y superpuesto. Sin existencia de escasez, el autoencoder probablemente el autoencoder podría aprender un trivial compresión sin ninguna característica significativa de la formación.

Modelo

Vamos a construir ahora nuestro modelo de juguete. Le ruego a los lectores que tengan en cuenta que este modelo no es realista e incluso un poco tonto en la práctica, pero es suficiente para mostrar cómo construimos un autoencoder disperso y capturamos algunas características.

Supongamos que ahora hemos creado un modelo de lenguaje que tiene una capa oculta particular cuya activación tiene tres dimensiones. Supongamos también que tenemos las siguientes fichas: “gato”, “gato feliz”, “perro”, “perro enérgico”, “no gato”, “no perro”, “robot” y “asistente de AI” en el conjunto de datos de entrenamiento y tienen los siguientes valores de activación.

data = torch.tensor([
# Cat categories
[0.8, 0.3, 0.1, 0.05], # "cat"
[0.82, 0.32, 0.12, 0.06], # "happy cat" (similar to "cat")
# Dog categories
[0.7, 0.2, 0.05, 0.2], # "dog"
[0.75, 0.3, 0.1, 0.25], # "loyal dog" (similar to "dog")

# "Not animal" categories
[0.05, 0.9, 0.4, 0.4], # "not cat"
[0.15, 0.85, 0.35, 0.5], # "not dog"

# Robot and AI assistant (more distinct in 4D space)
[0.0, 0.7, 0.9, 0.8], # "robot"
[0.1, 0.6, 0.85, 0.75] # "AI assistant"
], dtype=torch.float32)

Construcción de autoencoder

Ahora construimos el Autoencoder con el siguiente código:

class SparseAutoencoder(nn.Module):
def __init__(self, input_dim, hidden_dim):
super(SparseAutoencoder, self).__init__()
self.encoder = nn.Sequential(
nn.Linear(input_dim, hidden_dim),
nn.ReLU()
)
self.decoder = nn.Sequential(
nn.Linear(hidden_dim, input_dim)
)

def forward(self, x):
encoded = self.encoder(x)
decoded = self.decoder(encoded)
return encoded, decoded

Según el código anterior, vemos que el codificador tiene una sola capa lineal totalmente conectada, asignando la entrada a una representación oculta con hidden_dim y luego pasa a una activación de Relu. El decodificador usa solo una capa lineal para reconstruir la entrada. Tenga en cuenta que la ausencia de activación de RELU en el decodificador es intencional para nuestro caso de reconstrucción específico, porque la reconstrucción podría contener datos valorados de valor real y potencialmente negativos. Un RELU obligaría a la salida a permanecer no negativo, lo que no es deseable para nuestra reconstrucción.

Entrenamos el modelo usando el código a continuación. Aquí, la función de pérdida tiene dos partes: la pérdida de reconstrucción, que mide la precisión de la reconstrucción del autoencoder de los datos de entrada y una pérdida de dispersión (con peso), lo que fomenta la formulación de escasez en el codificador.

# Training loop
for epoch in range(num_epochs):
optimizer.zero_grad()

# Forward pass
encoded, decoded = model(data)

# Reconstruction loss
reconstruction_loss = criterion(decoded, data)

# Sparsity penalty (L1 regularization on the encoded features)
sparsity_loss = torch.mean(torch.abs(encoded))

# Total loss
loss = reconstruction_loss + sparsity_weight * sparsity_loss

# Backward pass and optimization
loss.backward()
optimizer.step()

Ahora podemos echar un vistazo al resultado. Hemos trazado el valor de salida del codificador de cada activación de los modelos originales. Recuerde que los tokens de entrada son “gatos”, “gato feliz”, “perro”, “perro enérgico”, “no gato”, “no perro”, “robot” y “asistente de IA”.

Imagen del autor: Características aprendidas por el codificador

A pesar de que el modelo original fue diseñado con una arquitectura muy simple sin ninguna consideración profunda, el autoencoder todavía ha capturado características significativas de este modelo trivial. Según la trama anterior, podemos observar al menos cuatro características que parecen ser aprendidas por el codificador.

Dé una consideración a la primera característica 1. Este feautre tiene grandes valores de activación en las 4 fichas siguientes: “gato”, “gato feliz”, “perro” y “perro enérgico”. El resultado sugiere que la característica 1 puede ser algo relacionado con “animales” o “mascotas”. La característica 2 también es un ejemplo interesante, que se activa en dos tokens “Robot” y “Asistente de AI”. Suponemos, por lo tanto, esta característica tiene algo que ver con “artificial y robótica”, lo que indica la comprensión del modelo sobre los contextos tecnológicos. La característica 3 tiene activación en 4 tokens: “no gato”, “no perro”, “robot” y “asistente de IA” y esto es posiblemente una característica “no un animal”.

Desafortunadamente, el modelo original no es un modelo real entrenado en el texto del mundo real, sino que está diseñado artificialmente con la suposición de que tokens similares tienen cierta similitud en el espacio de la activación del vector. Sin embargo, los resultados aún proporcionan ideas interesantes: la escasa autoencoder logró mostrar algunas características significativas y amigables para los humanos o conceptos del mundo real.

El simple resultado en esta publicación de blog sugiere:, un autoencoder escaso puede ayudar efectivamente a obtener características de alto nivel e interpretables de redes neuronales complejas como LLM.

Para los lectores interesados ​​en una implementación del mundo real de autoencoders dispersos, recomiendo esto artículodonde un autoencoder fue entrenado para interpretar un modelo de lenguaje grande real con 512 neuronas. Este estudio proporciona una aplicación real de autoencoders dispersos en el contexto de la interpretabilidad de LLM.

Finalmente, proporciono aquí este Google Colab computadora portátil Para mi implementación detallada mencionada en este artículo.