Aprende Deep Learning junto a Keras en 10 minutos y crea tu primera Convolutional Neural Network
¿Tienes 10 minutos? Siento robártelos pero estoy seguro de que valdrán la pena. En este articulo pretendo que entiendas de forma básica como funciona una red neuronal, veas las capas más representativas y programarás tu primera red neuronal convolucional usando Keras y Python. ¿Suena fantástico no?
Introducción
En los últimos tiempos hemos visto un decrecimiento significativo de las técnicas habituales en Machine Learning y un crecimiento exponencial del Deep Learning.
Este crecimiento no es casual, las redes neuronales han dado resultados mucho más satisfactorios en términos de rendimiento respecto al Machine Learning convencional.
Está masiva aceptación en diversos campos se debe a que la redes neuronales tienen propiedades muy interesantes desde el punto de vista practico:
- Los problemas a tratar cada vez se han vuelto más complejos. Aunque cada vez hay más accesibilidad a datos.
- Existe prácticamente una arquitectura para tratar cualquier medio de información.
- Hace escasos años eran impensables debido al gran coste computacional que suponían. Debido los grandes avances en GPUs (gracias gamers) esa frase ha quedado para la historia.
- Son diseños modulares que permiten desde una optimizaron rigurosa de ese modulo hasta montar tus propias arquitecturas como si de un puzzle se tratase.
- Permiten unos resultados que hasta el momento parecían imposible.
- En el campo de la visión por computador y de procesado lenguaje natural (NLP) han supuesto un salto de calidad abismal.
Podríamos decir que las redes neuronales han cambiado gran parte del paradigma del aprendizaje computacional. Por ejemplo antes, debíamos escoger cuidadosamente que atributos serian interesantes analizar.
Ahora ya no es estrictamente necesario sino que podemos delegar esa tarea a la propia red neuronal.
Menos bla bla bla… ¡Y explicame que es una red neuronal!
Cuando hablamos de una red neuronal, debemos tener la idea que únicamente es una función matemática.
Esta función matemática se encarga de coger una entrada X y transformarlos en una salida Y. Normalmente conocemos X como input y Y como prediction/output.
La función f además es extremadamente compleja con millones de pesos y enorme.
Pero que sea compleja con millones de pesos y enorme no es condición suficiente, tal y como hemos comentado anteriormente es interesante que esta sea pueda ser modular.
Divide y vencerás
Que esa f compleja y enorme sea modular nos hace pensar que quizás esta este compuesta por pequeñas funciones con tareas especificas. Estás funciones se conocen como capas.
El funcionamiento de las capas es muy simple:
- Cogen la información de la anterior entrada o capa.
- Transforman la información.
- Se pasa a la siguiente capa.
- Y así sucesivamente hasta llegar a la supuesta predicción.
Este procedimiento matemáticamente se conoce como composición de funciones y se puede definir de la siguiente forma:
Y no es más que una función dentro de otra, dentro de otra, dentro de otra… Si viesemos en detalle la figura anterior tendríamos:
Principal diferencia entre capas
Dado que este articulo es introductorio diremos que existen dos conjuntos diferenciados de capas con tareas muy especificas:
- Buscar patrones.
- Transformar los datos, llamadas capas de activación.
Buscar patrones
Las capas que buscan patrones son realmente las encargadas de aprender que patrón hay relevante en la entrada de esa capa. Estos patrones que aprenden se conocen como pesos.
Para comparar la entrada con los pesos se usa lo que se conoce como producto de señales.
Esta métrica dará el valor más elevado cuando ambas señales se parezcan más:
Cada neurona se encarga de calcular un único producto de señales entre la entrada y sus pesos.
Transforman los datos
Por otro lado están las capas que transforman los datos llamadas capas de activación estás llevan los datos a nuevos espacios, los condensan y los anulan. Pero sobretodo tienen una propiedad muy importante: son funciones no-lineales.
Una red neuronal debe ser una Universal Function Approximators, que viene a decir que “tiene que permitir aproximar cualquier función”.
Para aproximar cualquier función se requiere de un gran numero de grados de libertad y por consiguiente que nuestra red sea una función no-lineal bastante compleja. Esa no-linearidad no la pueden ofrecer únicamente las capas que buscan patrones porque todas son lineales. Por ese motivo se requiere intercalar capas lineales con no-lineales.
Además las capas de activación son muy útiles para transformar los datos al rango que deseemos. Unos ejemplos:
- tanh: [-1, 1]
- sigmoid: [0, 1]
- softmax: [0, 1] (únicamente en multiclase como capa final).
- ReLU: [0, inf]
Normalmente se usa el ingenio para combinar ambos tipos de capas para ir reduciendo o aumentando las dimensiones para ajustar las dimensiones de la predicción (numero de neuronas en la ultima capa).
En el siguiente caso las neuronas se van reduciendo hasta una, y esta será la que indique la predicción del input.
Perceptrón (Neurona Artificial)
De los dos anteriores conceptos nace el perceptrón que combina ambos para crear una neurona artificial.
Para una red neuronal real se lleva ese concepto al extremo. No buscan únicamente un patrón sino que se crea un banco de neuronas donde cada una buscará un patrón distinto. Esto se conoce como fully-connected. El nombre de fully-connected es muy apropiado porque realmente cada neurona de la siguiente capa esta conectada con todas las neuronas de la capa anterior.
Como el percepción siempre realiza esta combinación (capa + activación) algunos frameworks incluyen la activación en la propia capa como en keras con la capa dense.
A la vez este banco de neuronas se conecta a otro y así sucesivamente creando lo que se conoce como Multilayer Perceptron. Que es una red que dirige la información hacia un único sentido transformándola continuamente hasta obtener la salida deseada.
Este concepto de ir creando banco tras banco de neuronas hace que cada nivel sea un grado de abstracción distinto.
Donde las primeras capas encontrarán patrones más básicos y a medida que aumenta la profundidad encontrarán patrones más complejos.
¿Como aprenden?
Las redes neuronales al igual que todos los algoritmos de Machine Learning. Aquí nos centraremos en las supervisadas, existen otro tipo de redes para problemas no-supervisados, semi-supervisados y hasta aprendizaje por refuerzo pero en este articulo no las tendremos en cuenta.
Eso quiere decir que disponemos de una dataset (base de datos) con muestras donde conocemos tanto la entrada como su respectivo resultado (conocido como target).
El proceso de aprendizaje comienza inicializando los pesos de la red neuronal a un valor aleatorio. Podríamos decir que por ahora la red neuronal no entiende el problema. Pero basándonos en las muestras y en el tiempo será capaz de ir convergiendo hacia una solución.
En este punto entra en juego un elemento fundamental conocido como loss function (función de perdida). Esta función únicamente se encuentra en el proceso de aprendizaje y se encarga de cuantificar cuanto sé esta equivocando la predicción de la red neuronal respecto al target (lo que debería realmente dar).
Es importante determinar qué función de perdida poner porque esta 100% relacionado con el problema que estemos tratando de resolver.
El proceso de cuantificar el error desencadena lo que se conoce como backpropagation. Este el algoritmo estrella que se encarga de ir hacia atrás e ir corrigiendo los pesos de cada capa mediante la regla de la cadena.
Es proceso es bastante laborioso y se sale fuera de lo que queremos explicar en este articulo. Así que únicamente hay que tener presente del proceso de backpropagation que existe otro elemento importante llamado optimizador. Este se encarga de evaluar cuanto y como corregir el peso a lo largo del aprendizaje. Es decir, define el ritmo de aprendizaje.
¿Que es una Convolutional Neural Network?
Dentro de las redes neuronales existen muchas arquitecturas distintas especializadas en distintos ámbitos. En este caso hablaremos las Convolutional Neural Networks (CNN).
Recuerdas que antes te comenté que básicamente hay dos grandes conjuntos de tipos de capas, pues no iba mal encaminado… Las Convolutional Neural Network son perfectas para analizar imágenes, estás definen unas nuevas capas que permiten solventar los problemas de una red neuronal convencional y aprovecharse de las propiedades de las imágenes.
¿Cual es el problema habitual de las redes neuronales?
El problema que principalmente sufre cualquier arquitectura de Deep Learning es la gran cantidad de pesos. Recuerdas que comentamos que las redes neuronales comparaban el patrón aprendido con respecto su entrada.
Cuando esa entrada es por ejemplo una imagen o un cubo (alto x ancho x canales), cada neurona debería aprender tantos pesos como pixeles o elementos tiene la imagen o cubo. Lo que supone una bestialidad… Y totalmente intratable.
¿Que tienen de ventajoso las imágenes?
En contra a tener tantísimas dimensiones, tienen algo a su favor. Y es que un elemento puede encontrarse en una localización distinta de la imagen (invariancia a traslación). Además las imágenes comúnmente replican bastante sus patrones más básicos: cambios de contorno, esquinas, etc.
Convolución
Las Convolutional Neural Network usan la capa de convolución (concretamente 2d en el caso de imágenes) que básicamente buscará el mismo patrón pero en distintas posiciones de la imagen, moviendo una ventana a lo largo de la imagen.
Y además para reducir aún más el numero de pesos se puede usar el stride. Básicamente permite saltarse algunos pixeles.
Si lo comparamos respecto al banco de neuronas que teníamos al inicio, estas neuronas no están conectadas con todas las anteriores sino que únicamente aquellas que están cerca.
Pooling
La capa de pooling es una capa dedicada exclusivamente a reducir la dimensionalidad. En este caso también mueve una ventana a lo largo de la imagen, aunque esta vez cogerá únicamente el valor máximo (en el caso del max-pooling) o el valor medio de toda esa ventana (en el caso del avg-pooling).
Creando nuestra primera CNN
Hasta ahora hemos visto la teoría que sustenta los principios básicos de las redes neuronales. En esta sección programaremos nuestra primera red haciendo uso del framework para redes neuronales Keras.
En este caso haremos un clasificador de perros y gatos usando imágenes.
Instalando Keras
Keras es una libreria para crear arquitecturas deep learning muy sencilla. Debido a su sencillez ha conseguido una gran aceptación.
Realmente Keras en sí no calcula nada, sino que es wrapper de tensorflow (libreria bastante más compleja). De ese modo te abstraes de todos los problemas técnicos y te centras en aprender lo importante: Deep Learning.
Para instalarlo únicamente deberás usar el comando pip
o conda install
en el caso de tener anaconda:
pip install keras opencv-python
conda install keras opencv-python
Extra: si no tienes instalado python, deberías hacerlo antes de nada: https://www.python.org/
Descargando el dataset
Primero de todo para empezar esta sección es necesario que te descargues una base de datos de gatos y perros que puedes encontrar https://www.kaggle.com/lingjin525/dogs-and-cats-fastai#dogscats.zip
Una vez lo tengas descargado y descomprimido verás que tiene las siguientes carpetas:
- train: muestras que están etiquetados y sirve para entrenar la red.
- valid: muestras que están etiquetados y ayuda a monitorizar si la red está sufriendo problemas de overffiting (cuando aprende demasiado sobre los muestras de entrenamiento).
- test1: muestras no etiquetados para realizar tests.
- sample: subset de imágenes para ver cómo son.
Cargando el dataset
Para cargar nuestro dataset usaremos las propias funciones que ya incluye Keras.
Además añadiremos un proceso llamado data-aumentation que nos va a permitir añadir aumentar el numero de muestras aplicando rotaciones, traslaciones, zoom, cambios de iluminación, etc. Además redimensionamos las imágenes a 32x32 (porque si no tu ordenador podría explotar ;-)).
Como el problema es binario, nos interesará etiquetar los datos como: perro=1, gato=0.
Creando la arquitectura
Ahora es el turno de empezar a crear la red. Primero de todo deberás importar los módulos necesarios.
La arquitectura de la red esta pensada para ocupar poco espacio y poderlo ejecutar en un ordenador convencional.
Se pondrá únicamente una neurona al final junto a la sigmoid para representar la probabilidad de ser perro o gato.
Definiendo la función de perdida, optimizador y métricas.
En este caso definiremos que elementos estarán involucrados únicamente en el aprendizaje.
Adam es un tipo de optimizador que no requiere parámetros de learning rate explícitos sino que los estima.
La loss function binary_crossentropy se usa para cuantificar el error cuando la salida es una probabilidad que discrimina entre únicamente dos clases (perro o gato).
Finalmente algo que no hemos visto son las métricas. Son funciones útiles que ayudan a monitorizar el proceso pero que no participan activamente en el entrenamiento.
Entrenamiento
Vamos a entrenar este modelo durante 50 épocas donde cada una tendrá 2000 iteraciones. Eso quiere decir que la red corregirá 50*2000 veces los pesos.
Las iteraciones incrementan cada vez que se actualizaban los pesos. Y las epocas incrementan cuando se había aprendido con todos las muestras del dataset y se vuelve a empezar. En el caso de 50 épocas, pasaremos 50 veces por un mismo ejemplo.
Durante el entrenamiento veremos como por consola nos aparece cómo va evolucionando nuestra red:
Ahora tomatelo con calma, este proceso es lento y probablemente pueda estar bastantes horas. Si eres impaciente para obtener algo puedes reducir el numero de epocas, iteraciones, batch size o incrementar el learning rate.
Una vez terminado el entrenamiento guardaremos la red en formato json para la arquitectura y h5 para los pesos.
¡Usando nuestra red neuronal!
Primero de todo vamos a crear un parser de argumentos en el que facilitaremos la imagen o carpeta de imágenes a procesar.
Cargamos el modelo que anteriormente aprendimos:
Cargamos las imágenes. Por defecto cv2.imread
carga las imágenes en BGR, añadiendo […,::-1]
transformamos la imagen en RGB. Luego la redimensionamos a 32 x 32 y la dividimos por 255 (igual que en el entrenamiento).
Finalmente enviamos las imágenes a la red neuronal, los procesamos y obtenemos los resultados:
Los resultados son los siguientes:
¡Y eso ha sido todo! Este es el primer articulo sobre redes neuronales, hemos condensado mucho la información para que entendáis las bases. Pero eso nos ha permitido despertar tu curiosidad y ver las capacidades que tiene el Deep Learning.
A continuación os proporciono el github del proyecto para que tengáis más accesible: https://github.com/adriaciurana/medium-cnn
Si estáis interesados en saber más también podéis navegar por mí blog: http://www.bigneuralvision.com/blog/ (donde en un seguido de articulos explico como crear vuestro propio framework de DL).
Espero que os haya gustado el articulo.