Un Tutorial de Aprendizaje Profundo: De Perceptrones a Redes Profundas


BY IVAN VASILEV - JAVA DEVELOPER @ TOPTAL (TRANSLATED BY MARISELA ORDAZ)
En los últimos años, ha habido un resurgimiento en el campo de la Inteligencia Artificial. Se ha extendido más allá del mundo académico, con grandes figuras como Google, Microsoft y Facebook, quienes han creado sus propios equipos de investigación, obteniendo impresionantes adquisiciones.
Se comenta que esto puede atribuirse a la gran cantidad de datos brutos generados por los usuarios de redes sociales, muchos de los cuales deben ser analizados, al igual que al poder computacional precario disponible a través de GPGPUs.
Pero más allá de estos fenómenos, este resurgimiento se ha impulsado en gran parte por una nueva tendencia en la IA, concretamente en el aprendizaje de máquina, conocida como “aprendizaje profundo”. En este tutorial, te voy a presentar los conceptos claves y algoritmos detrás del aprendizaje profundo, empezando por la unidad más simple de la composición hasta llegar a los conceptos de aprendizaje automático en Java.
(Para una descripción completa: Soy también el autor de una biblioteca de aprendizaje profundo de Java, disponible aquí, y los ejemplos de este artículo se implementan utilizando la biblioteca de arriba Si te gusta, puedes apoyarla dándole una estrella en GitHub, por lo cual estaría muy agradecido. Las instrucciones de uso están disponibles en la página de inicio.)

Un Tutorial de Treinta Segundos sobre Aprendizaje de Máquinas

En caso de que no estés familiarizado, echa un vistazo a esta introducción al aprendizaje de máquinas:
El procedimiento general es el siguiente:
  1. Tenemos un algoritmo al que se le da un puñado de ejemplos etiquetados; por ejemplo, 10 imágenes de perros con la etiqueta 1 (“perro”) y 10 imágenes de otras cosas con la etiqueta 0 (“No perro”) - Ten en cuenta que estamos usando principalmente para este post, clasificación supervisada y binaria.
  2. El algoritmo “aprende” a identificar imágenes de perros y cuando se le alimenta con una nueva imagen, espera producir la etiqueta correcta (1 si se trata de una imagen de un perro, y 0 en caso contrario).
Esta configuración es muy general: los datos podrían ser síntomas y enfermedades de las etiquetas, o tus datos podrían ser imágenes de personajes escritos a mano y las etiquetas los personajes que representan.

Perceptrones: Aprendizaje Profundo de Algoritmos

Uno de los primeros algoritmos de entrenamiento supervisado es el perceptrón; un bloque de construcción básico de redes neuronales.
Supongamos que tenemos puntos n en el plano, con la etiqueta ‘0’ y ‘1’. Nos dan un nuevo punto y queremos adivinar su etiqueta (esto es similar al escenario “perro” y “No perro” de arriba). ¿Cómo lo hacemos?
Un buen acercamiento podría ser mirar al vecino más cercano y devolver la etiqueta desde ese punto. Pero una manera un poco más inteligente de hacer las cosas, sería elegir una línea que separe mejor los datos etiquetados y usar eso como clasificador.
En este caso, cada pieza de datos de entrada se representa como un vector x = ( x_1, x_2 ) y nuestra función sería algo así como “ ‘0’ si está por debajo de la línea, ‘1’ si está por encima”.
Para representar esto matemáticamente, deja que nuestro separador sea definido por un vector de pesos w y un desplazamiento vertical sesgo b. Entonces, nuestra función combinaría las entradas y los pesos con una función de transferencia de suma ponderada:
El resultado de esta función de transferencia sería entonces alimentada a una función de activación para producir un etiquetado. En el ejemplo anterior, nuestra función de activación era un umbral de corte (por ejemplo, 1 si es mayor que un cierto valor):
result of this transfer function

Entrenando el Perceptrón

El entrenamiento del perceptrón consiste en alimentarlo con múltiples muestras de entrenamiento y el cálculo de la salida para cada uno de ellos. Después de cada muestra, los pesos w se ajustan de tal manera a fin de minimizar el error de salida, definido como la diferencia entre la salida deseada (objetivo) y la real. Hay otras funciones de error, como el error cuadrado medio, pero el principio básico de entrenamiento sigue siendo el mismo.

Inconvenientes del Perceptrón Simple

El enfoque del perceptrón simple para el aprendizaje profundo, tiene un gran inconveniente: sólo puede aprender funciones linealmente separables. ¿Qué tan importante es este inconveniente? Toma XOR, una función relativamente simple, y notarás que no puede ser clasificada por un separador lineal (nota el intento fallido, a continuación):
The drawback to this deep learning approach is that some functions cannot be classified by a linear separator.
Para hacer frente a este problema, tendremos que utilizar un perceptrón multicapa, también conocido como red neuronal feedforward: en efecto, vamos a componer una gran cantidad de estos perceptrones para crear un mecanismo más potente para el aprendizaje.

Redes Neuronales Feedforward para el Aprendizaje Profundo

Una red neuronal es en realidad una composición de perceptrones conectados de diferentes maneras, y que operan con diferentes funciones de activación.
Feedforward neutral network deep learning is a more complex approach than single perceptrons.
Para empezar, vamos a ver la red neuronal feedforward, que tiene las siguientes propiedades:
  • Una entrada, salida, y una o más capas ocultas. La figura anterior muestra una red con una capa de entrada de 3 unidades, 4-unidades de capa oculta y una capa de salida con 2 unidades (los términos unidades y neuronas son intercambiables).
  • Cada unidad es un perceptrón simple, como el descrito anteriormente.
  • Las unidades de la capa de entrada sirven como entradas para las unidades de la capa oculta, mientras que las unidades de la capa oculta son entradas para la capa de salida.
  • Cada conexión entre dos neuronas tiene un peso w (similar a los pesos perceptron).
  • Cada unidad de la capa t suele estar conectada a cada unidad de la capa t anterior - 1 (aunque se podrían desconectar mediante el establecimiento de su peso a 0).
  • Para procesar los datos de entrada, sujetas el vector de entrada a la capa de entrada, estableciendo los valores del vector como “salidas” para cada una de las unidades de entrada. En este caso en particular, la red puede procesar un vector de entrada tridimensional (debido a las 3 unidades de entrada). Por ejemplo, si tu vector de entrada es [7, 1, 2], entonces ajustarías la salida de la unidad de entrada superior, a 7, la unidad del medio a 1, y así sucesivamente. Estos valores se propagan hacia adelante hasta las unidades ocultas, utilizando la función de transferencia suma ponderada para cada unidad oculta (de ahí el término propagación hacia adelante), que a su vez calcula sus salidas (función de activación).
  • La capa de salida calcula sus salidas de la misma forma que la capa oculta. El resultado de la capa de salida es la salida de la red.

Más Allá de la Linealidad

¿Qué pasa si sólo se permite a cada uno de nuestros perceptrones utilizar una función de activación lineal? Entonces, la salida final de nuestra red será aún una función lineal de las entradas, simplemente ajustada con una tonelada de diferentes pesos que se recogió a través de la red. En otras palabras, una composición lineal de un grupo de funciones lineales todavía es sólo una función lineal. Si nos limitamos a las funciones de activación lineales, entonces la red neuronal feedforward no es más poderosa que el perceptrón, sin importar cuántas capas tenga.
Una composición lineal de un montón de funciones lineales sigue siendo sólo una función lineal, por lo que la mayor parte de las redes neuronales utilizan funciones de activación no lineales.
Debido a esto, la mayoría de las redes neuronales usan funciones de activación no lineales como logistictanhbinary or rectifier. Sin ellos, la red sólo puede aprender las funciones que son combinaciones lineales de sus entradas.

Entrenando Perceptrones

El algoritmo de aprendizaje profundo más común para entrenamiento supervisado de los perceptrones multicapa se conoce como propagación reversa. El procedimiento básico:
  1. Una muestra de entrenamiento se presenta y se propaga hacia adelante a través de la red.
  2. Se calcula el error de salida, por lo general el error cuadrático medio:
    mean squared error
    Donde t es el valor objetivo e y es la salida real de la red. Otros cálculos de error también son aceptables, pero el MSE es una buena opción.
  3. Los errores de red se reducen usando un método llamado descenso de gradiente estocástico.Gradient descent
    El descenso gradiente es universal, pero en el caso de redes neuronales, esto sería un gráfico del error de entrenamiento como una función de los parámetros de entrada. El valor óptimo para cada peso es aquel en que el error alcanza un mínimo global. Durante la fase de entrenamiento, los pesos se actualizan en pequeños pasos (después de cada muestra de entrenamiento o un mini-grupo de varias muestras) de manera que siempre están tratando de alcanzar el mínimo global, pero esto no es una tarea fácil, ya que a menudo terminan en mínimos locales, como el que se ve en la derecha. Por ejemplo, si el peso tiene un valor de 0,6, se debe cambiar a 0,4.
    Esta cifra representa el caso más simple, aquella en la que el error depende de un solo parámetro. Sin embargo, el error de red depende de cada peso de red y la función de error es mucho, mucho más compleja.
    Afortunadamente, la propagación hacia atrás proporciona un método para la actualización de cada peso entre dos neuronas, con respecto al error de salida. La derivación en sí es bastante complicada, pero la actualización de peso para un determinado nodo tiene la siguiente forma (simple):
    example form
Donde E es el error de salida, y w_i es el peso de la entrada i a la neurona.
En esencia, el objetivo es moverse en la dirección de la gradiente con respecto al peso i. El término clave es, por supuesto, la derivada del error, lo cual no siempre es fácil de calcular: ¿cómo encontrar este derivado para un peso al azar de un nodo oculto al azar en medio de una gran red?
La respuesta: a través de propagación hacia atrás. Los errores se calculan en primer lugar en las unidades de salida, donde la fórmula es bastante simple (basado en la diferencia entre el objetivo y los valores predeterminados), y luego se propagan a través de la red de una manera inteligente, permitiéndonos actualizar de manera eficiente nuestros pesos durante el entrenamiento y (con suerte) llegar a un mínimo.

Capa Oculta

La capa oculta es de particular interés. Por el teorema de aproximación universal, una única red de capa oculta con un número finito de neuronas puede ser entrenada para la aproximación de una función arbitraria al azar. En otras palabras, una sola capa oculta es lo suficientemente potente como para aprender cualquier función. Dicho esto, a menudo aprendemos mejor en la práctica con múltiples capas ocultas (es decir, redes más profundas).
La capa oculta es donde la red guarda la representación abstracta interna de los datos de entrenamiento.
La capa oculta es donde la red guarda la representación abstracta interna de los datos de entrenamiento, similar a la forma en que un cerebro humano (analogía muy simplificada) tiene una representación interna del mundo real. En adelante en el tutorial, vamos a ver diferentes formas de jugar un poco con la capa oculta.

Un Ejemplo de Red

Se puede ver una red simple (4-2-3 capa) de feedforward neural que clasifica el conjunto de datos IRIS, implementado en Java aquí, a través del método testMLPSigmoidBP. El conjunto de datos contiene tres clases de plantas de iris con características como la longitud sépalo, longitud pétalo, etc. Se proporciona a la red 50 muestras por clase. Las características se sujetan a las unidades de entrada, mientras que cada unidad de salida corresponde a una única clase del conjunto de datos: “1/0/0” indica que la planta es de clase Setosa, “0/1/0” indica versicolor, y “0/0/1” indica Virginica. El error de clasificación es 2/150 (es decir, no clasifica correctamente 2 muestras de 150).

El Problema con las Grandes Redes

Una red neuronal puede tener más de una capa oculta: en ese caso, las capas superiores están “construyendo” nuevas abstracciones en la parte superior de las capas anteriores. Y como hemos mencionado antes, a menudo se puede aprender mejor en la práctica con las redes más grandes.
Sin embargo, el aumento del número de capas ocultas conduce a dos problemas conocidos:
  1. Desaparición del Gradiente: a medida que añadimos más y más capas ocultas, la propagación hacia atrás se vuelve cada vez menos útil en la transmisión de información a las capas inferiores. En efecto, como la información se pasa de nuevo, los gradientes comienzan a desaparecer y se hacen más pequeños en relación con los pesos de las redes.
  2. Sobreajuste: tal vez éste sea el problema central en el aprendizaje automático. En pocas palabras, el sobreajuste describe el fenómeno de ajuste de los datos de entrenamiento demasiado cerca, tal vez con la hipótesis de que son muy complejos. En tal caso, el alumno termina el montaje de los datos de entrenamiento muy bien pero se desarrollará muy mal en ejemplos reales.
Veamos algunos algoritmos de aprendizaje profundo para abordar estas cuestiones.

Autoencoders

La mayoría de las clases introductorias de aprendizaje automático tienden a terminar con las redes neuronales feedforward. Pero el espacio de posibles redes es mucho más rico, así que continuemos.
Un autoencoder es típicamente una red neuronal feedforward, que tiene como objetivo aprender una representación (codificación) comprimida y distribuida de un conjunto de datos.
An autoencoder is a neural deep learning network that aims to learn a certain representation of a dataset.
Conceptualmente, la red está capacitada para “recrear” la entrada, es decir, la entrada y los datos de objetivo son los mismos. En otras palabras: estás tratando de usar lo mismo como salida y entrada, pero comprimido de alguna manera. Este es un enfoque confuso, así que vamos a ver un ejemplo.

Compresión de la Entrada: Las Imágenes en Escala de Grises

Digamos que los datos de entrenamiento constan de imágenes en escala de grises de 28x28 y el valor de cada pixel se fija a una neurona de capa de entrada (es decir, la capa de entrada tendrá 784 neuronas). Luego, la capa de salida tendría el mismo número de unidades (784) como la capa de entrada y el valor objetivo para cada unidad de salida, sería el valor de escala de grises de un pixel de la imagen.
La intuición detrás de esta arquitectura es que la red no va a aprender un “mapeo” entre los datos de entrenamiento y sus etiquetas, pero si aprenderá la estructura interna y las características de los propios datos. (Debido a esto, la capa oculta también se denomina detector de característica.) Por lo general, el número de unidades ocultas es más pequeño que las capas de entrada / salida, lo que obliga a la red a aprender solamente las características más importantes y logra una reducción de dimensionalidad.
Queremos unos pequeños nodos en el medio para aprender los datos a nivel conceptual, produciendo una representación compacta.
En efecto, queremos unos pequeños nodos en el medio para aprender realmente los datos a nivel conceptual, produciendo una representación compacta que de alguna manera capte las características fundamentales de nuestra entrada.

La Enfermedad de la Gripe

Para demostrar aún más autoencoders, vamos a ver una aplicación más. En este caso, vamos a utilizar un conjunto de datos simple, que consiste en síntomas de la gripe (crédito a esta entrada en el blog de la idea). Si estás interesado, el código para este ejemplo se puede encontrar en el método testAEBackpropagation.
He aquí cómo el conjunto de datos se desglosa:
  • Hay seis entidades de entrada binarias.
  • Los tres primeros son los síntomas de la enfermedad. Por ejemplo, 1 0 0 0 0 0 indica que este paciente tiene temperatura alta, mientras que 0 1 0 0 0 0 indica tos, 1 1 0 0 0 0 indica la tos y alta temperatura, etc.
  • Las tres últimas características son síntomas “de venta libre”; cuando un paciente tiene uno de estos, es menos probable que él o ella esté enfermo/a. Por ejemplo, 0 0 0 1 0 0 indica que este paciente tiene una vacuna contra la gripe. Es posible tener combinaciones de los dos conjuntos de características: 0 1 0 1 0 0indica un paciente vacunado con tos, y así sucesivamente.
Vamos a considerar que un paciente está enfermo. Cuando él o ella tiene al menos dos de las tres primeras características, y saludable si él o ella tiene al menos dos de las tres últimas (con desempates que se rompen a favor de los pacientes sanos), por ejemplo:
  • 111000, 101000, 110000, 011000, 011100 = enferma
  • 000111, 001110, 000101, 000011, 000110 = sano
Vamos a entrenar a un autoencoder (mediante propagación hacia atrás) con seis unidades de entrada y seis de salida, pero sólo dos unidades ocultas.
Después de varios cientos de iteraciones, se observa que cuando cada una de las muestras de “enfermos” se presentan a la red de aprendizaje de máquina, una de las dos unidades ocultas (la misma unidad para cada muestra “enfermo”) siempre exhibe un valor de activación más alto que la otra. Por el contrario, cuando se presenta una muestra “sano”, la otra unidad oculta tiene una mayor activación.

De Vuelta al Aprendizaje de Máquina

En esencia, nuestras dos unidades ocultas han aprendido una representación compacta del conjunto de datos de los síntomas de la gripe. Para ver cómo esto se relaciona con el aprendizaje, volvemos al problema de sobreajuste. Mediante el entrenamiento de nuestra red para aprender una representación compacta de los datos, estamos dando preferencia a una representación más simple en lugar de una hipótesis altamente compleja que sobre-ajusta los datos de entrenamiento.
En cierto modo, al favorecer estas representaciones más simples, estamos tratando de aprender los datos en un sentido más verdadero.

Visita la Parte 2 del artículo

Artículo vía Toptal

Déjame tus dudas y comentarios: Conversion Conversion Emoticon Emoticon

Entradas Populares