Un tutorial de aprendizaje profundo: de perceptrones a redes profundas

Publicado: 2022-03-11

En los últimos años, ha habido un resurgimiento en el campo de la Inteligencia Artificial. Se extiende más allá del mundo académico con jugadores importantes como Google, Microsoft y Facebook que crean sus propios equipos de investigación y realizan algunas adquisiciones impresionantes.

Parte de esto se puede atribuir a la abundancia de datos sin procesar generados por los usuarios de las redes sociales, muchos de los cuales deben analizarse, el surgimiento de soluciones avanzadas de ciencia de datos, así como a la potencia computacional barata disponible a través de GPGPU.

Pero más allá de estos fenómenos, este resurgimiento ha sido impulsado en gran parte por una nueva tendencia en IA, específicamente en el aprendizaje automático, conocido como "Aprendizaje profundo". En este tutorial, le presentaré los conceptos y algoritmos clave detrás del aprendizaje profundo, comenzando con la unidad más simple de composición y construcción hasta los conceptos de aprendizaje automático en Java.

(Para divulgación completa: también soy el autor de una biblioteca de aprendizaje profundo de Java, disponible aquí, y los ejemplos en este artículo se implementan utilizando la biblioteca anterior. Si le gusta, puede apoyarlo dándole una estrella en GitHub , por lo que estaría agradecido. Las instrucciones de uso están disponibles en la página de inicio.)

Un tutorial de treinta segundos sobre aprendizaje automático

En caso de que no esté familiarizado, consulte esta introducción al aprendizaje automático:

El procedimiento general es el siguiente:

  1. Tenemos un algoritmo que proporciona 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"). Tenga en cuenta que principalmente nos quedamos a la clasificación binaria supervisada para esta publicación.
  2. El algoritmo “aprende” a identificar imágenes de perros y, cuando se alimenta con una nueva imagen, espera producir la etiqueta correcta (1 si es una imagen de un perro y 0 en caso contrario).

Esta configuración es increíblemente general: sus datos pueden ser síntomas y sus etiquetas enfermedades; o sus datos podrían ser imágenes de caracteres escritos a mano y sus etiquetas los caracteres reales que representan.

Perceptrones: algoritmos tempranos de aprendizaje profundo

Uno de los primeros algoritmos de entrenamiento supervisado es el del perceptrón, un componente básico de la red neuronal.

Digamos que tenemos n puntos en el plano, etiquetados como '0' y '1'. Se nos da un nuevo punto y queremos adivinar su etiqueta (esto es similar al escenario anterior de "Perro" y "No perro"). ¿Cómo lo hacemos?

Un enfoque podría ser mirar al vecino más cercano y devolver la etiqueta de ese punto. Pero una forma un poco más inteligente de hacerlo sería elegir una línea que separe mejor los datos etiquetados y usarla como clasificador.

Una representación de los datos de entrada en relación con un clasificador lineal es un enfoque básico para el aprendizaje profundo.

En este caso, cada dato de entrada se representaría como un vector x = ( x_1, x_2 ) y nuestra función sería algo así como "'0' si está debajo de la línea, '1' si está arriba".

Para representar esto matemáticamente, definamos nuestro separador mediante un vector de pesos w y un desplazamiento vertical (o sesgo) b . Entonces, nuestra función combinaría las entradas y los pesos con una función de transferencia de suma ponderada:

función de transferencia de suma ponderada

El resultado de esta función de transferencia se introduciría luego en una función de activación para producir un etiquetado. En el ejemplo anterior, nuestra función de activación era un límite de umbral (por ejemplo, 1 si es mayor que algún valor):

resultado de esta función de transferencia

Entrenando al perceptrón

El entrenamiento del perceptrón consiste en alimentarlo con múltiples muestras de entrenamiento y calcular la salida para cada una de ellas. Después de cada muestra, los pesos w se ajustan de tal manera que se minimice el error de salida , definido como la diferencia entre la salida deseada (objetivo) y la real . Hay otras funciones de error, como el error cuadrático medio, pero el principio básico del entrenamiento sigue siendo el mismo.

Inconvenientes de un solo perceptrón

El enfoque de perceptrón único para el aprendizaje profundo tiene un gran inconveniente: solo puede aprender funciones linealmente separables. ¿Qué tan importante es este inconveniente? Tome XOR, una función relativamente simple, y observe que no se puede clasificar mediante un separador lineal (observe el intento fallido, a continuación):

El inconveniente de este enfoque de aprendizaje profundo es que algunas funciones no se pueden clasificar mediante un separador lineal.

Para abordar este problema, necesitaremos usar un perceptrón multicapa, también conocido como red neuronal de avance: en efecto, compondremos un grupo de estos perceptrones para crear un mecanismo más poderoso para el aprendizaje.

Redes neuronales feedforward para el aprendizaje profundo

Una red neuronal es realmente solo una composición de perceptrones, conectados de diferentes maneras y que operan en diferentes funciones de activación.

El aprendizaje profundo de red neutral feedforward es un enfoque más complejo que los perceptrones únicos.

Para empezar, veremos la red neuronal feedforward, que tiene las siguientes propiedades:

  • Una entrada, una salida y una o más capas ocultas . La figura anterior muestra una red con una capa de entrada de 3 unidades, una capa oculta de 4 unidades y una capa de salida con 2 unidades (los términos unidades y neuronas son intercambiables).
  • Cada unidad es un único perceptrón 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 del perceptrón).
  • Cada unidad de la capa t generalmente está conectada a cada unidad de la capa anterior t - 1 (aunque podría desconectarlas configurando su peso en 0).
  • Para procesar los datos de entrada, "sujeta" el vector de entrada a la capa de entrada, configurando los valores del vector como "salidas" para cada una de las unidades de entrada. En este caso particular, la red puede procesar un vector de entrada tridimensional (debido a las 3 unidades de entrada). Por ejemplo, si su vector de entrada es [7, 1, 2], entonces establecería la salida de la unidad de entrada superior en 7, la unidad central en 1, y así sucesivamente. Estos valores luego se propagan hacia las unidades ocultas utilizando la función de transferencia de suma ponderada para cada unidad oculta (de ahí el término propagación hacia adelante), que a su vez calculan sus salidas (función de activación).
  • La capa de salida calcula sus salidas de la misma manera 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 a cada uno de nuestros perceptrones solo se le permite usar una función de activación lineal? Entonces, la salida final de nuestra red seguirá siendo una función lineal de las entradas, simplemente ajustada con una tonelada de diferentes pesos que se recopilan en toda la red. En otras palabras, una composición lineal de un montón de funciones lineales sigue siendo solo una función lineal. Si estamos restringidos a las funciones de activación lineal, 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 solo una función lineal, por lo que la mayoría de las redes neuronales usan funciones de activación no lineales.

Debido a esto, la mayoría de las redes neuronales utilizan funciones de activación no lineales como logística, tanh, binaria o rectificadora. Sin ellos, la red solo puede aprender funciones que son combinaciones lineales de sus entradas.

Perceptrones de entrenamiento

El algoritmo de aprendizaje profundo más común para el entrenamiento supervisado de los perceptrones multicapa se conoce como retropropagación. El procedimiento básico:

  1. Se presenta una muestra de entrenamiento y se propaga a través de la red.
  2. El error de salida se calcula, normalmente el error cuadrático medio:

    error medio cuadrado

    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. El error de red se minimiza usando un método llamado descenso de gradiente estocástico.

    Descenso de gradiente

    El descenso de gradiente es universal, pero en el caso de las redes neuronales, este sería un gráfico del error de entrenamiento en función de los parámetros de entrada. El valor óptimo para cada ponderación es aquel en el 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 lote de varias muestras) de tal manera que siempre están tratando de alcanzar el mínimo global, pero esto no es tarea fácil, ya que a menudo terminan en mínimos locales, como el de la derecha. Por ejemplo, si el peso tiene un valor de 0,6, debe cambiarse a 0,4.

    Esta figura representa el caso más simple, aquel en el que el error depende de un solo parámetro. Sin embargo, el error de red depende del peso de cada red y la función de error es mucho, mucho más compleja.

    Afortunadamente, la retropropagación proporciona un método para actualizar cada peso entre dos neuronas con respecto al error de salida. La derivación en sí es bastante complicada, pero la actualización del peso para un nodo dado tiene la siguiente forma (simple):

    formulario de ejemplo

    Donde E es el error de salida y w_i es el peso de la entrada i a la neurona.

    Esencialmente, el objetivo es moverse en la dirección del gradiente con respecto al peso i . El término clave es, por supuesto, la derivada del error, que no siempre es fácil de calcular: ¿cómo encontraría esta derivada para un peso aleatorio de un nodo oculto aleatorio en medio de una red grande?

    La respuesta: a través de la retropropagación. Los errores se calculan primero en las unidades de salida donde la fórmula es bastante simple (basada en la diferencia entre el objetivo y los valores predichos), y luego se propagan a través de la red de 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 red de una sola capa oculta con un número finito de neuronas se puede entrenar para aproximar una función arbitrariamente aleatoria. En otras palabras, una sola capa oculta es lo suficientemente poderosa 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 almacena su representación abstracta interna de los datos de entrenamiento.

La capa oculta es donde la red almacena su 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. Avanzando en el tutorial, veremos diferentes formas de jugar con la capa oculta.

Una red de ejemplo

Puede ver una red neuronal feedforward simple (4-2-3 capas) 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 del sépalo, la longitud de los pétalos, etc. La red cuenta con 50 muestras por clase. Las funciones están sujetas a las unidades de entrada, mientras que cada unidad de salida corresponde a una sola 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, clasifica incorrectamente 2 muestras de 150).

El problema de 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 sobre las capas anteriores. Y como mencionamos antes, a menudo puede aprender mejor en la práctica con redes más grandes.

Sin embargo, aumentar la cantidad de capas ocultas genera dos problemas conocidos:

  1. Gradientes que se desvanecen: a medida que agregamos más y más capas ocultas, la retropropagación se vuelve cada vez menos útil para pasar información a las capas inferiores. En efecto, a medida que se transmite la información, los gradientes comienzan a desvanecerse y se vuelven pequeños en relación con los pesos de las redes.
  2. Sobreajuste: quizás el problema central en el aprendizaje automático. Brevemente, el sobreajuste describe el fenómeno de ajustar demasiado los datos de entrenamiento, quizás con hipótesis que son demasiado complejas. En tal caso, su alumno termina ajustando muy bien los datos de entrenamiento, pero se desempeñará mucho, mucho peor en ejemplos reales.

Veamos algunos algoritmos de aprendizaje profundo para abordar estos problemas.

Codificadores automáticos

La mayoría de las clases introductorias de aprendizaje automático tienden a detenerse en las redes neuronales de avance. Pero el espacio de posibles redes es mucho más rico, así que continuemos.

Un codificador automático suele ser una red neuronal de avance que tiene como objetivo aprender una representación distribuida comprimida (codificación) de un conjunto de datos.

Un autocodificador es una red neuronal de aprendizaje profundo que tiene como objetivo aprender una determinada representación de un conjunto de datos.

Conceptualmente, la red está entrenada para "recrear" la entrada, es decir, la entrada y los datos de destino son los mismos. En otras palabras: está tratando de generar lo mismo que ingresó, pero comprimido de alguna manera. Este es un enfoque confuso, así que veamos un ejemplo.

Comprimir la entrada: imágenes en escala de grises

Digamos que los datos de entrenamiento consisten en imágenes en escala de grises de 28x28 y el valor de cada píxel está sujeto a una neurona de la capa de entrada (es decir, la capa de entrada tendrá 784 neuronas). Entonces, la capa de salida tendría el mismo número de unidades (784) que la capa de entrada y el valor objetivo para cada unidad de salida sería el valor de escala de grises de un píxel de la imagen.

La intuición detrás de esta arquitectura es que la red no aprenderá un "mapeo" entre los datos de entrenamiento y sus etiquetas, sino que aprenderá la estructura interna y las características de los datos mismos. (Debido a esto, la capa oculta también se denomina detector de características ). Por lo general, la cantidad de unidades ocultas es menor que las capas de entrada/salida, lo que obliga a la red a aprender solo las características más importantes y logra una reducción de la dimensionalidad.

Queremos algunos nodos pequeños en el medio para aprender los datos a nivel conceptual, produciendo una representación compacta.

En efecto, queremos algunos nodos pequeños en el medio para realmente aprender los datos a nivel conceptual, produciendo una representación compacta que de alguna manera capture las características principales de nuestra entrada.

enfermedad gripal

Para demostrar aún más los codificadores automáticos, veamos una aplicación más.

En este caso, usaremos un conjunto de datos simple que consta de síntomas de gripe (crédito a esta publicación de blog por la idea). Si está interesado, el código de este ejemplo se puede encontrar en el método testAEBackpropagation .

Así es como se desglosa el conjunto de datos:

  • Hay seis características de entrada binaria.
  • Los tres primeros son 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 tos y temperatura alta, etc.
  • Las últimas tres características son síntomas “contra”; cuando un paciente tiene uno de estos, es menos probable que esté enfermo. 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 0 indica un paciente vacunado con tos, y así sucesivamente.

Consideraremos que un paciente está enfermo cuando tiene al menos dos de las tres primeras características y sano si tiene al menos dos de las tres segundas (desempate a favor de los pacientes sanos), por ejemplo:

  • 111000, 101000, 110000, 011000, 011100 = enfermo
  • 000111, 001110, 000101, 000011, 000110 = saludable

Entrenaremos un codificador automático (usando retropropagación) con seis unidades de entrada y seis de salida, pero solo dos unidades ocultas .

Después de varios cientos de iteraciones, observamos que cuando cada una de las muestras "enfermas" se presenta a la red de aprendizaje automático, una de las dos unidades ocultas (la misma unidad para cada muestra "enferma") siempre exhibe un valor de activación más alto que el otro. Por el contrario, cuando se presenta una muestra “sana”, la otra unidad oculta tiene una mayor activación.

Volviendo al aprendizaje automático

Básicamente, 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 se relaciona esto con el aprendizaje, volvamos al problema del sobreajuste. Al entrenar nuestra red para que aprenda una representación compacta de los datos, estamos favoreciendo una representación más simple en lugar de una hipótesis muy compleja que sobreajuste los datos de entrenamiento.

En cierto modo, al favorecer estas representaciones más simples, intentamos aprender los datos en un sentido más real.

Máquinas Boltzmann restringidas

El siguiente paso lógico es observar una máquina de Boltzmann restringida (RBM), una red neuronal estocástica generativa que puede aprender una distribución de probabilidad sobre su conjunto de entradas .

En el aprendizaje automático, las máquinas de Botlzmann restringidas se componen de unidades visibles y ocultas.

Los RBM se componen de una capa oculta, visible y sesgada. A diferencia de las redes feedforward, las conexiones entre las capas visible y oculta no están dirigidas (los valores se pueden propagar tanto en la dirección de visible a oculta como de oculta a visible) y están totalmente conectadas (cada unidad de una capa dada está conectada a cada unidad en la siguiente: si permitiéramos que cualquier unidad en cualquier capa se conectara a cualquier otra capa, entonces tendríamos una máquina Boltzmann (en lugar de una máquina Boltzmann restringida ).

El RBM estándar tiene unidades binarias ocultas y visibles: es decir, la activación de la unidad es 0 o 1 bajo una distribución de Bernoulli, pero existen variantes con otras no linealidades.

Si bien los investigadores conocen los RBM desde hace algún tiempo, la reciente introducción del algoritmo de entrenamiento no supervisado de divergencia contrastiva ha renovado el interés.

divergencia contrastiva

El algoritmo de divergencia contrastiva de un solo paso (CD-1) funciona así:

  1. Fase positiva :
    • Una muestra de entrada v se sujeta a la capa de entrada.
    • v se propaga a la capa oculta de manera similar a las redes feedforward. El resultado de las activaciones de la capa oculta es h .
  2. Fase negativa :
    • Propaga h de vuelta a la capa visible con el resultado v' (las conexiones entre las capas visible y oculta no están dirigidas y, por lo tanto, permiten el movimiento en ambas direcciones).
    • Propaga la nueva v' de regreso a la capa oculta con el resultado de activaciones h' .
  3. Actualización de peso :

    actualización de peso

    Donde a es la tasa de aprendizaje y v , v' , h , h' y w son vectores.

La intuición detrás del algoritmo es que la fase positiva ( h dado v ) refleja la representación interna de la red de los datos del mundo real . Mientras tanto, la fase negativa representa un intento de recrear los datos basados ​​en esta representación interna ( v' dada h ). El objetivo principal es que los datos generados estén lo más cerca posible del mundo real y esto se refleja en la fórmula de actualización de peso.

En otras palabras, la red tiene cierta percepción de cómo se pueden representar los datos de entrada, por lo que intenta reproducir los datos en función de esta percepción. Si su reproducción no se acerca lo suficiente a la realidad, hace un ajuste y vuelve a intentarlo.

Volviendo a la gripe

Para demostrar la divergencia contrastiva, usaremos el mismo conjunto de datos de síntomas que antes. La red de prueba es un RBM con seis unidades visibles y dos ocultas. Entrenaremos la red utilizando la divergencia contrastiva con los síntomas v anclados a la capa visible. Durante la prueba, los síntomas se presentan nuevamente a la capa visible; luego, los datos se propagan a la capa oculta. Las unidades ocultas representan el estado enfermo/saludable, una arquitectura muy similar al codificador automático (propagando datos de la capa visible a la oculta).

Después de varios cientos de iteraciones, podemos observar el mismo resultado que con los codificadores automáticos: una de las unidades ocultas tiene un valor de activación más alto cuando se presenta alguna de las muestras "enfermas", mientras que la otra siempre está más activa para las muestras "saludables".

Puede ver este ejemplo en acción en el método testContrastiveDivergence .

Redes profundas

Ahora hemos demostrado que las capas ocultas de codificadores automáticos y RBM actúan como detectores de características efectivos; pero es raro que podamos usar estas funciones directamente. De hecho, el conjunto de datos anterior es más una excepción que una regla. En cambio, necesitamos encontrar alguna forma de usar estas características detectadas indirectamente.

Afortunadamente, se descubrió que estas estructuras se pueden apilar para formar redes profundas . Estas redes se pueden entrenar con avidez, una capa a la vez, para ayudar a superar el gradiente de fuga y los problemas de sobreajuste asociados con la retropropagación clásica.

Las estructuras resultantes suelen ser bastante poderosas y producen resultados impresionantes. Tomemos, por ejemplo, el famoso artículo sobre "gatos" de Google en el que utilizan un tipo especial de codificadores automáticos profundos para "aprender" la detección de rostros humanos y de gatos en función de datos no etiquetados .

Miremos más de cerca.

Codificadores automáticos apilados

Como sugiere el nombre, esta red consta de múltiples codificadores automáticos apilados.

Los codificadores automáticos apilados tienen una serie de entradas, salidas y capas ocultas que contribuyen a los resultados del aprendizaje automático.

La capa oculta del codificador automático t actúa como una capa de entrada para el codificador automático t + 1 . La capa de entrada del primer codificador automático es la capa de entrada para toda la red. El procedimiento de entrenamiento codicioso por capas funciona así:

  1. Entrene el primer codificador automático ( t=1 , o las conexiones rojas en la figura anterior, pero con una capa de salida adicional) individualmente usando el método de retropropagación con todos los datos de entrenamiento disponibles.
  2. Entrenar el segundo autoencoder t=2 (conexiones verdes). Dado que la capa de entrada para t=2 es la capa oculta de t=1 , ya no estamos interesados ​​en la capa de salida de t=1 y la eliminamos de la red. El entrenamiento comienza sujetando una muestra de entrada a la capa de entrada de t=1 , que se propaga hacia la capa de salida de t=2 . A continuación, los pesos (entrada oculta y salida oculta) de t=2 se actualizan mediante retropropagación. t=2 usa todas las muestras de entrenamiento, similar a t=1 .
  3. Repita el procedimiento anterior para todas las capas (es decir, elimine la capa de salida del codificador automático anterior, reemplácela con otro codificador automático y entrene con propagación hacia atrás).
  4. Los pasos 1 a 3 se denominan preentrenamiento y dejan los pesos correctamente inicializados. Sin embargo, no hay asignación entre los datos de entrada y las etiquetas de salida. Por ejemplo, si la red está entrenada para reconocer imágenes de dígitos escritos a mano, aún no es posible asignar las unidades desde el último detector de características (es decir, la capa oculta del último codificador automático) al tipo de dígito de la imagen. En ese caso, la solución más común es agregar una o más capas completamente conectadas a la última capa (conexiones azules). Toda la red ahora se puede ver como un perceptrón multicapa y se entrena mediante retropropagación (este paso también se denomina ajuste fino ).

Los codificadores automáticos apilados, por lo tanto, tienen que ver con proporcionar un método de preentrenamiento efectivo para inicializar los pesos de una red, dejándolo con un perceptrón complejo de múltiples capas que está listo para entrenar (o ajustar ).

Redes de creencias profundas

Al igual que con los codificadores automáticos, también podemos apilar máquinas Boltzmann para crear una clase conocida como redes de creencias profundas (DBN) .

Las redes de creencias profundas se componen de una pila de máquinas de Boltzmann.

En este caso, la capa oculta de RBM t actúa como una capa visible para RBM t+1 . La capa de entrada del primer RBM es la capa de entrada para toda la red, y el preentrenamiento por capas codicioso funciona así:

  1. Entrene el primer RBM t=1 usando divergencia contrastiva con todas las muestras de entrenamiento.
  2. Entrene el segundo RBM t=2 . Dado que la capa visible para t=2 es la capa oculta de t=1 , el entrenamiento comienza sujetando la muestra de entrada a la capa visible de t=1 , que se propaga hacia la capa oculta de t=1 . Estos datos luego sirven para iniciar el entrenamiento de divergencia contrastiva para t=2 .
  3. Repita el procedimiento anterior para todas las capas.
  4. De manera similar a los codificadores automáticos apilados, después del entrenamiento previo, la red se puede ampliar conectando una o más capas completamente conectadas a la capa oculta final de RBM. Esto forma un perceptrón de múltiples capas que luego se puede ajustar usando retropropagación.

Este procedimiento es similar al de los codificadores automáticos apilados, pero con los codificadores automáticos reemplazados por RBM y la retropropagación reemplazada por el algoritmo de divergencia contrastiva.

(Nota: para obtener más información sobre cómo construir y entrenar codificadores automáticos apilados o redes de creencias profundas, consulte el código de muestra aquí).

Redes convolucionales

Como arquitectura final de aprendizaje profundo, echemos un vistazo a las redes convolucionales, una clase especial y particularmente interesante de redes de avance que se adaptan muy bien al reconocimiento de imágenes.

Las redes convolucionales son una clase especial de redes feedforward de aprendizaje profundo.
Imagen vía DeepLearning.net

Antes de ver la estructura real de las redes convolucionales, primero definimos un filtro de imagen o una región cuadrada con pesos asociados. Un filtro se aplica a toda una imagen de entrada y, a menudo, aplicará varios filtros. Por ejemplo, podría aplicar cuatro filtros de 6x6 a una imagen de entrada dada. Luego, el píxel de salida con coordenadas 1,1 es la suma ponderada de un cuadrado de 6x6 de píxeles de entrada con la esquina superior izquierda 1,1 y los pesos del filtro (que también es un cuadrado de 6x6). El píxel de salida 2,1 es el resultado del cuadrado de entrada con la esquina superior izquierda 2,1 y así sucesivamente.

Con eso cubierto, estas redes se definen por las siguientes propiedades:

  • Las capas convolucionales aplican una serie de filtros a la entrada. Por ejemplo, la primera capa convolucional de la imagen podría tener cuatro filtros de 6x6. El resultado de un filtro aplicado a la imagen se llama mapa de características (FM) y el número de mapas de características es igual al número de filtros. Si la capa anterior también es convolucional, los filtros se aplican en todos sus FM con diferentes pesos, por lo que cada FM de entrada está conectado a cada FM de salida. La intuición detrás de los pesos compartidos en la imagen es que las características se detectarán independientemente de su ubicación, mientras que la multiplicidad de filtros permite que cada uno de ellos detecte un conjunto diferente de características.
  • Las capas de submuestreo reducen el tamaño de la entrada. Por ejemplo, si la entrada consta de una imagen de 32x32 y la capa tiene una región de submuestreo de 2x2, el valor de salida sería una imagen de 16x16, lo que significa que 4 píxeles (cada cuadrado de 2x2) de la imagen de entrada se combinan en una sola salida píxel Hay varias formas de submuestrear, pero las más populares son la agrupación máxima, la agrupación promedio y la agrupación estocástica.
  • La última capa de submuestreo (o convolucional) generalmente está conectada a una o más capas completamente conectadas, la última de las cuales representa los datos de destino.
  • El entrenamiento se realiza mediante una retropropagación modificada que tiene en cuenta las capas de submuestreo y actualiza los pesos del filtro convolucional en función de todos los valores a los que se aplica ese filtro.

Puede ver varios ejemplos de redes convolucionales entrenadas (con retropropagación) en el conjunto de datos MNIST (imágenes en escala de grises de letras escritas a mano) aquí, específicamente en los métodos testLeNet* (recomendaría testLeNetTiny2 ya que logra una tasa de error baja de alrededor del 2 % en un período de tiempo relativamente corto). También hay una buena visualización de JavaScript de una red similar aquí.

Implementación

Ahora que hemos cubierto las variantes de redes neuronales más comunes, pensé en escribir un poco sobre los desafíos que se presentan durante la implementación de estas estructuras de aprendizaje profundo.

En términos generales, mi objetivo al crear una biblioteca de aprendizaje profundo era (y sigue siendo) construir un marco basado en redes neuronales que cumpliera con los siguientes criterios:

  • Una arquitectura común que sea capaz de representar diversos modelos (todas las variantes sobre redes neuronales que hemos visto anteriormente, por ejemplo).
  • La capacidad de utilizar diversos algoritmos de entrenamiento (propagación hacia atrás, divergencia contrastiva, etc.).
  • Rendimiento decente.

Para satisfacer estos requisitos, adopté un enfoque escalonado (o modular) para el diseño del software.

Estructura

Empecemos con lo básico:

  • NeuralNetworkImpl es la clase base para todos los modelos de redes neuronales.
  • Cada red contiene un conjunto de capas.
  • Cada capa tiene una lista de conexiones, donde una conexión es un vínculo entre dos capas, de modo que la red es un gráfico acíclico dirigido.

Esta estructura es lo suficientemente ágil como para usarse en redes feedforward clásicas, así como en RBM y arquitecturas más complejas como ImageNet.

También permite que una capa sea parte de más de una red. Por ejemplo, las capas en una red de creencias profundas también son capas en sus RBM correspondientes.

Además, esta arquitectura permite ver una DBN como una lista de RBM apilados durante la fase de preentrenamiento y una red de avance durante la fase de ajuste fino, lo cual es tanto intuitivamente agradable como programáticamente conveniente.

Propagación de datos

El siguiente módulo se encarga de propagar datos a través de la red, un proceso de dos pasos:

  1. Determinar el orden de las capas. Por ejemplo, para obtener los resultados de un perceptrón multicapa, los datos se "sujetan" a la capa de entrada (por lo tanto, esta es la primera capa que se calcula) y se propagan hasta la capa de salida. Para actualizar los pesos durante la retropropagación, el error de salida debe propagarse a través de cada capa en orden de amplitud, comenzando desde la capa de salida. Esto se logra usando varias implementaciones de LayerOrderStrategy , que aprovecha la estructura gráfica de la red, empleando diferentes métodos de recorrido de gráficos. Algunos ejemplos incluyen la estrategia de ancho primero y la orientación de una capa específica. El orden en realidad está determinado por las conexiones entre las capas, por lo que las estrategias devuelven una lista ordenada de conexiones.
  2. Calcular el valor de activación. Cada capa tiene un ConnectionCalculator asociado que toma su lista de conexiones (del paso anterior) y los valores de entrada (de otras capas) y calcula la activación resultante. Por ejemplo, en una red feedforward sigmoidal simple, el ConnectionCalculator de la capa oculta toma los valores de las capas de entrada y polarización (que son, respectivamente, los datos de entrada y una matriz de 1s ) y los pesos entre las unidades (en caso de que esté completamente conectado). capas, los pesos en realidad se almacenan en una conexión Totalmente Conectada como Matrix ), calcula la suma ponderada e introduce el resultado en la función sigmoide. Las calculadoras de conexión implementan una variedad de funciones de transferencia (p. ej., suma ponderada, convolucional) y activación (p. ej., logística y tanh para perceptrón multicapa, binaria para RBM). La mayoría de ellos se pueden ejecutar en una GPU usando Aparapi y se pueden usar con entrenamiento de mini lotes.

Computación GPU con Aparapi

Como mencioné anteriormente, una de las razones por las que las redes neuronales han resurgido en los últimos años es que sus métodos de entrenamiento conducen en gran medida al paralelismo, lo que le permite acelerar significativamente el entrenamiento con el uso de una GPGPU. En este caso, opté por trabajar con la biblioteca Aparapi para agregar compatibilidad con GPU.

Aparapi impone algunas restricciones importantes en las calculadoras de conexión:

  • Solo se permiten matrices unidimensionales (y variables) de tipos de datos primitivos.
  • Solo se permite llamar a los métodos miembro de la propia clase Aparapi Kernel desde el código ejecutable de la GPU.

Como tal, la mayoría de los datos (pesos, matrices de entrada y salida) se almacenan en instancias de Matrix , que utilizan internamente matrices flotantes unidimensionales. Todas las calculadoras de conexión de Aparapi utilizan AparapiWeightedSum (para capas totalmente conectadas y funciones de entrada de suma ponderada), AparapiSubsampling2D (para capas de submuestreo) o AparapiConv2D (para capas convolucionales). Algunas de estas limitaciones se pueden superar con la introducción de la arquitectura de sistemas heterogéneos. Aparapi también permite ejecutar el mismo código tanto en la CPU como en la GPU.

Capacitación

The training module implements various training algorithms. It relies on the previous two modules. For example, BackPropagationTrainer (all the trainers are using the Trainer base class) uses feedforward layer calculator for the feedforward phase and a special breadth-first layer calculator for propagating the error and updating the weights.

My latest work is on Java 8 support and some other improvements, will soon be merged into master.

Conclusión

The aim of this Java deep learning tutorial was to give you a brief introduction to the field of deep learning algorithms, beginning with the most basic unit of composition (the perceptron) and progressing through various effective and popular architectures, like that of the restricted Boltzmann machine.

The ideas behind neural networks have been around for a long time; but today, you can't step foot in the machine learning community without hearing about deep networks or some other take on deep learning. Hype shouldn't be mistaken for justification, but with the advances of GPGPU computing and the impressive progress made by researchers like Geoffrey Hinton, Yoshua Bengio, Yann LeCun and Andrew Ng, the field certainly shows a lot of promise. There's no better time to get familiar and get involved like the present.

Appendix: Resources

If you're interested in learning more, I found the following resources quite helpful during my work:

  • DeepLearning.net: a portal for all things deep learning. It has some nice tutorials, software library and a great reading list.
  • An active Google+ community.
  • Two very good courses: Machine Learning and Neural Networks for Machine Learning, both offered on Coursera.
  • The Stanford neural networks tutorial.
Related: Schooling Flappy Bird: A Reinforcement Learning Tutorial