En el Deep Learning usualmente podemos usar las Redes Neuronales, o variantes de estas arquitecturas, como por ejemplo las Redes Convolucionales, o las redes recurrentes (como las LSTM), para tareas de clasificación de datos o para realizar tareas de regresión, es decir, tratar de predecir cantidades numéricas.
Sin embargo, resulta que también podemos interconectar los elementos de cualquiera de estos tipos de redes para lograr que la red aprenda a predecir el mismo dato de entrada.
Pero, ¿para qué queremos crear un modelo que replique el mismo dato de entrada o que genere una predicción que sea casi igual al dato original? Aunque inicialmente puede parecer que no tiene mucho sentido, en la práctica esto tiene muchas aplicaciones fundamentales, como por ejemplo la detección de anomalías, la limpieza de datos o la generación de nuevos datos. Y la manera de lograr esto es construyendo lo que se conoce como un Autoencoder.
Así que en este artículo hablaremos en detalle de los Autoencoders: entenderemos qué son, cómo están conformados internamente y cuáles son los principales usos que podemos darle a este tipo de Red Neuronal para desarrollar diferentes tipos de aplicaciones.
El Principio de Funcionamiento: una analogía biológica
Comencemos entendiendo la idea básica y el principio de funcionamiento esencial de los Autoencoders a través de un ejemplo muy intuitivo haciendo una equivalencia con lo que ocurre en el ámbito biológico:

Como todos sabemos, un ser humano tiene un elemento esencial en cada una de sus células: el ADN. Ese ADN es una molécula que contiene la información esencial del ser humano.
El ADN no es el ser humano en sí, pero si tuviésemos el ADN y el entorno biológico adecuado, podríamos usar esa cadena, esa información esencial, para reconstruir a un ser humano. Aunque esto hasta el momento no ha sido posible en la realidad, sirve perfectamente a manera de ejemplo: lo importante aquí es que el ADN preserva esa información esencial de lo que es el individuo desde el punto de vista biológico.
Si llevamos este concepto al caso de los Autoencoders, encontramos una similitud directa. En los Autoencoders lo que tenemos inicialmente es un dato: una representación numérica de una imagen, de un video, de un texto o cualquier tipo de dato que queramos representar. Ese dato lo llevamos a un formato numérico y, a partir de él, lo que podemos hacer es extraer el «ADN del dato». Es decir, extraemos los elementos esenciales que lo caracterizan, quitando toda la información irrelevante y preservando su esencia.
Luego, si tenemos los elementos computacionales necesarios, podríamos intentar reconstruir ese dato original a partir de su «ADN», volviendo al dato de entrada.
Así que lo que hace un Autoencoder es tomar un dato, extraer de alguna forma su ADN (su información esencial) y luego intentar reconstruir el dato original de la forma más fiel posible a partir de ese ADN.
Y para lograr esto, como veremos en un momento, se usa una configuración específica de Red Neuronal que durante el entrenamiento aprende a representar de forma compacta el dato de entrada y luego utiliza esa representación para reconstruirlo.
Arquitectura y componentes de un Autoencoder
Teniendo claro este principio de funcionamiento básico, veamos en detalle cómo está conformado internamente un Autoencoder.
Este tipo de arquitectura contiene esencialmente dos elementos principales y un estado intermedio fundamental: el codificador, la representación compacta y el decodificador:

Veamos en detalle cada uno de estos elementos.
1. El codificador (encoder)
El codificador es una Red Neuronal (que puede ser una red densa estándar, una red convolucional o una red LSTM, dependiendo de la naturaleza de los datos).
Y su funcionamiento consiste en tomar el dato de entrada y procesarlo a través de sus capas para extraer sus características principales.
2. La representación compacta («el ADN»)
El procesamiento que realiza el codificador genera lo que se conoce como una representación compacta. Este elemento es el punto intermedio entre el codificador y el decodificador y es precisamente el ADN del dato de entrada. Y en realidad, esta representación compacta es simplemente la salida del codificador:

Como vemos en la figura de arriba, en esta sencilla representación el autoencoder toma un dato con 10 valores numéricos a la entrada (en azul, a la izquierda) y genera una representación compacta (en rojo, en la parte central) con únicamente 4 elementos.
Y acá entendemos por qué este elemento se conoce precisamente como «representación compacta»: en el ejemplo anterior hemos pasado de 10 a 4 datos. Y estos 4 elementos conservan la esencia de ese dato original, pero con menos información redundante. Además, dicha representación compacta es la esencia necesaria que permitirá luego su reconstrucción.
3. El Decodificador (decoder)
El decodificador actúa básicamente como un espejo o una versión reflejada de la red neuronal del codificador. Lo que hace el decodificador es, por ejemplo, tomar la representación compacta de 4 elementos que se obtuvo con el codificador e intentar reconstruir los 10 elementos del dato original.
Desde luego, esta reconstrucción no es perfecta, lo cual quiere decir que cuando comparamos el dato original con el dato reconstruido, la idea es que sean lo más parecidos posible, pero inevitablemente va a existir algún grado de error.
¿Cómo se entrena un Autoencoder?
Como hemos visto hasta el momento, la idea del Autoencoder consiste en construir una modelo (usando cualquier variante de Red Neuronal) que aprenda a tomar un dato de entrada, a representarlo de forma compacta preservando su información esencial y a reconstruirlo para que se parezca al máximo al dato original. Pero, ¿cómo logramos que la red aprenda esto?
Aprendizaje no supervisado
Para entrenar el autoencoder vamos a usar un esquema conocido como aprendizaje no supervisado.
A diferencia del aprendizaje supervisado (utilizado cuando construimos un clasificador de imágenes o un modelo para Series de Tiempo, donde debemos mostrarle al modelo tanto el dato de entrada como la categoría objetivo), en el caso de los Autoencoders solo le presentamos el dato de entrada.
Y como el modelo tiene que aprender a predecir ese mismo dato, no es necesario presentarle ninguna etiqueta, categoría o valor numérico adicional objetivo. Solo usamos el dato de entrada, por lo cual este esquema se conoce precisamente como aprendizaje no supervisado.
Proceso de entrenamiento

En la figura de arriba vemos los pasos involucrados en el entrenamiento de un Autoencoder. Estos pasos siguen la misma lógica de entrenamiento de cualquier modelo de Deep Learning:
- Predicción Inicial: tomamos los datos de entrada (vamos a llamarlos $x$) y los llevamos al Autoencoder. Esto genera una predicción (los datos de entrada reconstruidos) que vamos a llamar $\hat{x}$ (x gorro, a la derecha en la imagen de arriba).
- Cálculo del error: inicialmente, como este Autoencoder tiene unos parámetros internos o coeficientes aleatorios (que definen qué tanto peso o importancia se le da a cada elemento de la entrada), las predicciones $\hat{x}$ o datos reconstruidos no se van a parecer mucho a los datos originales $x$. Así que se debe calcular entonces la pérdida, es decir, comparar y cuantificar numéricamente qué tanto se parece la predicción $\hat{x}$ al dato de entrada $x$. Este error inicial será relativamente grande.
- Ajuste de parámetros: esa cantidad numérica de pérdida se usa para ajustar los parámetros del modelo mediante el algoritmo de backpropagation y un optimizador, como por ejemplo el gradiente descendente. Estos parámetros internos se ajustan buscando que la pérdida sea lo más pequeña posible.
- Iteración: se repiten los pasos anteriores una y otra vez por un cierto número de iteraciones. Se le vuelve a presentar al Autoencoder el conjunto de datos $x$, se genera una nueva predicción $\hat{x}$ y, debido al ajuste previo, se espera que $\hat{x}$ se acerque un poco más al dato original. Se calcula nuevamente la pérdida, se ajustan los parámetros y el ciclo continúa hasta que se completen las iteraciones de entrenamiento que hayamos definido.
Con este proceso se logra que las predicciones sean progresivamente lo más parecidas a los datos de entrada.
Principales aplicaciones de los Autoencoders
Muy bien, así que teniendo claro el funcionamiento de un Autoencoder lo que nos interesa ahora es responder a la pregunta planteada al inicio de este artículo: ¿por qué queremos construir un modelo capaz de predecir su misma entrada? Y la respuesta está en las aplicaciones de este tipo de arquitectura.
Así que a continuación veremos las principales aplicaciones que podemos desarrollar con estos Autoencoders (vale la pena aclarar que en los ejemplos que siguen a continuación asumiremos que todas las aplicaciones están en el campo de las imágenes, pero las mismas ideas se pueden extender a otros ámbitos).
1. Detección de anomalías
Supongamos que queremos construir un sistema capaz de determinar si una imagen médica (por ejemplo, una radiografía) contiene o no contiene un tumor. La presencia de un tumor es una situación anómala, ya que la mayoría de las veces las personas sometidas al examen están en perfecto estado de salud.
Solución con Autoencoders:
Para ello entrenamos un Autoencoder únicamente con imágenes normales (sin tumores). De esta manera el Autoencoder aprenderá a reconstruir exclusivamente este tipo de imágenes normales:

Y una vez entrenado viene la fase de predicción.
Si al Autoencoder entrenado le presentamos una imagen normal, como el modelo fue entrenado con estos datos, aprenderá a reconstruirla correctamente. Este principio lo vemos en la siguiente figura:

Y acá está lo clave: al calcular el error (la diferencia entre la reconstrucción $\hat{y}$ y el dato de entrada $x$), encontraríamos que es muy buena y el error será relativamente pequeño.
Pero ¿qué pasa si ahora le presentamos al Autoencoder una imagen anormal (con un tumor)? En este caso, como el modelo no fue entrenado para reconstruir este tipo de patologías, la reconstrucción no será precisa. Así que al calcular el error entre la imagen de entrada anormal y la imagen de salida generada, este error será relativamente grande:

Entonces, para detectar anomalías con Autoencoders podemos usar precisamente el tamaño del error de reconstrucción como un umbral para determinar de forma automática si el dato ingresado es normal o anormal.
Y aunque en el ejemplo anterior vimos este principio aplicado a imágenes médicas, en la práctica este mismo principio de detección de anomalías lo podemos aplicar a cualquier tipo de dato. Por ejemplo, te invito a darle una mirada al tutorial de detección de anomalías en señales cardiacas usando autoencoders, donde explico en detalle este tipo de aplicación.
2. Limpieza de datos (denoising)
Pensemos en un sistema de procesamiento de imágenes donde los datos vienen contaminados por ruido (como artefactos visuales o algún tipo de distorsión) y nuestro objetivo es recuperar su nitidez (es decir, eliminar dicho ruido).
Solución con Autoencoders:
En este caso podemos construir un Autoencoder pero al momento del entrenamiento cambiamos la configuración con respecto a la detección de anomalías.
Así que durante el entrenamiento presentamos a la entrada del modelo imágenes con ruido y a la salida le presentamos sus correspondientes imágenes sin ruido (que es lo que esperamos que aprenda a predecir el modelo):

Entonces, la idea es que el modelo aprenda a obtener una representación compacta que preserve únicamente «lo esencial» de la imagen original. Y lo esencial son precisamente todos los elementos de la imagen que son diferentes del ruido.
Y con esto la idea es que durante la fase de predicción, si al Autoencoder le presentamos una imagen ruidosa, este ya habrá aprendido a extraer su esencia (quitando el ruido) y, al momento de la reconstrucción, logrará generar una imagen totalmente nítida (o al menos con un menor nivel de ruido) a la salida:

3. Generación de nuevos datos
Y la tercera aplicación de los Autoencoders es su capacidad de generar datos sintéticos, es decir, datos similares a aquellos del conjunto de entrenamiento pero que a la vez sean totalmente nuevos y no existan en la realidad.
Solución con Autoencoders:
Para lograr la generación de datos debemos entrenar el modelo presentándole una gran cantidad de datos con las características de interés. Por ejemplo, si queremos que el modelo genere imágenes podríamos presentarle durante el entrenamiento varios miles de imágenes de gatos, para que el modelo aprenda a reconstruir ese tipo de contenido específico:

El truco de esta aplicación ocurre en la etapa de predicción. En este caso, si queremos generar un dato nuevo:
- Eliminamos por completo la parte del codificador.
- Accedemos directamente a la entrada del decodificador, la cual contiene únicamente la representación compacta obtenida con el codificador.
- En lugar de pasar un dato real, le inyectamos ruido aleatorio a esta representación compacta.
- El decodificador tomará este componente de ruido y, basándose en la esencia de lo que aprendió sobre los gatos, generará a su salida imágenes de diferentes tipos de gatos totalmente sintéticos e inéditos.

Conclusión
Como acabamos de ver, un Autoencoder es un tipo de Red Neuronal (ya sea densa, convolucional, LSTM o incluso Transformer) que se entrena mediante aprendizaje no supervisado para que aprenda a predecir el mismo dato que recibe a su entrada.
Y para lograr esto usa dos elementos:
- El codificador, que toma el dato de entrada y aprende a generar una representación compacta del dato de entrada
- Y el decodificador, que actúa como espejo del codificador, tomando esa representación compacta y logrando reconstruir el dato original.
Y esta arquitectura resulta sumamente útil para desarrollar aplicaciones en campos como la detección de anomalías, la limpieza de datos ruidosos y la generación de nuevos datos sintéticos, entre otras.
