Vicente Rodríguez

Nov. 17, 2018

Redes neuronales convolucionales

Las redes neuronales convolucionales han demostrado ser muy buenas cuando se trata de reconocer objetos en una imagen. Tienen una arquitectura diferente que permite aprovechar cada parte de una imagen. En una arquitectura normal tenemos que convertir una imagen de tres dimensiones (alto x ancho x profundidad) a una imagen de una sola dimension, esto trae algunos problemas, necesitamos muchos nodos para representar una imagen pequeña (64 x 64 x 3) = (12,288) lo cual aumenta el tiempo de aprendizaje de una red neuronal. Con las redes neuronales convolucionales no tenemos que realizar esta tarea y podemos usar imagenes de grandes dimensiones como (1024 x 1024 x 3) sin que la red sea lenta.

Esta arquitectura presenta dos capas ocultas nuevas, la capa convolucional y la capa pooling:

Capa Convolucional

Esta es la capa más importante de una red neuronal convolucional y lleva el nombre de la arquitectura de la red, aquí tenemos un elemento llamado kernel que se encarga de encontrar patrones en una imagen, pongamos un ejemplo:

kernel e imagen

A la izquierda tenemos una imagen de tamaño 6 x 6, cada cuadro representa un pixel de la imagen, tenemos seis filas y seis columnas.

A la derecha tenemos el kernel, este tiene un tamaño de 3 x 3.

Para que el kernel pueda encontrar patrones en la imagen este tiene que recorrer la imagen:

primer kernel

cada cuadro del kernel se multiplica por cada cuadro de la imagen y esta multiplicación depende del tamaño del kernel, el kernel de ejemplo tiene un tamaño de 3 x 3 entonces tomamos una parte de la image del mismo tamaño, la multiplicación se realiza en orden de columnas:

La primera columna

3 x 1 + 5 x 1 + 5 x 1 = 13

La segunda columna

4 x 0 + 3 x 0 + 4 x 0 = 0

La tercera columna

6 x 1 + 2 x 1 + 3 x 1 = 11

Despues se suma el resultado de cada columna 13 + 0 + 11 = 24 para obtener el resultado final.

Ahora tenemos que repetir el proceso hasta topar con la ultima columna:

kernel de la primera fila

Podemos notar como movemos el kernel columna por columna hasta que el kernel topa con el final de la imagen.

Las multiplicaciones son iguales siempre que movemos el kernel:

Primera operación


4 x 1 + 3 x 1 + 4 x 1 = 11

6 x 0 + 2 x 0 + 3 x 0 = 0

5 x 1 + 4 x 1 + 3 x 1 = 12



11 + 0 + 12 = 23 

Segunda operación


6 x 1 + 2 x 1 + 3 x 1 = 11

5 x 0 + 4 x 0 + 3 x 0 = 0

1 x 1 + 3 x 1 + 2 x 1 = 6



11 + 0 + 6 = 17 

Tercera operación


5 x 1 + 4 x 1 + 3 x 1 = 12

1 x 0 + 3 x 0 + 2 x 0 = 0

3 x 1 + 2 x 1 + 6 x 1 = 11



12 + 0 + 11 = 23 

Una vez terminemos con las columnas de la primera fila tenemos que pasar a la segunda:

kernel segunda fila

El proceso de mover el kernel se repite hasta topar con la ultima fila y la ultima columna, de esta manera la matriz resultante tendra todos sus valores completos

matriz completa

Podriamos decir que la matriz resultante es la imagen despues de pasar por el proceso de multiplicación y suma, ambos nombres son correctos pero hay que tener cuidado de no confundirse ya que tendremos más capas por donde la matriz resultante o imagen pasara hasta llegar a la capa de salida.

El proceso de mover el kernel por toda la imagen y multiplicar los valores se conoce como operación convolucional.

Si compararamos este tipo de arquitectura con la arquitectura simple que hemos visto en los tutoriales anteriores el kernel sería un sustituto de los pesos W, ambos se encargan de encontrar patrones en los datos.

Para que la capa convolucional este completa a la matriz resultante se le agrega el parametro b y se le aplica la función de activación.

matriz completa

Padding

Un metodo y parametro importante en la capa convolucional es el padding, este metodo se encarga de agregar pixeles al rededor de una imagen:

padding

Hay imagenes donde hay información importante lejos del centro de la imagen, especificamente en las esquinas, por ejemplo si tenemos una foto de personas, algunas personas pueden aparecer en las esquinas de la foto, si realizamos la operación convolucional el kernel pasa muy pocas veces por las esquinas de la imagen comparado con las veces que pasa por el centro de la imagen, por esto agregamos más pixeles alrededor de la imagen para que la información importante este más cerca del centro.

Otro de los usos de este metodo es para evitar que la matriz resultante sea muy pequeña, si recordamos teniamos una imagen 6 x 6 y un kernel 3 x 3 esto da como resultado una matriz 4 x 4, en una red neuronal convolucional tendremos varias capas convolucionales y cada vez que la matriz resultante pasa por estas capas va perdiendo tamaño. La capa pooling que veremos más adelante también se encarga de reducir el tamaño de la matriz resultante por eso es importante mantener un buen tamaño y el metodo padding ayuda a conseguir esto.

Stride

Este parametro indica cuantas posiciones ya sean columnas o filas se moverá el kernel.

En el primer ejemplo vimos como el kernel se movia una sola fila y una sola columna hasta recorrer toda la imagen pero el numero de posiciones puede cambiar.

Empezamos como siempre con la primera sección de la imagen:

primer stride

Cuando pasemos a la segunda sección moveremos el kernel dos columnas en lugar de una:

segundo stride

También se moverá dos filas:

tercer stride

Con esto logramos que la operación convolucional sea más rapida y que la matriz resultante sea más pequeña en este caso de 3 x 3.

Siempre hay que tener cuidado de que la operación convolucional sea exacta, en este ejemplo cambie la imagen de 6 x 6 a una 7 x 7 para que el kernel pudiera pasar por todas las columnas, si usamos una imagen 6 x 6:

stride malo

el kernel tendría problemas al llegar al final de la imagen.

Para evitar estos problemas existe una formula que indica cual sera el tamaño de la matriz resultante:


(N + 2p - k / s)  + 1 x (N + 2p - k / s)  + 1

donde N es el tamaño de la imagen, k el tamaño del kernel, p el numero de pixeles que se le agrego a la imagen (padding) y s el numero de posiciones que se moverá el kernel (stride)

si usamos una imagen 7 x 7 con un padding de 0, un kernel 3 x 3 y un stride de 2:


(7 + 0 - 3 / 2)  + 1 x (7 + 0 - 3 / 2)  + 1


= (4 / 2) + 1 x (4 / 2) + 1

= 3 x 3

si ahora usamos una imagenn 6 x 6 con los mismos parametros:


(6 + 0 - 3 / 2)  + 1 x (6 + 0 - 3 / 2)  + 1


= (3 / 2) + 1 x (3 / 2) + 1

= 2.5 x 2.5

este resultado no es entero, siempre tenemos que buscar que esta formula regrese un numero entero para saber que la operación convolucional se realizara correctamente.

Imagenes a color

Una imagen a color tiene tres canales: rgb(rojo, verde, azul).

imagen a color

Esto quiere decir que tendremos tres matrices representando a la imagen a color, una matriz por cada canal de color y el tamaño de la imagen sera de 6 x 6 x 3, también tendremos tres kernels de tamaño 3 x 3 x 3, uno para cada canal de color.

Cada kernel multiplicara al canal de color que le corresponda, el kernel rojo con la matriz roja, el kernel verde con la matriz verde y el kernel azul con la matriz azul.

El resultado de la operación convolucional es una matriz 4 x 4:

operacion convolucional a color

igual que las imagenes con un solo canal de color cada kernel multiplica una sección del canal que le corresponda y para obtener el resultado se suman los valores de los tres kernels y se escribe en la matriz resultante.

En una red neuronal convolucional tendremos varios kernels para que cada uno se encargue de encontrar distintos patrones en la imagen, como ya vimos cuando tenemos imagenes a color necesitamos tres kernels para cada canal de color, si hablamos de una capa convolucional con 10 kernels en realidad estamos hablando de 30 kernels ya que cada uno se divide en tres para cubrir cada canal de color.

Capa Pooling

Esta capa funciona similar al kernel de la capa convolucional, en este caso pasamos un kernel vacio por la imagen pero en lugar de multiplicar tomamos el valor más grande de la sección de la imagen. En el siguiente ejemplo tenemos un kernel 2 x 2 y un stride de 2:

pooling

el kernel pasa cuatro veces por la imagen, cada una esta representada por un color. En este ejemplo usamos el metodo Max Pooling que como su nombre indica toma el valor más grande del pixel de la sección, existe otro metodo llamado Average Pooling, en este metodo calculamos el promedio de los pixeles de la sección.

Este metodo sirve para reducir el tamaño de la matriz resultante, en el ejemplo pasamos de una matriz 4 x 4 a una matriz 2 x 2, con esto tenemos una imagen final más pequeña que es más facil de entrenar.

Esta capa suele ir despues de la capa convolucional.

Red neuronal convolucional

Veamos un ejemplo de la red neuronal completa

red neuronal

Cuando hablemos del numero de capas que tiene una red neuronal convolucional podemos tomar la capa convolucional y la capa pooling como una sola, en el ejemplo la red neuronal tiene 4 capas.

La primera y segunda capa son convolucionales, como podemos notar conforme la imagen pasa por estas capas pierde tamaño pero gana profundidad gracias al kernel, la primera capa tiene 6 kernels y la segunda tiene 16 kernels, estos parametros, al tener una funcionalidad similar a los pesos W, también cambian con el backpropagation, el backpropagation es más complejo en este tipo de redes neuronales pero keras se encarga de esta parte.

Las ultimas dos capas son iguales a las que se usan en una red neuronal comun, necesitamos este tipo de capas porque son las que se encargan de clasificar las imagenes. Una vez la imagen paso por las capas convolucionales y estas encontraron patrones en la imagen necesitamos convertir la ultima capa convolucional de profundidad tres (18 x 18 x 16) a una capa de una sola profundidad (5,184), recordemos que en el primer tutorial de redes neuronales convertimos las imagenes de tamaño (64 x 64 x 3) a un vector muy grande de tamaño (12,288) ya que una capa normal solo reconoce dos dimensiones (alto y ancho). Despues de convertir la imagen a una sola dimension podemos agregar más capas normales y conectarlas, en el ejemplo agregamos una capa más de tamaño (120, 5,184), esta tiene 120 neuronas, por ultimo tenemos la capa de salida con 10 neuronas, una para cada clase y esta capa usa la función de activación softmax para realizar la clasificación muliple.

Código

Usaremos el framework keras para construir una red neuronal convolucional, primero importamos las funciones necesarias:


import keras

from keras.models import Sequential, Model

from keras.layers import Dense, Flatten, Activation

from keras.layers import Conv2D, MaxPooling2D

Ahora crearemos la red neuronal capa por capa


  model = Sequential()



  #Primera capa

  model.add(Conv2D(64, 

        kernel_size=(3, 3), padding="valid",

        activation='relu', strides=1, input_shape=(256, 256, 3))

  model.add(MaxPooling2D())



  #Segunda capa

  model.add(Conv2D(64, 

        kernel_size=(3, 3), padding="valid",

        activation='relu', strides=1))

  model.add(MaxPooling2D())



  #Tercera capa / Convertir los datos

  model.add(Flatten())



  #Cuarta capa

  model.add(Dense(500))

  model.add(Activation('relu'))



  #Clasificación 

  model.add(Dense(3))

  model.add(Activation('softmax'))

Crear una red neuronal con keras es muy sencillo sin importar que arquitectura estemos usando. En el siguiente tutorial usaremos esta arquitectura para clasificar los coches tesla, también aplicaremos los metodos batch normalization, dropout y aplicaremos nuevas tecnicas como data augmentation.