Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

KERAS

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 60

Universidad Autónoma de Madrid

Escuela politécnica superior

Grado en Ingenieria Informática

Trabajo Fin de Grado

HERRAMIENTAS MODERNAS
EN REDES NEURONALES: LA
LIBRERÍA KERAS

Autor: Carlos Antona Cortés


Tutor: José Ramón Dorronsoro Ibero

Enero 2017
Herramientas modernas en redes neuronales: la librerı́a keras

HERRAMIENTAS MODERNAS
EN REDES NEURONALES: LA
LIBRERÍA KERAS

Autor: Carlos Antona Cortés


Tutor: José Ramón Dorronsoro Ibero

Codigo: 1617 032 CO


Dpto. de Neurocomputación
Escuela Politécnica Superior
Universidad Autónoma de Madrid
Enero 2017

i
Resumen

El mundo de las redes neuronales está en auge. Poder simular el cerebro humano en un
ordenador, parece ser uno de los hitos más prometedores de la informatica. Es cierto que este
hito todavı́a no se ha conseguido, pero mediante algoritmos de machine learning, ya es posible
entrenar máquinas para que aprendan de forma parecida a como lo harı́a nuestro cerebro. El
objetivo de este Trabajo de Fin de Grado es poner en práctica estos algoritmos utilizando la
librerı́a Keras.

En primer lugar, se hará una breve introduccion al mundo de las redes neuronales. Se em-
pezará por lo más básico, explicando qué es una red neuronal y definiendo las partes mas
importantes de su arquitectura. Una vez entendidos los conceptos básicos, se describirán los
tres tipos de redes neuronales mas extendidas actualmente debido a sus buenos resultados: Per-
ceptrón multicapa, redes convolucionales, y redes LSTM.

En segundo lugar, se describirá Keras, una librerı́a Python de deep learning con la cual podre-
mos diseñar nuestros propios modelos de redes neuronales. Se detallarán las clases y funciones
más importantes, ası́ como la gran cantidad de posibilidades que nos ofrece.

Por último, se aplicarán todos los conocimientos descritos anteriormente para diseñar cuatro
tipos de redes neuronales que resolverán dos tipos de problemas distintos. En cuanto a proble-
mas de clasificación de datos, veremos como una maquina es capaz de clasificar si una persona
tendrá diabetes a partir de sus datos médicos, y veremos como clasificar imágenes en las que
aparecen números para determinar que número es el que se representa en la imagen. Por otro la-
do, se llevarán a cabo dos problemas de predicción de datos. Mediante el primero, estudiaremos
como predecir el precio de distintas viviendas segun cualidades que se han recogido previamente,
y con el segundo, veremos como esta máquina es capaz de generar textos una vez haya sido
entrenada con ellos.

Palabras Clave

Redes neuronales, Keras, Tensorflow, perceptrón, redes convolucionales, redes LSTM, dia-
betes, housing, mnist, generador de texto.

ii
Abstract

The world of neural networks is growing. Being able to simulate the human brain in a com-
puter seems to be one of the most promising milestones in computing. It is true that it has not
been achieved, but using machine learning algorithms, it is already possible to train machines
to learn in a similar way as our brain. The objective of this End-of-Grade Work is to implement
these algorithms using the Keras library.
First of all, a brief introduction to the world of neural networks will be made. It will start with
the basics, explaining what is a neural network and defining the most important parts of its
architecture. After understanding the basics, I will describe the three types of neural networks
more promising due to their results: Multilayer Perceptron, Convolutional Networks, and LSTM
Networks.

Secondly, I will describe Keras, a deep learning python library with which we are able to design
our own neural network models. I will detail the classes and the most important functions, as
well as the great amount of possibilities that this library offers us.

Finally, all previous knowledge is applied to design four types of neural networks that will
solve two different types of problems. As for the problems of data classification, we will see how
to clasify a person depending of if she or he will have diabetes or not analyzing their medical da-
ta, and we will see how to classify images of handwritten numbers, to determine which number
is represented in the picture. On the other hand, data prediction problems will be addressed.
Through the first example, we will be able to predict the prize of several houses according to
qualities that have been previously collected, and with the second, we will see how a machine
is able to generate texts once he has been trained with them.

Keywords

Neural network, Keras, Tensorflow, perceptron, convolutional neural network, LSTM net-
work, diabetes, housing, mnist, text generator.

iii
Agradecimientos

En primer lugar quiero dar las gracias a mi tutor, José Dorronsoro, por darme la oportunidad
de adentrarme en el mundo de las redes neuronales. En una mundo tan extenso, relativamente
novedoso, y en constante desarrollo, me habrı́a sido mucho mas dificil cumplir con mis objetivos
si no fuese gracias a su constante ayuda.

En segundo lugar quiero dar las gracias a mis compañeros de clase: Sergio, David, Javi, Galan,
Gus, Alfonso... Durante estos 4 años podrı́a decir que han sido las personas con las que más
momentos he compartido, y por tanto, no pueden faltar en mis agradecimientos. Incontables
son los dias que hemos pasado en las salas de estudio de la biblioteca, las semanas entrando
a la universidad cuando aún no habı́a amanecido y saliendo cuando el sol ya se habı́a ido, los
periodos de examenes y práctcicas en los que hemos tenido que dormir menos de lo que nos
hubiese gustado... En fin, gracias por hacerme el camino mas ameno.

Una mención especial a mis amigos de Vallecas, los de toda la vida: Alvaro, Alberto, Ivan,
Benze... En estos cuatro años hemos cambiado mucho, y gracias a las vacaciones, el canal de
música, las noches de viernes en el bar... he conseguido tomarme ese respiro todas las semanas
para abstraerme lo necesario de los estudios, y seguir disfrutando de la vida.

Por último, y no por ellos menos importante, quiero ofrecer una mención especial a mi fa-
milia. No me cabe duda de que gracias a ellos y a su educación, estoy donde estoy. Ellos han
sido los que verdaderamente han tenido que aguantarme estos 19 años de estudio. Semanas de
nervios, luces encendidas a altas horas de la noche, apoyos y consejos cuanto mas lo necesitaba...
No tendrı́a páginas suficientes en este TFG para agradecerles todo lo que han hecho por mi.

iv
Índice general

Indice de Figuras VIII

1. Introducción 1
1.1. Motivacion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1.1. ¿Qué es deep learning? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1.2. ¿Qué podemos hacer mediante deep learning? . . . . . . . . . . . . . . . . 2
1.2. Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3. Estructura del documento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

2. Estado del arte: Redes neuronales 4


2.1. Redes neuronales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.1.1. Historia de las redes neuronales . . . . . . . . . . . . . . . . . . . . . . . . 4
2.1.2. La neurona biológica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.1.3. La neurona artificial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.1.4. Funciones de las neuronas artificiales . . . . . . . . . . . . . . . . . . . . . 7
2.1.5. Tipos de aprendizaje en redes neuronales . . . . . . . . . . . . . . . . . . 9
2.2. Perceptrón . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.3. Perceptron multicapa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.3.1. Propagación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.3.2. Consideraciones de diseño . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.3.3. Algoritmo de Retropropagación o Backpropagation . . . . . . . . . . . . . 14
2.3.4. Regla delta generalizada . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.3.5. Tasa de aprendizaje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.3.6. Sobreajuste y early stopping . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.4. Redes neuronales convolucionales . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

v
Herramientas modernas en redes neuronales: la librerı́a keras

2.4.1. Estructura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.5. Redes neuronales recurrentes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.5.1. Redes LSTM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

3. La librerı́a Keras 21
3.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.2. Instalación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.3. Modelos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
3.3.1. Modelo secuencial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
3.3.2. Clase Model de la API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
3.4. Capas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
3.4.1. Funciones básicas de las capas . . . . . . . . . . . . . . . . . . . . . . . . 22
3.4.2. Capas convolucionales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.4.3. Capas pooling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.4.4. Capas recurrentes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.5. Inicializadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.6. Activaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.7. Funciones de pérdida . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.7.1. Regularizadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.8. Optimizadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.9. Callbacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.10. Datasets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.11. Preprocesado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.12. Visualización . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.13. Wrapper para Scikit-Learn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

4. Keras: Diseño y desarrollo de modelos 27


4.1. Clasificación de pacientes segun predicción de tener diabetes - Regresión logı́stica 27
4.1.1. Cargando datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.1.2. Definiendo el modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
4.1.3. Compilando el modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
4.1.4. Ajustando el modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
4.1.5. Evaluando el modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
4.1.6. Analizando datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
4.2. Predicción del precio de una vivienda - Regresión lineal . . . . . . . . . . . . . . 30
4.2.1. Descripcion del problema . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
4.2.2. Desarrollo de la red neuronal . . . . . . . . . . . . . . . . . . . . . . . . . 30

vi
Herramientas modernas en redes neuronales: la librerı́a keras

4.2.3. Mejorando los resultados . . . . . . . . . . . . . . . . . . . . . . . . . . . 31


4.3. Clasificador de números escritos a mano - Perceptrón vs Red convolucional . . . 33
4.3.1. Cargando el dataset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
4.3.2. Resultados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
4.4. Generador de textos - Red LSTM . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
4.4.1. Aprendiendo secuencias de caracteres . . . . . . . . . . . . . . . . . . . . 36
4.4.2. Generando secuencias de caracteres . . . . . . . . . . . . . . . . . . . . . . 38
4.4.3. Analizando resultados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

5. Conclusiones y lı́neas futuras 40

Glosario de acrónimos 41

Bibliografı́a 42

A. Códigos fuente 44
A.1. 4.1. Problema de diabetes - Regresión logı́stica . . . . . . . . . . . . . . . . . . . 44
A.2. 4.2. Problema Boston Housing - Regresión lineal . . . . . . . . . . . . . . . . . . 44
A.2.1. Modelo estándar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
A.2.2. Modelo con datos de entrada normalizados . . . . . . . . . . . . . . . . . 45
A.2.3. Modelo más profundo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
A.2.4. Modelo más ancho . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
A.3. 4.3 MNIST - Perceptrón multicapa vs Red convolucional . . . . . . . . . . . . . . 47
A.3.1. Perceptrón multicapa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
A.3.2. Red convolucional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
A.4. 4.4 Generación de textos - Red LSTM . . . . . . . . . . . . . . . . . . . . . . . . 48
A.4.1. Entrenamiento de la red . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
A.4.2. Generacion de texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

vii
Indice de Figuras

2.1. Historia de las redes neuronales Imagen extraı́da de SlideShare . . . . . . . . . . 5


2.2. Estructura de una neurona Imagen extraı́da de Wikipedia . . . . . . . . . . . . . 5
2.3. Sinapsis Imagen extraı́da de Wikipedia . . . . . . . . . . . . . . . . . . . . . . . . 6
2.4. Esquema de una neurona artificial Imagen extraı́da de ibiblio.org . . . . . . . . . 6
2.5. Función identidad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.6. Función escalón binario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.7. Función logı́stica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.8. Función tangencial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.9. Función rectificadora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.10. Funcion de activación softplus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.11. Perceptron simple Imagen extraı́da de GitHub . . . . . . . . . . . . . . . . . . . . 10
2.12. Separacion lineal del perceptrón. Imagen extraı́da de Wikipedia . . . . . . . . . . 11
2.13. Separacion lineal de la funcion AND. Imagen extraı́da de Wikipedia . . . . . . . . 12
2.14. Separacion lineal de la funcion OR. Imagen extraı́da de Wikipedia . . . . . . . . 12
2.15. Perceptrón multicapa. Imagen extraı́da de Wikipedia . . . . . . . . . . . . . . . . 12
2.16. Tabla comparativa del perceptrón segun sus capas. Imagen extraı́da de GitHub . 13
2.17. Funcionamiento de capa convolucional. Imagen extraı́da de deeplearning.net . . . 16
2.18. Max-pooling aplicado a una imagen Imagen extraı́da de Wikipedia . . . . . . . . 17
2.19. Ejemplo básico de red neuronal recurrente. Imagen extraı́da de GitHub . . . . . . 18
2.20. Red neuronal recurrente desenrollada. Imagen extraı́da de GitHub . . . . . . . . 18
2.21. Red neuronal recurrente desenrollada. Imagen extraı́da de GitHub . . . . . . . . 19
2.22. Estructura del modulo repetidor. Imagen extraı́da de GitHub . . . . . . . . . . . 19
2.23. Notación del modulo repetidor. Imagen extraı́da de GitHub . . . . . . . . . . . . 19

4.1. Patrones dataset MNIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

viii
Introducción
1
1.1. Motivacion

1.1.1. ¿Qué es deep learning?

Deep Learning (aprendizaje profundo) es una rama de machine learning (aprendizaje au-
tomático) formada por un conjunto de algoritmos que intentan modelar abstracciones de alto
nivel en datos usando grafos profundos con múltiples capas de procesamiento. Estas capas de
procesamiento pueden estar compuestas por transformaciones tanto lineales como no lineales.

Antes de entrar de lleno en este mundo tan complejo, relativamente moderno, y en constante
cambio, no estarı́a de más entender que significa que una maquina pueda aprender. Muchas
veces en el mundo de la informática, nos encontramos ante problemas que son difı́ciles de pro-
gramar. Imaginemos el caso de una aplicación de reconocimiento de textos escritos a mano. Es
difı́cil imaginarse un conjunto de reglas que permitan distinguir unos caracteres de otros, ya que
dependiendo de la forma de escritura de cada individuo, los caracteres cambian relativamente
su forma. Por ejemplo, podrı́a ser bastante difı́cil distinguir el número 0 de la letra o. Junto
a este ejemplo, también tenemos muchos tipos de problemas en los que cuesta imaginarse un
conjunto de reglas para su resolución: reconocimiento de objetos, de discursos... Aquı́ es donde
entra en juego el Machine Learning en general, y el Deep Learning en partı́cular.

Si en vez de intentar escribir un programa que resuelva nuestro complejo problema, escribimos
un algoritmo que permita a nuestro ordenador estudiar miles de ejemplos con sus soluciones,
para luego aplicar la experiencia a la hora de resolver nuevos casos, estaremos aplicando Ma-
chine Learning.

El Deep Learning, que tuvo sus inicios en los años 80s, no es más que un paradigma de im-
plementación de Machine Learning. Debido a las recientes investigaciones sobre el mundo de la
Inteligencia Artificial, esta tecnologı́a se encuentra ahora mismo en constante desarrollo, ya que
se ha demostrado que es la forma más eficiente de hacer con un computador una simulación
de lo que nuestro cerebro puede llegar a hacer. A través de este TFG descubriremos que estas
tecnologı́as que a simple vista parecen futuristas o sacadas de una pelı́cula de ciencia ficción
están accesibles para cualquier programador.

1
Herramientas modernas en redes neuronales: la librerı́a keras

1.1.2. ¿Qué podemos hacer mediante deep learning?

Como ya se ha comentado, las técnicas de deep learning nos han abierto una puerta a mu-
chos tipos de problemas que hasta hace relativamente poco eran difı́cilmente programables. De
entrada, podemos resolver problemas de clasificación y predicción de una manera mucho más
eficiente y precisa. Algunos ejemplos concretos de aplicaciones que utilizan redes neuronales
podrı́an ser:

1. Colorear imágenes en blanco y negro : Tradicionalmente, esta tarea ha sido llevada


a cabo por el ser humano de manera manual, hasta que mediante el uso de deep learning, se
han utilizado los objetos y contextos de las propias imágenes para ser coloreadas. [20]

2. Añadir sonido a pelı́culas mudas : Pongamos el ejemplo de querer recrear el sonido


que hace un palo al golpear con una superficie. Si entrenamos el sistema utilizando una gran
cantidad de vı́deos donde se muestra el sonido que hace un palo al ser golpeado contra diferen-
tes superficies, nuestra red neuronal asociará los frames del vı́deo mudo con la información ya
aprendida, y seleccionará el sonido que mejor se adapte a la escena. [21]

3. Traducciones automáticas : Pese a que la traducción de palabras, frases o textos lle-


va siendo posible desde hace muchos años, mediante la utilización de redes neuronales se han
alcanzado resultados mucho mejores sobre todo en dos áreas: traducción de texto, y traducción
de imágenes. En el caso de los textos por ejemplo, se ha pasado de traducir palabras sueltas, a
analizar y entender la gramática y la conexión entre palabras, haciendo ası́ deducciones mucho
más precisas del significado global de la frase. En el caso de traducción de textos en imágenes ya
es posible de identificar letras, con ellas formar palabras, y a su vez formar un texto. En muchos
contextos a esto se le llama traducción visual, y ya ha sido implementado en aplicaciones como
Google Traductor. [22]

4. Clasificación de objetos en fotografı́as : Esta funcionalidad consiste en detectar y cla-


sificar uno o más objetos de la escena de una fotografı́a para después crear una palabra o frase
que describa el contenido de la imagen. En 2014, hubo un ”boom”de algoritmos que alcanzaron
resultados impresionantes a la hora de resolver este problema. Un ejemplo de aplicación que usa
este algoritmo podrı́a ser Life on Live. [23]

5. Generación de textos : Esta tarea consiste en, dado una recopilación de textos, generar
nuevos textos a partir de una palabra o una frase [18]. Una aplicación podrı́a ser la generación
de textos escritos a mano. Mediante machine learning, podemos aprender la relación entre los
movimientos del bolı́grafo y las letras escritas con la idea de generar nuevos ejemplos. Esta
funcionalidad puede ser utilizada por médicos forenses o especialistas en análisis de manuscri-
tos, ya que es posible aprender una cantidad impresionante de estilos de escritura. Otra posible
aplicación serı́a la de generar nuevos textos con nuevas historias. Mediantes redes LSTM se
ha conseguido aprender la relación entre los distintos elementos de un texto (letra, palabra,
frase...), para después generar nuevos textos letra a letra o palabra a palabra. Los modelos son
capaces de aprender como puntuar, formar oraciones, e incluso copiar los estilos de escritura
para generar dichos textos. Veremos un ejemplo de uso en el apartado 4.4.

6. Inteligencia artificial en videojuegos : Por todos es sabido que la inteligencia artifi-


cial en los vı́deojuegos es una tecnologı́a con la que llevamos conviviendo mucho tiempo. En
un shooter, la IA sabe identificar dónde está tu jugador, y con esa información, sabe a quién y
dónde disparar. Pero... ¿Y si fuese posible analizar, por ejemplo, todos los pı́xeles de la pantalla?
Mediante deep learning esto es relativamente sencillo, permitiendo a la IA rival analizar mucha

2 CAPÍTULO 1. INTRODUCCIÓN
Herramientas modernas en redes neuronales: la librerı́a keras

más información para tomar ası́ mejores decisiones. Un ejemplo nos lo encontramos en AlphaGo
[24], una aplicación desarrollada por Google que ganó al campeón mundial de Go.

Otros ejemplos de aplicaciones de redes neuronales para resolver problemas actuales podrı́an
ser: reconocimiento y traducción de discursos y charlas en tiempo real, foco automático en ob-
jetos en movimiento en fotografı́as, conversión automática de objetos en fotografı́as, respuestas
automáticas a preguntas sobre objetos en fotografı́as... Como se puede observar, casi todas estas
tareas se tratan de automatizar. Son tareas que el ser humano puede hacer manualmente, pero
una maquina es capaz de aprender a hacerlo en mucho menos tiempo y con mucha más eficiencia
y precisión.

1.2. Objetivos

Los objetivos marcados a cumplir en este TFG son los siguientes:

Realizar un primer acercamiento al mundo de las redes neuronales. Entender su funciona-


miento básico, y estudiar los tipos de redes neuronales más extendidas.
Realizar un estudio de la librerı́a Keras para descubrir que herramientas nos puede facilitar
a la hora de crear redes neuronales.
Aplicar los conocimientos estudiados sobre redes neuronales para diseñar varios ejemplos
utilizando la librerı́a Keras.

1.3. Estructura del documento

La estructura de este TFG se divide en las siguientes secciones:

Estado del arte : en este capı́tulo se llevará a cabo un primer acercamiento al concepto de
red neuronal. Se empieza analizando la neurona biológica ası́ como su funcionamiento, para
luego formar la idea de neurona artificial. Se detallan las funciones necesarias para que una
neurona artificial se comporte del mismo modo que una biológica. Una vez comprendidos
los conceptos básicos, se analizan tres de los tipos de redes neuronales más extendidas:
perceptrón, redes convolucionales, y redes LSTM
La librerı́a Keras : en este capı́tulo se describirá que es Keras y que puede aportarnos a
la hora de programar una red neuronal. Se explica la forma de crear un modelo, ası́ como
la manera de aplicarle todos los conceptos aprendidos en el capı́tulo 2.
Desarrollo y pruebas de modelos : en este capı́tulo se describirán cuatro problemas
y la forma de resolverlos aplicando redes neuronales mediante la librerı́a Keras. Predeci-
remos la probabilidad de que un paciente tenga diabetes analizando sus datos médicos.
Veremos como predecir el precio óptimo de una vivienda a partir de varias cualidades de
sus alrededores. Detectaremos números escritos a mano, clasificandolos según el número
escrito. Y por último, creamos un modelo de red neuronal que sea capaz de escribir texto
por él mismo.
Conclusiones : en este capı́tulo se hará una pequeña reflexión sobre el potencial de las
redes neuronales a la hora de crear nuevas aplicaciones, y se propondrán posibles nuevas
lineas de investigación.
Anexo : encontraremos los códigos completos para resolver los cuatro problemas propues-
tos.

CAPÍTULO 1. INTRODUCCIÓN 3
Estado del arte: Redes neuronales
2
2.1. Redes neuronales

2.1.1. Historia de las redes neuronales

Desde hace cientos de años, se ha intentado estudiar el cerebro humano. Sin embargo, a
partir de los años 50, cuando se empezó a desarrollar las bases de la tecnologı́a actual, hubo
un fuerte avance en este estudio desde la perspectiva de la computación. Las redes neuronales
artificiales, como su propio nombre indica, pretenden imitar la forma de funcionamiento de las
neuronas que forman el cerebro humano.

Años 40 :

A principios de los años 40, el neurólogo Warren McCulloch y el matemático Walter Pitts
propusieron los primeros modelos matemáticos y eléctricos de redes neuronales. Descri-
bieron como funcionaban las neuronas, y modelaron un red neuronal simple utilizando
circuitos eléctricos.
A finales de década, Donald Hebb definió dos conceptos muy importantes:
• El proceso de aprendizaje se localiza principalmente en la sinapsis, también conocida
como conexión entre neuronas.
• La información se representa en el cerebro humano mediante un conjunto de neuronas
activas o inactivas.
Estas dos reglas se sintetizan en la regla de aprendizaje de Hebb, que sigue siendo aplicada
en algunos modelos actuales. Esta regla afirma que los cambios en los pesos de la sinapsis
se basan en la interacción entre las neuronas pre y post sintácticas, y en el número de
veces que se activan de manera simultanea.

Años 50:

En 1956 en la ciudad de Dartmouth, se llevó a cabo la primera conferencia sobre Inte-


ligencia Artificial donde se discutió sobre la capacidad de las maquinas para simular el
aprendizaje humano.
A finales de los años 50, el neurobiólogo Frank Rosenblatt empezó a trabajar en el concepto
de Perceptrón. Esto dio lugar a la regla de aprendizaje Delta, que permitı́a emplear señales
continuas de entrada y de salida.

4
Herramientas modernas en redes neuronales: la librerı́a keras

En 1959 Bernard Widrow y Marcian Hoff desarrollaron los algoritmos Adaline (Adaptative
Linear Neuron) y Madaline (Multiple Adaline). Estos modelos fueron empleados para
desarrollar la primera solución a un problema real aplicando redes neuronales: un filtro
que eliminaba el eco en las llamadas telefónicas.

Años 80:

En 1982, el interés por las redes neuronales se renovó. John Hopfield presentó varios
artı́culos a la Academia Nacional de Ciencias en los que no solo describı́a el modelado del
cerebro humano, si no que demostró que aplicaciones podrı́a tener su estudio a la hora de
crear nuevos dispositivos.

En 1984, Kohonen desarrolló una familia de redes de memoria asociativa y mapas auto-
organizativos, actualmente llamadas redes de Kohonen.

En 1985, Paul Werbos desarrolló el algoritmo Backpropagation que resolvió el problema


de entrenar redes neuronales multicapa de forma efectiva.

En 1986, los investigadores Hinton y Sejnowski desarrollaron la máquina de Boltzmann,


un tipo de red neuronal recurrente estocástica.

Figura 2.1: Historia de las redes neuronales


Imagen extraı́da de SlideShare

2.1.2. La neurona biológica

El cerebro, visto a un alto nivel y simplificando enormemente su estructura, se podrı́a definir


como un conjunto de millones y millones de células, llamadas neuronas, interconectadas entre
ellas mediante sinapsis. La sinapsis se lleva a cabo en la zona donde 2 neuronas se conectan, y
las partes de la célula que se encargan de realizarla son las dendritas y las ramificaciones del
axón.

Figura 2.2: Estructura de una neurona


Imagen extraı́da de Wikipedia

CAPÍTULO 2. ESTADO DEL ARTE: REDES NEURONALES 5


Herramientas modernas en redes neuronales: la librerı́a keras

Cada neurona desarrolla impulsos eléctricos que se trasmiten a lo largo de ésta mediante su axón.
Éste, al final se divide en ramificaciones axionales, que conectan con otras neuronas mediante
sus dendritas. El conjunto de elementos que hay entre la ramificación axional y la dendrita
forman la sinapsis, que regula la transmisión del impulso eléctrico mediante unos elementos
quı́micos llamados neurotransmisores.

Figura 2.3: Sinapsis


Imagen extraı́da de Wikipedia
Los neurotransmisores liberados en la sinapsis pueden tener un efecto negativo o positivo sobre
la transmisión del impulso eléctrico en la neurona que los recibe en sus dendritas. Esta neurona
recibe varias señales de las distintas sinapsis, y las combina consiguiendo un cierto nivel de
estimulación. En función de este nivel de activación, la neurona emite señales eléctricas mediante
impulsos, con una intensidad determinada y con una frecuencia llamada tasa de disparo.
En resumen, si consideramos que la información del cerebro está codificada en impulsos eléctricos
que se transmiten entre neuronas, y que los impulsos se ven modificados básicamente en la
sinapsis, podemos intuir que la codificación del aprendizaje estará en la sinapsis y en la forma
en la que las neuronas dejan pasar o inhiben las señales segregando neurotransmisores.

2.1.3. La neurona artificial

Las neuronas artificiales son modelos que tratan de simular el comportamiento de las
neuronas biológicas. Cada neurona se representa como una unidad de proceso que forma parte
de una entidad mayor, la red neuronal.

Figura 2.4: Esquema de una neurona artificial


Imagen extraı́da de ibiblio.org
Como podemos intuir observando la imagen anterior, la neurona artificial se comporta en cierto
modo como una biológica, pero de forma simplificada:

6 CAPÍTULO 2. ESTADO DEL ARTE: REDES NEURONALES


Herramientas modernas en redes neuronales: la librerı́a keras

Entradas (x1 , x2 , ...): estos valores pueden ser enteros, reales o binarios y equivaldrı́an a
los impulsos que envı́an otras neuronas a través de sus dendritas.

Pesos (w1 , w2 , ...): equivaldrı́an a los mecanismos de sinapsis necesarios para transmitir el
impulso.

El producto de los valores xi , wi equivaldrı́a a las señales quı́micas inhibidoras y excita-


doras que se dan en la neurona. Estos valores son la entrada de la función de activación,
que convierte todo el conjunto de valores en uno solo llamado potencial. La función de
ponderación suele ser la suma ponderada de las entradas y los pesos sinápticos.

La salida de la función de ponderación llega a la función de activación que transforma este


valor en otro en el dominio que trabajen las salidas de las neuronas. Suele ser una función
no lineal como la función paso o la función sigmoide, aunque también se usa funciones
lineales.

En resumen, podemos establecer las siguientes analogı́as:

Neuronas biológicas ⇐⇒ Neuronas Artificiales.

Conexiones sinápticas ⇐⇒ Conexiones ponderadas.

Efectividad de las sinapsis⇐⇒ Peso de las conexiones.

Efecto excitador o inhibidor de una conexión ⇐⇒ Signo del peso de una conexión.

Activación → Tasa de disparo ⇐⇒ Función de activación → Salida

2.1.4. Funciones de las neuronas artificiales

Función de red o propagación

Esta función se encarga de transformar las diferentes entradas que provienen de la capa
anterior, en el potencial de la neurona actual. Normalmente, las neuronas han de tratar si-
multáneamente con varios valores de entrada, y han de hacerlo como si se tratase de uno solo.
Esta función viene a resolver el problema de combinar las entradas simples (x1 , x2 , x3 ...) en una
sola entrada global. Podrı́a describirse mediante la siguiente ecuación:

input = (x1 : w1 ) ∗ (x2 : w2 ) ∗ ... ∗ (xn : wn ) (2.1)

siendo ” : ” el operador apropiado (por ejemplo: sumatorio, máximo, producto...), x las distintas
entradas y w el peso de las conexiones. Multiplicando las entradas por los pesos, se permite que
un valor muy grande de entrada pueda tener una influencia pequeña, si sus pesos son pequeños.
Por lo general, este operador suele ser la suma ponderada de todas las entradas multiplicadas
por sus respectivos pesos.
Xn
0
y = x i ∗ wi (2.2)
i=1

Función de activación

La función de activación combina el potencial que nos proporciona la función de propagación


con el estado actual de la neurona para conseguir el estado futuro de ésta (activada/desactivada).
Esta función es normalmente creciente y monótona. Las funciones más comunes son:

CAPÍTULO 2. ESTADO DEL ARTE: REDES NEURONALES 7


Herramientas modernas en redes neuronales: la librerı́a keras

Identidad: es una función de activación muy simple que siempre devuelve como salida su
valor de entrada. Su rango es (−∞, ∞), y es una función monótona.

f (x) = x (2.3) Figura 2.5: Función identidad

Escalón binario: es la función más usada por redes neuronales binarias, ya que no es lineal
y es bastante sencilla. El Perceptrón y Hopfield son algunos ejemplos de redes que utilizan
esta función. Cuenta con un rango (0,1), y es monótona.

 
0 x<0
f (x) = (2.4) Figura 2.6: Función escalón binario
1 x≥0

Logı́stica / Sigmoide / Softstep: es una de las funciones más utilizadas para modelar
redes neuronales. Su rango es continuo en los valores (0,1), es monótona e infinitamente
diferenciable.

1
f (x) = (2.5) Figura 2.7: Función logı́stica
1 + e−x

Tangente hiperbólica: esta función es utilizada por redes con salidas continuas. Un ejemplo
serı́a el Perceptrón multicapa con retropropagación, ya que su algoritmo de aprendizaje
necesita una función derivable. Cumple con un rango (-1,1), es monótona, y se aproxima
a la función identidad en su origen.

ex − e−x
f (x) = tanh(x) = (2.6) Figura 2.8: Función tangencial
ex + e−x

Rectificadora (ReLU - Rectified Linear Unit): Esta función de activación la introdujo


por primera vez en el año 2000 Hahnloser, con motivaciones biológicas y matemáticas. Se
viene usando en redes convolucionales más que la ampliamente extendida función logı́stica
sigmoide (se basa en probabilidades), y es más practica que la tangente hiperbólica. La
función rectificadora es, por tanto, una de las funciones de activación más populares para
deep learning.

8 CAPÍTULO 2. ESTADO DEL ARTE: REDES NEURONALES


Herramientas modernas en redes neuronales: la librerı́a keras

 
0 x<0
f (x) = (2.7) Figura 2.9: Función rectificadora
x x≥0

Softplus: aproximación suavizada de la función de activación rectificadora.

Figura 2.10: Funcion de activación


f (x) = ln(1 + ex ) (2.8) softplus

2.1.5. Tipos de aprendizaje en redes neuronales

Aprendizaje supervisado

Los modelos de aprendizaje supervisado son aquellos utilizados cuando el problema nos
presenta de antemano tanto el conjunto de datos de entrada como los atributos que queremos
predecir. Existen dos categorı́as:

Regresión: los valores de salida son una o más variables continuas. Un ejemplo serı́a pre-
decir el valor de una casa en función de sus metros cuadrados, el número de habitaciones,
tamaño de la piscina... (Problema Boston-Housing detallado en el punto 4.2)

Clasificación: los datos pertenecen a dos o más clases, y se busca aprender como clasificar
nuevas entradas en esas clases a partir de datos que ya conocemos. Uno de los ejemplos
más conocidos es el Iris dataset, donde se intenta clasificar los datos en 4 tipos de flores
según la longitud y la anchura de sus pétalos y sépalos. Otro de ellos es el problema del
dataset MNIST, que busca clasificar imágenes de números en los 10 tipos de caracteres
numéricos (problema detallado en el punto 4.3).

Aprendizaje no supervisado

Este problema se da cuando no hay información previa de salidas para el conjunto de en-
tradas. En estos casos, el objetivo es encontrar grupos mediante clustering, o determinar una
distribución de probabilidad sobre un conjunto de entrada.

2.2. Perceptrón

En los años 50, F.Rosenblatt desarrolló por primera vez la idea de Perceptrón basándose
en la regla de aprendizaje de Hebb y en los modelos de neuronas biológicas de McCulloch y
Pitts. Uno de las caracterı́sticas que más interés despertó de este modelo fue su capacidad para
aprender a reconocer patrones.
El perceptrón se basa en una arquitectura monocapa. Está constituido por un conjunto de
células de entrada, que reciben los patrones a reconocer o clasificar, y una o varias células de

CAPÍTULO 2. ESTADO DEL ARTE: REDES NEURONALES 9


Herramientas modernas en redes neuronales: la librerı́a keras

salida que se ocupan de clasificar estos patrones de entrada en clases. Cada célula de entrada
está conectada con todas las células de salida. En la figura 2.11 se puede observar la arquitectura
de un perceptrón simple con 4 entradas y 1 salida.

Figura 2.11: Perceptron simple


Imagen extraı́da de GitHub

El umbral (θ) es un parámetro utilizado como factor de comparación a la hora de generar la


salida de una neurona. En esta arquitectura, la salida de la neurona se calcula multiplicando
los valores de las entradas, por los pesos de las conexiones:
n
X
y0 = wi x i (2.9)
i=1

Sin embargo, la salida definitiva depende del umbral, por lo que se obtiene aplicándole la función
de salida al nivel de activación de la célula, es decir:

y = F (y 0 , θ) (2.10)

si y 0 ≥ θ 1

y= (2.11)
si y 0 < θ 0
Con estas fórmulas, podemos deducir que la salida de la célula (y) será 1 (neurona activada) si
y 0 > θ, o 0 (neurona desactivada) en caso contrario.
La función de salida (F ) produce una salida binaria, por lo que es un diferenciador en dos
categorı́as. En el caso de tener únicamente dos dimensiones, con las ecuaciones 2.9, 2.10 y 2.11
se podrı́a llegar a la ecuación
w1 x 1 + w2 x 2 + θ = 0 (2.12)
que es la ecuación de una recta con pendiente
w1
− (2.13)
w2
y cuyo corte en la abscisa en el eje x pasa por
θ
− . (2.14)
w2
Como podemos ver en la figura 2.12, podemos imaginarnos el perceptrón como una recta, que
en un gráfica de dos dimensiones deja las dos categorı́as a separar a un lado y a otro de la
misma.

10 CAPÍTULO 2. ESTADO DEL ARTE: REDES NEURONALES


Herramientas modernas en redes neuronales: la librerı́a keras

Figura 2.12: Separacion lineal del perceptrón.


Imagen extraı́da de Wikipedia

Aprendizaje

El perceptrón es un tipo de red basado en aprendizaje supervisado, es decir, necesita conocer


los valores esperados para cada una de las entradas antes de construir el modelo. Este proceso
se lleva a cabo mediante la inserción de patrones de entrada del dataset con el que que se quiere
entrenar la red.
Entrenar la red no es más que encontrar los pesos sinápticos y el umbral que mejor haga
predecir a nuestra red los resultados esperados. Para la determinación de estas variables, se
sigue un proceso adaptativo. Se comienza con unos valores aleatorios, y se van modificando
según la diferencia entre los valores deseados y los obtenidos por la red.
En resumen, el perceptrón simple aprende iterativamente siguiendo estos pasos:

1. Inicialización de variables

2. Bucle de iteraciones:

a) Bucle para todos los ejemplos


1) Leer valores de entrada
2) Calcular error
3) Actualizar pesos según el error
a 0 Actualizar pesos de entradas
b 0 Actualizar el umbral
b) Comprobar que el vector de pesos es correcto

3. Salida

Capacidades de un perceptrón simple

Hasta ahora, hemos descrito el perceptrón como un clasificador. Sin embargo, también pue-
den ser usados para emular funciones lógicas elementales como AND, OR y NAND. Conside-
remos las funciones AND y OR. Dado que son funciones linealmente separables, pueden ser
aprendidas por un perceptrón.
Sin embargo, la función XOR no puede ser aprendida por un único perceptrón, ya que requiere
el uso de al menos dos rectas para separar las clases. Si se quiere alcanzar esta funcionalidad,
es necesario utilizarse al menos una capa más. Aquı́ es donde entra en juego el perceptrón
multicapa.

CAPÍTULO 2. ESTADO DEL ARTE: REDES NEURONALES 11


Herramientas modernas en redes neuronales: la librerı́a keras

Figura 2.13: Separacion lineal de la Figura 2.14: Separacion lineal de la


funcion AND. funcion OR.
Imagen extraı́da de Wikipedia Imagen extraı́da de Wikipedia

2.3. Perceptron multicapa

El perceptrón muticapa tuvo su origen en los años 80, con la idea de solucionar el mayor
problema que presenta el perceptrón simple: no ser capaz de aprender funciones no linealmente
separables (como es el caso de la función XOR). Se ha demostrado que es un aproximador
universal de funciones.
Éste, es un modelo de red neuronal con alimentación hacia delante, es decir, con conexiones sin
bucles (tipo de red feedforward). Está compuesto por varias capas ocultas entre la entrada y la
salida, y se caracteriza por tener salidas disjuntas pero relacionadas entre sı́ (siendo la salida de
una neurona la entrada de la siguiente).

Figura 2.15: Perceptrón multicapa.


Imagen extraı́da de Wikipedia
Las capacidades de decisión de un perceptrón multicapa de 2 y 3 capas con una única neurona
de salida se muestran en la figura 2.16:
En el perceptrón multicapa, al igual que en el perceptrón simple, podemos diferenciar una fase
de propagación de los valores de entrada hacia delante, y una fase de aprendizaje en la que
los errores obtenidos a la salida del perceptrón se van propagando hacia atrás con el objetivo
de actualizar los pesos de las conexiones mediante el gradiente de la función de error. Este
algoritmo se llama backpropagation o retropropagación.

2.3.1. Propagación

Imaginemos un perceptrón multicapa con C capas. Llamemos W C = Wijc a la matriz de


pesos de la capa c y c + 1, donde Wijc representa el peso de la neurona i de la capa c a la
neurona j de la capa c+1. Denominaremos U C = uci al vector de umbrales de las neuronas de la

12 CAPÍTULO 2. ESTADO DEL ARTE: REDES NEURONALES


Herramientas modernas en redes neuronales: la librerı́a keras

Figura 2.16: Tabla comparativa del perceptrón segun sus capas.


Imagen extraı́da de GitHub

capa c. Se denomina aci a la activación o entrada de la neurona i de la capa c. Las activaciones


de las neuronas se calculan de forma distinta dependiendo de la capa en la que nos encontremos.

Capa de entrada: la activación se corresponde con el patrón de entrada del perceptrón.


Capa oculta: la activación procede de las salidas de las capas anteriores conectadas a las
neuronas de esta capa. Esta activación se calcula como la suma de los productos de las
activaciones que reciben las neuronas de las capas anteriores multiplicadas por su peso,
añadiéndoles el umbral, es decir:
nc−1
X
c−1 c−1
outci = f ( wji aj + uci ) (2.15)
j=1

Capa de salida: ocurre lo mismo que en las capas ocultas, salvo que ahora la salida de las
neuronas se corresponde con la salida de la red.

La función f es a lo que llamamos función de activación. Las funciones de activación más


utilizadas en el perceptrón multicapa son la función sigmoidal y la función tangente hiperbólica.
Ambas poseen un intervalo continuo dentro de los rangos [0,1] y [-1,1], y están relacionadas
mediante la expresión fthip (x) = 2fsigm (x) − 1, por lo que la utilización de una u otra depende
de cual sea más compatible con el tipo de patrón que se va a utilizar. La función sigmoidal tiene
un nivel de saturación inferior igual a 0, y la tangente hiperbólica lo tiene a -1.
Normalmente, la función de activación suele ser la misma en todas las neuronas de la red
exceptuando las neuronas de la capa de salida que suelen utilizar dos funciones distintas: la
función identidad, generalmente utilizada en problemas de regresión, y la función sigmoidal, en
problemas de clasificación.

2.3.2. Consideraciones de diseño

A la hora de diseñar un perceptrón multicapa para abordar un problema, el primer paso


es determinar la arquitectura de la red. Esto implica determinar tres variables, ya explicadas
anteriormente:

Función de activación: se elige según el comportamiento y el recorrido deseado, pero no


influye en la capacidad de la red para resolver el problema.
Número de neuronas de entrada y de salida: viene dado por la definición del problema.
En ocasiones esta afirmación no tiene porque ser del todo cierta, y se ha de proceder a

CAPÍTULO 2. ESTADO DEL ARTE: REDES NEURONALES 13


Herramientas modernas en redes neuronales: la librerı́a keras

hacer un análisis previo basándose en técnicas de análisis de correlación, de sensibilidad,


de importancia relativa...

Número de capas ocultas: pese a ser una variable que ha de definir el diseñador, no existe
un método que determine el número óptimo de capas ocultas necesarias para resolver un
problema, ya que existen muchos tipos de arquitectura distintos capaces de resolver un
mismo ejercicio. Uno de los métodos, por ejemplo, serı́a partir de una arquitectura ya
entrenada, e ir realizando pequeños cambios en el número de neuronas/capas ocultas para
buscar ası́ el diseño óptimo.

2.3.3. Algoritmo de Retropropagación o Backpropagation

Como se ha comentado anteriormente, el proceso de aprendizaje del perceptrón multicapa


consiste en propagar hacia atrás cierta información desde la salida del perceptrón hasta su en-
trada. Esta información será el error entre la salida obtenida y la salida esperada, con el objetivo
de que en las siguientes iteraciones la salida obtenida se aproxime lo máximo posible a la salida
esperada. Por tanto, nos encontramos ante un algoritmo de aprendizaje supervisado.
Hay muchas funciones de error que se pueden utilizar, pero el perceptrón multicapa usa habi-
tualmente la función del error cuadrático medio, que se define como:
n
c
1X
e(n) = (si (n) − yi (n))2 (2.16)
2
i=1

siendo n cada una de las iteraciones del aprendizaje. El error obtenido e(n) es el error de una
sola iteración, por lo que si queremos entrenar la red con varios patrones, el error medio de esta
1 PN
será E = N n=1 e(n). En resumen, el perceptrón multicapa aprende encontrando el mı́nimo
de la función de error.
Aunque el aprendizaje debe llevarse a cabo minimizando el error total, los métodos más utili-
zados son los basados en métodos de gradiente estocástico, que consisten en minimizar el error
en cada patrón e(n). Por tanto, aplicando el método de gradiente descendiente, cada peso de la
red w se actualiza para cada patrón de entrada n, y siendo α la tasa de aprendizaje, de acuerdo
con la siguiente ecuación:
∂e(n)
w(n) = w(n − 1) − α (2.17)
∂w
Dado que las neuronas de la red están agrupadas en capas ocultas según niveles, es posible
aplicar el método del gradiente descendente de forma eficiente en todas las neuronas, llevando
a cabo el algoritmo de retropropagación o regla delta generalizada.

2.3.4. Regla delta generalizada

Como se ha comentado previamente, la regla delta generalizada no es más que una forma
eficiente de aplicar el método de gradiente a los parámetros de la arquitectura (pesos y umbra-
les). Su uso consiste en ajustar pesos y bı́as tratando de minimizar la suma del error cuadrático.
Para ello, se cambian dichas variables en la dirección contraria al gradiente del error.
Las redes neuronales entrenadas mediante esta técnica, dan respuestas más que razonables cuan-
do al sistema se le presentan entradas que nunca habı́a analizado antes. A una nueva entrada,
le hará corresponder una entrada similar a la salida obtenida para un patrón de entrenamiento,
siendo éste similar al patrón presentado a la red. Esta es una de las grandes propiedades de la
regla delta, su capacidad de generalización.

14 CAPÍTULO 2. ESTADO DEL ARTE: REDES NEURONALES


Herramientas modernas en redes neuronales: la librerı́a keras

2.3.5. Tasa de aprendizaje

La tasa de aprendizaje (α) es un parámetro que determina la velocidad a la que van a cambiar
los pesos de las conexiones de la red. Tiene generalmente un rango [0,1], siendo los valores más
cercanos a cero los que hacen que los pesos cambien poco a poco, acercándose lentamente a
la convergencia, y los cercanos a uno los que hacen que la red converja más rápidamente al
principio, pero siendo posible que los pesos oscilen demasiado al encontrar el peso óptimo final.
Por esta razón es importante encontrar una tasa de aprendizaje óptima.
Aquı́ es donde entra en juego un segundo término llamado momento (η), que pondera cuánto
queremos que influya lo que los pesos han cambiado en la anterior iteración. Con ello, sabremos
que si los pesos han cambiado mucho es que estamos aún lejos del valor de la tasa de aprendizaje
óptimo, por lo que se avanzará en su búsqueda más rápidamente. Por otro lado, si los pesos no
han cambiado apenas, sabremos que el valor óptimo de α está cerca.
Si se modifica la ecuación 2.17 para añadir esta mejora, quedarı́a de la siguiente manera:

∂e(n)
w(n) = w(n − 1) = −α + η∆w(n − 1) (2.18)
∂w
siendo ∆w(n − 1) = w(n − 1) − w(n − 2) el incremento que sufrió el parámetro w en la anterior
iteración.

2.3.6. Sobreajuste y early stopping

El sobreajuste o overfitting es el efecto secundario de sobreentrenar un algoritmo de aprendi-


zaje con ciertos datos para los que ya se conoce el resultado deseado. El algoritmo debe alcanzar
un estado en el cual sea capaz de predecir otros casos a partir de lo ya aprendido mediante datos
de entrenamiento, generalizando para poder resolver distintas situaciones a las ya presentes du-
rante el entrenamiento. No obstante, cuando un sistema se entrena demasiado o se entrena con
datos extraños, el algoritmo tiende a quedarse ajustado a unas caracterı́sticas muy especificas de
los datos de entrenamiento que no representan un estado general del problema. En este estado,
nuestro diseño es más eficaz al responder a muestras del conjunto de entrenamiento, pero ante
nuevas entradas el resultado empeora.
Una manera de resolver este problema es extraer un conjunto de entradas del dataset de entre-
namiento, y utilizarlo de manera auxiliar a modo de validación. Ya que este subconjunto se deja
al margen durante el entrenamiento, su objetivo será evaluar el error en la red tras cada época
para determinar cuando éste empieza a aumentar. Cuando aumente, se prodecerá a detener el
entrenamiento y se conservarán los valores de los pesos del ciclo anterior. A este método se le
conoce como early-stopping.

2.4. Redes neuronales convolucionales

Las redes neuronales convolucionales son muy similares a las redes neuronales ordinarias
descritas hasta ahora, como el perceptrón multicapa. Las neuronas tienen pesos, sesgos, reciben
una entrada con la que realiza un producto escalar y sobre la que aplica una función de activa-
ción, tienen una función de perdida...
Sin embargo, se utilizan principalmente para resolver el mayor problema que tienen las redes
neuronales ordinarias: el tratamiento de imágenes. Pese a que con las redes neuronales estándar
es posible manejar imágenes (veremos el ejemplo del MNIST en el apartado 4.3), en cuanto las
imágenes aumentan su tamaño y calidad esto se vuelve intratable. Al tratarse de neuronas to-
talmente conectadas, provocarı́amos un desperdicio de recursos ası́ como un rápido sobreajuste.

CAPÍTULO 2. ESTADO DEL ARTE: REDES NEURONALES 15


Herramientas modernas en redes neuronales: la librerı́a keras

Las redes neuronales convolucionales trabajan dividiendo y modelando la información en par-


tes más pequeñas, y combinando esta información en las capas más profundas de la red. Por
ejemplo, en el caso del tratamiento de una imagen, las primeras capas tratarı́an de detectar
los bordes de las figuras. Las siguientes capas buscarı́an combinar los patrones de detección de
bordes para conseguir formas más simples, y aplicar patrones de posición de objetos, ilumi-
nación... Por último, en las últimas capas se intentará hacer coincidir la imagen con todos los
patrones descubiertos, para conseguir una predicción final de la suma de todos ellos. Ası́ es como
las redes neuronales convolucionales consiguen modelar una gran cantidad de datos, dividiendo
previamente el problema en partes para conseguir predicciones más sencillas y precisas.

2.4.1. Estructura

En general, todas las redes neuronales convoluciones están formadas por una estructura
compuesta por 3 tipos de capas:

Capa convolucional

Esta capa le da nombre de la red. En vez de utilizar la multiplicación de matrices como


en la redes neuronales estándar, se aplica una operación llamada convolución. Esta operación
recibe como entrada una imagen, y sobre ella aplica un filtro que nos devuelve su mapa de
caracterı́sticas, reduciendo ası́ el tamaño de sus parámetros. La convolución utiliza tres ideas
que ayudan a mejorar cualquier sistema sobre el que se aplique machine learning:

Interacciones dispersas: Al aplicar un filtro de menos tamaño sobre la entrada, redu-


cimos bastante el número de parámetros y cálculos.

Parametros compartidos: Compartir parámetros entre los distintos tipos de filtros


ayuda a mejorar la eficiencia del sistema.

Representaciones equivariantes: Si las entradas cambian, las salidas cambian de forma


similar.

Además, la convolución proporciona herramientas para trabajar con entradas de tamaño varia-
ble, lo cual es muy útil cuando se trabaja con imágenes (cada imagen tiene un número distinto
de pı́xeles). Se basa en un operador matemático que transforma dos funciones f y g, en una
tercera, que en cierto sentido, representa la magnitud en la que se superponen f y una versión
trasladada y rotada de g.

Figura 2.17: Funcionamiento de capa convolucional.


Imagen extraı́da de deeplearning.net

16 CAPÍTULO 2. ESTADO DEL ARTE: REDES NEURONALES


Herramientas modernas en redes neuronales: la librerı́a keras

Capa de reducción o pooling

Esta capa se coloca generalmente después de la capa convolucional. Es la encargada de


reducir la cantidad de parámetros a analizar reduciendo las dimensiones espaciales (ancho x
alto), quedándose de esta forma con las caracterı́sticas más comunes. La operación que lleva a
cabo esta capa también se llama reducción de muestreo o submuestreo, ya que la reducción de
tamaño implica también una perdida de información. Sin embargo, para un red neuronal, este
tipo de pérdida puede ser beneficioso debido a:

La reducción del tamaño provoca una menor sobrecarga de cálculo en las próximas capas
de la red.

Reduce habitualmente el sobreajuste.

La operación que se suele aplicar en esta capa es ”max-pooling”, que divide la imagen de entrada
en un conjunto de rectángulos, y respecto a cada uno de ellos, se queda con el valor máximo.

Figura 2.18: Max-pooling aplicado a una imagen


Imagen extraı́da de Wikipedia

Capa clasificadora totalmente conectada

Una vez que la imagen ha pasado tanto por las capas convolucionales como las de pooling
y se han extraı́do sus caracterı́sticas más destacadas, los datos llegan a la fase de clasificación.
Para ello, ĺas redes convolucionales normalmente utilizan capas completamente conectadas en
las que cada pı́xel se trata como una neurona independiente. Las neuronas de esta fase funcionan
como las de un perceptrón multicapa, donde la salida de cada neurona se calcula multiplicando
la salida de la capa anterior por el peso de la conexión, y aplicando a este dato una función de
activación.

2.5. Redes neuronales recurrentes

Los seres humanos no empezamos a pensar desde cero a cada segundo. Por ejemplo, mientras
leemos, entendemos cada palabra basándonos en el contexto que forman las palabras previas.
No desperdiciamos los ideas anteriores, sino que estas tienen persistencia en la memoria.
Las redes neuronales tradicionales no cuentan con esta capacidad, y es su mayor defecto. Por
ejemplo, imaginemos el caso en el que queremos clasificar que clase de evento está pasando en
un punto de una pelı́cula. No está muy claro cómo una red neuronal tradicional podrı́a usar
razonablemente las escenas anteriores para predecir las siguientes.
Y aquı́ es donde entran en juego las redes neuronales recurrentes, ya que estas sı́ resuelven este

CAPÍTULO 2. ESTADO DEL ARTE: REDES NEURONALES 17


Herramientas modernas en redes neuronales: la librerı́a keras

problema. Su principal caracterı́stica es que son redes con bucles, que permiten que la informa-
ción persista.

Figura 2.19: Ejemplo básico de red neuronal recurrente.


Imagen extraı́da de GitHub

En el diagrama 2.19, podemos ver cómo una parte de la red neuronal, A, recibe una entrada
x y devuelve una salida h. El bucle permite que la información pase de un ciclo de la red al
siguiente. Pese a que el concepto de bucle parezca algo extraño, las redes neuronales que cuentan
con ellos no son tan distantes de la redes neuronales tradicionales. Una red neuronal recurrente
puede ser creada utilizando múltiples copias de la misma red, pasando el mensaje o salida al
nodo sucesor. Si desenrollamos el bucle, tendrı́amos algo parecido a la figura 2.20:

Figura 2.20: Red neuronal recurrente desenrollada.


Imagen extraı́da de GitHub

Esta forma de cadena hace prever que las redes neuronales recurrentes están ı́ntimamente rela-
cionadas con secuencias y listas. En los últimos años, se han logrado auténticos grandes éxitos
aplicando las RNN para resolver problemas como reconocimiento de discursos, modelación de
lenguajes, traducciones, captación de imágenes... Un factor clave en estos éxitos es el uso de las
redes LSTMs, un tipo muy especial de redes neuronales recurrentes que trabajan por muchas
razones de forma más eficiente que la versión estándar.

El problema de la longitud de las dependencias.

Uno de los intereses de las RNNs es la idea de conectar información antigua con la tarea
actual. En temas de vı́deo, serı́a útil por ejemplo utilizar frames anteriores para entender el
frame actual, pero... ¿pueden las RNN hacer esto? La respuesta es, depende.
Algunas veces, sólo necesitamos utilizar información reciente para la tarea actual. Por ejemplo,
en temas de modelación de lenguaje, para adivinar la siguiente palabra en un contexto, en la
mayorı́a de los casos bastarı́a con analizar la frase en la que se encuentra. Sin embargo, hay
casos en los que se necesita acceder a un contexto más grande. Desafortunadamente, a medida
que el espacio entre la información requerida y la tarea actual aumenta, las RNN tardan cada
vez más en aprender a conectar la información.

En teorı́a, las RNN son perfectamente capaces de resolver este problema (long-term depen-
dencies), pero en la práctica no lo parece tanto. En 1991, Hochreiter estudió este problema, y
encontró algunas razones por las que las RNN encuentran dificultades a la hora de aprender
información sobre grandes contextos. Por suerte, las redes LSTMs solventan estos problemas.

18 CAPÍTULO 2. ESTADO DEL ARTE: REDES NEURONALES


Herramientas modernas en redes neuronales: la librerı́a keras

Figura 2.21: Red neuronal recurrente desenrollada.


Imagen extraı́da de GitHub

2.5.1. Redes LSTM

Las redes Long Short Term Memory (normalmente llamadas LSTMs) son un tipo especial de
redes neuronales recurrentes descritas por primera vez en 1997 por Hochreiter & Schmidhuber,
capaces de aprender una larga lista de dependencias en largos periodos de tiempo.
Todas las redes neuronales recurrentes tienen forma de cadena al repetir sus módulos. En las
RNN estándar, el modulo repetidor tiene una estructura muy simple, con una sola capa, como
podrı́a ser la de tipo tanh. Las redes LSTM tambien tienen forma de cadena, pero el modulo
repetidor en vez de tener una sola capa, tiene cuatro.

Figura 2.22: Estructura del modulo repetidor.


Imagen extraı́da de GitHub

Figura 2.23: Notación del modulo repetidor.


Imagen extraı́da de GitHub
La clave de las redes LSTMs se encuentra en el estado de la celda, es decir, en la linea horizontal
que recorre la parte superior del diagrama 2.21, ya que permite a la información fluir por toda
la red con sólo algunas pequeñas interacciones, sin ser a penas alterada. La red también tiene
la habilidad de borrar o añadir información al estado de la celda mediante estructuras llamadas
puertas. Estas puertas son una manera de permitir opcionalmente a la información circular o
no, y se componen de una capa sigmoide y una operación de multiplicación. Las salidas de la
capa sigmoide alternan entre 0 y 1, describiendo si la información fluye o no. Una red LSTM
tiene 3 de estas puertas, para proteger y controlar el estado de la celda.

Las redes neuronales LSTM siguen una serie de pasos para decidir qué información se va a
ir almacenando o borrando. Podemos destacar los siguientes:

1. Decidir qué información despreciar. Esta decisión la toma la capa sigmoide, que
devuelve una salida igual a 1 si se busca mantener la información, o 0 si queremos desha-

CAPÍTULO 2. ESTADO DEL ARTE: REDES NEURONALES 19


Herramientas modernas en redes neuronales: la librerı́a keras

cernos de ella.
Volvamos al ejemplo de modelado del lenguaje, donde se quiere predecir una palabra
basándose en las anteriores. En este problema, el estado de la celda puede almacenar el
género del sujeto para usar los pronombres adecuados. Cuando nos encontremos un nuevo
sujeto, olvidaremos el genero del anterior ya que no será de utilidad.

2. Decidir qué información se va a almacenar. Consta de dos partes: primero, una capa
sigmoide decide qué valores son actualizados. Después, una capa tanh crea un vector con
los nuevos valores candidatos que pueden ser añadidos al estado.
En el ejemplo anterior, se decidirı́a que queremos añadir el género del nuevo sujeto al
estado de la celda, para reemplazar el viejo que queremos olvidar.

3. Actualizar el estado de la celda. En el paso anterior se decide qué hacer, y ahora


toca hacerlo. Se multiplica el viejo estado por la salida de la capa sigmoide del primer
paso, olvidando ası́ las cosas que se decidieron olvidar. A esto, se le suma el producto de
la salida de la capa sigmoide y de la capa tanh del segundo paso. Con ello, se consiguen
saber los nuevos valores candidatos, escalados según la decisión de actualizar el estado de
la celda.
En el caso de modelado de lenguaje, ahora es cuando se desecha la información sobre
el género del viejo sujeto y se añade la nueva información, como se decidió en los pasos
anteriores.

4. Decidir la salida basándose en el estado de la celda, pero de manera filtrada.


Primero, mediante una capa sigmoide, se decide qué partes del nuevo estado de la celda
se van a sacar como salida. Después, se pasa el estado de la celda por una capa tanh para
tener valores entre -1 y 1, y se multiplica por la salida de la capa sigmoide para sacar solo
las partes que se decidan.
En el ejemplo de modelado de lenguaje, una vez que se encuentre el nuevo sujeto, se
sacará información acerca de él como puede ser si éste es singular o plural, para después
poder conjugar correctamente el verbo que le sigue.

Como se ha comentado anteriormente, la mayorı́a de los mejores resultados utilizando redes


recurrentes, es mediante las redes LSTMs. Pero a pesar de que su descubrimiento ha sido un
gran hito, todavı́a quedan metas por cumplir. Una de ellas serı́a dotar a las RNN de una
capacidad para decidir qué información consultar en una fuente muy grande de información.
Por ejemplo, si estamos usando redes RNN para crear un titulo que describa una imagen, serı́a
útil elegir que partes de la imagen usar para cada palabra.

20 CAPÍTULO 2. ESTADO DEL ARTE: REDES NEURONALES


La librerı́a Keras
3
3.1. Introducción

Keras es una librerı́a de redes neuronales escrita en Python y capaz de ejecutarse tanto sobre
Tensorflow como sobre Theano. Sus principales caracterı́sticas son:

Fácil y rápido prototipado gracias a su modularidad, minimalismo y extensibilidad.


Soporta tanto redes neuronales convolucionales como recurrentes (ası́ como la combinación
de ambas)
Soporta esquemas de conectividad arbitrarios (incluyendo entrenamiento multi-entrada y
multi-salida)
Corre en CPU y GPU
Es compatible con Python 2.7-3.5

3.2. Instalación

Para la instalacion de Keras, son necesarias las siguientes dependencias:

numpy y scipy : librerı́as cientificas para Python numéricas.


pyyaml : parseador YAML para Python.
HDF5 y h5py : paquete para el manejo de grandes cantidades de datos. (Opcional, pero
requı́rido si se usan funciones para cargar/guardar modelos)
cuDNN - Nvidia CUDA : librerı́a para tarjetas gráficas NVIDIA que permite la aceleración de
la GPU en temas de redes neuronales. (Opcional pero recomendado si se usan CNNs)
Tensorflow o Theano : librerı́as Python enfocadas a Machine Learning.

Existen 2 modos de instalación:

Desde PyPI: sudo pip install keras


Desde repositorio Git: sudo python setup.py install

Por defecto, Keras usa Tensorflow como motor backend. Sin embargo, esta opción puede ser con-
figurada. La primera vez se ejecuta Keras, se crea un fichero de configuración en /.keras/keras.json”,
que puede ser modificado.
"image_dim_ordering": "tf",
"epsilon": 1e-07,
"floatx": "float32",
"backend": "tensorflow"

21
Herramientas modernas en redes neuronales: la librerı́a keras

3.3. Modelos

Hay dos tipos de modelos disponibles para su implementacion en Keras: el modelo secuencial,
y la clase Model (más general). Ambos modelos presentan varios métodos en común, como summary
(), get_config() o to_json() que devuelven información basica sobre el modelo, o get_weights()
y set_weights(), los métodos getter y setter propios de los pesos del modelo.

3.3.1. Modelo secuencial

Los métodos básicss del modelo secuencial son:

compile(self, optimizer, loss, metrics=[], sample_weight_mode=None) : Calcula automática-


mente la función gradiente y prepara el modelo para una forma concreta de entrenamiento.

fit(self, x, y, batch_size=32, nb_epoch=10, verbose=1, callbacks=[], validation_split=0.0,


validation_data=None, shuffle=True, class_weight=None, sample_weight=None) : Entrena el
modelo para un número fijado de ciclos (nb_epoch), con actualizaciones de gradiente cada
batch_size ejemplos.

evaluate(self, x, y, batch_size=32, verbose=1, sample_weight=None) : Calcula la función de


perdida dados unos datos de entrada, lote por lote.

predict(self, x, batch_size=32, verbose=0) : Genera predicciones para unos valores de en-


trada.

3.3.2. Clase Model de la API

Con la clase Model, dadas una entrada y una salida, podemos inicializar nuestro modelo de
la siguiente forma:
a = Input(shape=(32,))
b = Dense(32)(a)
model = Model(input=a, output=b)

En caso de que tengamos múltiples conjuntos de entradas y de salidas, también podrı́amos


inicializarlo de la siguiente manera:
model = Model(input=[a1, a2], output=[b1, b3, b3])

3.4. Capas

3.4.1. Funciones básicas de las capas

A la hora de diseñar las capas de nuestra red neuronal, tenemos una serie de funciones
disponibles:

Dense: Para capas regulares totalmente conectadas.


keras.layers.core.Dense(output_dim, init=’glorot_uniform’, activation=’linear’, weights=None
, W_regularizer=None, b_regularizer=None, activity_regularizer=None, W_constraint=None, b_constraint
=None, bias=True, input_dim=None)

Activation:Se aplica una función de activación a una salida. Las principales funciones que
nos ofrece Keras son:

22 CAPÍTULO 3. LA LIBRERÍA KERAS


Herramientas modernas en redes neuronales: la librerı́a keras

• softmax: generalización de la función logı́stica.


• softplus

• softsign

• relu: función rectificadora


• tanh: función tangente hiperbólica
• sigmoid: función sigmoide
• hard_sigmoid

• linear: función lineal

Dropout: Consiste en establecer al azar una fracción de unidades de entrada a 0 en cada


actualización durante la fase de entrenamiento. Esto ayuda a evitar el sobreajuste.

Reshape: Transforma la salida en una forma concreta.

Algunos ejemplos de uso prodrı́an ser:

model.add(Dense(32, input_dim=16)) : modelo que contarı́a con una array de entrada de


tamaño 16, y de salida de 32.
model.add(Activation(’tanh’)) : aplica la función de activación tangencial.
model.add(Dropout(0.2)) : establecerı́a entradas a 0 en el 20 % de los casos.
model.add(Reshape((3, 4), input_shape=(12,))) : define una capa de salida de 3x4 para nues-
tro modelo.

3.4.2. Capas convolucionales

Keras presenta diversas funciones para desarrollar capas convolucionales según las dimen-
siones de su entrada. La más destacable, a modo de ejemplo, es:
Convolution2D(nb_filter, nb_row, nb_col, init=’glorot_uniform’, activation=None, weights=None,
border_mode=’valid’, subsample=(1, 1), dim_ordering=’default’, W_regularizer=None, b_regularizer
=None, activity_regularizer=None, W_constraint=None, b_constraint=None, bias=True)

Un ejemplo de uso donde se define una capa convolucional de dos dimensiones, con 32 ma-
peadores de tamaño 5x5 y una funcion de activación rectificadora, serı́a:
model.add(Convolution2D(32, 5, 5, border_mode=’valid’, activation=’relu’)) :

Además de la versión en 2D, Keras nos ofrece funciones para entradas de una dimensión o
tres dimensiones. Aparte, tenemos funcionalidades para desarrollar capas convolucionales dila-
tadas (AtrousConvolution2D), hacer deconvolución (Deconvolution2D), etc.

3.4.3. Capas pooling

Al igual que ocurre con las capas convolucionales, Keras ofrece un buen número de funciones
para desarrollar capas pooling en redes convolucionales, dependiendo de las dimensiones de la
entrada. Como en el caso anterior, una función representativa serı́a:
MaxPooling2D(pool_size=(2, 2), strides=None, border_mode=’valid’, dim_ordering=’default’)

Si en vez de utilizar la función máximo se requiere que nuestra capa utilice otro tipo de algorit-
mos, Keras también nos ofrece funciones como: AveragePooling2D, GlobalMaxPooling2D... Ası́ como
sus variantes para 1D y 3D.

CAPÍTULO 3. LA LIBRERÍA KERAS 23


Herramientas modernas en redes neuronales: la librerı́a keras

3.4.4. Capas recurrentes

Keras presenta 3 tipos de capas recurrentes:

SimpleRNN : Red recurrente estándar totalmente conectada cuya salida realimenta la entra-
da.
LSTM : Redes Long-Short Term Memory. Este tipo de red ha sido descrito en el apartado
2.5, y será puesto en ejemplo en el apartado 4.4
GRU : Gated Recurrent Unit. Red neuronal recurrente muy similar a las redes LSTM, pero
que no dispone de una unidad de memoria interna y utiliza dos puertas lógicas en lugar
de tres.

3.5. Inicializadores

Los inicializadores definen la manera de inicializar los pesos de las capas de nuestro modelo.
El argumento usado en para definir este inicializador en las capas es init. Las opciones más
comunes son:

uniform
normal
identity
zero
glorot normal
glorot uniform

3.6. Activaciones

El modo de activación puede ser implementado mediante una capa Activation (model.add
(Dense(64)); model.add(Activation(’tanh’))), o mediante un parámetro que soportan todas las
capas (model.add(Dense(64, activation=’tanh’))). Las funciones más comunes, descritas previa-
mente en el punto 2.1.4, son :

linear: función lineal.


sigmoid: función sigmoide / logı́stica.
tanh: función tangente hiperbólica.
relu: función rectificadora.
softplus: aproximación suavizada de la función rectificadora.

3.7. Funciones de pérdida

La función de perdida es uno de los dos parámetros necesarios para compilar un modelo.
Algunas de las funciones más conocidas que nos proporciona Keras son:

mean_squared_error(y_true, y_pred) : Calcula el error cuadrático medio.


mean_absolute_error / mae : Calcula el error medio absoluto.
binary_crossentropy: Calcula la entropı́a cruzada en problemas de clasificación binaria.
También conocida como perdida logarı́tmica.

24 CAPÍTULO 3. LA LIBRERÍA KERAS


Herramientas modernas en redes neuronales: la librerı́a keras

3.7.1. Regularizadores

Los regularizadores permiten aplicar penalizaciones en las capas durante la optimización.


Estas penalizaciones se incorporan a la función de perdida que la red optimiza.
Ejemplo de uso: model.add(Dense(64, input_dim=64, W_regularizer=l2(0.01), activity_regularizer
=activity_l2(0.01)))

3.8. Optimizadores

El optimizador es otro de los dos valores necesarios para compilar un modelo (junto con la
función de pérdida). Los principales optimizadores disponibles son: [14]

SGD : aproximación estocástica del metodo de gradiente descendiente descrito en los puntos
2.3.3 y 2.3.4.
Adagrad : algoritmo basado en gradiente que adapta el ratio de aprendizaje a los parámetros,
realizando grandes actualizaciones cuando éstos son infrecuentes, y pequeñas actualiza-
ciones cuando son frecuentes.
Adadelta : extensión del algoritmo Adagrad
Adam : algoritmo basado en el gradiente de primer orden de funciones estocásticas objeti-
vas. Este método es sencillo de implementar, es eficiente computacionalmente hablando,
necesita poca capacidad de memoria, y es muy bueno en problemas con una gran cantidad
de datos y/o parámetros [13]. Es utilizado por defecto en los modelos de Keras.

3.9. Callbacks

Los callbacks son una serie de funciones que pueden ser aplicadas en ciertos momentos
del proceso de entrenamiento. Estos callbacks pueden ser utilizados para echar un vistazo a los
estados internos ası́ como a las estadı́sticas del modelo que estamos entrenando. Para utilizarlos,
basta con pasar como argumento a la función fit(...) una lista de métodos, que serán llamados
en cada fase del entrenamiento. Las principales funciones son:

BaseLogger(): Se aplica en todo modelo de Keras, y acumula la media de las métricas que
se han definido para ser monitorizadas por época.

Callback(): Clase base abstracta utilizada para crear nuevos callbacks. Como paráme-
tros, recibe los propios para configurar el entrenamiento (número de ciclos, verbosidad...),
ası́ como la instancia del modelo que queremos entrenar.

ProgbarLogger(): Callback que muestra métricas en la salida estándar (stdout).

History(): Callback aplicado en cada modelo Keras que almacena eventos en un objeto de
tipo History.

ModelCheckpoint(...): Almacena el modelo después de cada época. Como argumentos recibe


el fichero donde dejar la información, la cantidad de elementos a monitorizar, el modo de
verbosidad, un booleano para decidir si sobreescribir o no el mejor modelo, el modo, y
otro booleano para guardar solo pesos o información de todo el modelo.

CAPÍTULO 3. LA LIBRERÍA KERAS 25


Herramientas modernas en redes neuronales: la librerı́a keras

3.10. Datasets

Keras cuenta con una serie de dataset ya predefinidos y listos para realizar nuestras pruebas:

CIFAR10: dataset que cuenta con 50.000 imágenes a color de entrenamiento, a clasificar
en 10 categorı́as, y 10.000 imágenes para testear los resultados. También existe una versión
con 100 categorı́as (CIFAR100).

Clasificación de sentimientos en reviews de IMDB: Este dataset cuenta con 25.000


pelı́culas etiquetadas según el sentimiento (bueno/malo). Estas reviews han sido prepro-
cesadas, y las palabras han sido indexadas según su frecuencia.

MNIST: dataset que contiene 60.000 imágenes en blanco y negro de los 10 tipos de
dı́gitos, y 10.000 imágenes para testear los modelos.

3.11. Preprocesado

Keras cuenta con una serie de funciones para procesar tanto modelos secuenciales, como
texto, como imágenes. Las más importantes son:

Modelos secuenciales: pad_sequences(...) transforma una lista en un array 2D.

Texto: text_to_word_sequence(...) separa una frase en palabras, one_hot(...) codifica un


texto en una lista de palabras indexadas en un vocabulario de tamaño n...

Imágenes: ImageDataGenerator(...) define la configuración para la preparación y el aumento


de una imágen a la hora de ser procesada.

3.12. Visualización

El módulo keras.utils.visualize_util proporciona funciones útiles para mostrar gráficamente


un modelo (acompañado del uso de graphviz). La siguiente función mostrarı́a una gráfica del
modelo y lo guardarı́a en un fichero .png.
plot(model, to_file=’model.png’)

3.13. Wrapper para Scikit-Learn

Keras presenta compatibilidad con Scikit-Learn. Esta conocida librerı́a open source pro-
porciona diversas herramientas útiles para mineria y analisis de datos. Trabaja junto con las
librerias SciPy y NumPy de Python, y permite resolver problemas de regresión, clasificación y
clustering.
Se pueden usar modelos Keras secuenciales como parte del ciclo de trabajo de Scikit-Learn
mediante sus wrappers. Existen dos interfaces disponibles:

KerasClassifier(build_fn=None, **sk_params) : Implementa una interfaz de clasificación.


KerasRegressor(build_fn=None, **sk_params) : Implementa una interfaz de regresión.

Como primer argumento tendremos la instancia de la clase o la función a llamar, y como segundo
los parámetros del modelo y de ajuste.

26 CAPÍTULO 3. LA LIBRERÍA KERAS


Keras: Diseño y desarrollo de modelos
4
4.1. Clasificación de pacientes segun predicción de tener diabe-
tes - Regresión logı́stica

Como primer ejemplo introductorio a las redes neuronales en Keras, se va a utilizar un


conocido dataset que representa diabetes en indios americanos. Este dataset se puede adquirir
en el repositorio de UCI Machine Learning [15], y describe información médica de pacientes
indios, ası́ como información sobre si han tenido diabetes en los siguientes 5 años.
La información médica especificada es la siguiente:

Número de embarazos.
Concentración de glucosa.
Presión en sangre.
Tamaño de la doblez de la piel en el triceps.
Insulina
Índice de masa corporal
Función que representa el número de antepasados con diabetes.
Edad

4.1.1. Cargando datos

Cuando se trabaja con algoritmos de Machine Learning que utilizan números aleatorios,
es una buena metodologı́a de trabajo predefinir de antemano la semilla. Con ello, podremos
ejecutar el mismo código varias veces obteniendo el mismo resultado. Esta idea es bastante
útil a la hora de demostrar un resultado, comparar distintos algoritmos, debuggear parte del
código...
Se iniciará la generación de números aleatorios con la semilla que queramos, por ejemplo:
numpy.random.seed(4)

Nos encontramos ante un problema de clasificación binaria (tener diabetes representa salida 1,
y no tenerla salida 0). Todas las variables que definen al paciente son numéricas, lo cual hace
fácil su uso directamente en redes neuronales, que esperan datos numéricos tanto en las entradas
como en las salidas.
Una vez que tenemos descargado nuestra fuente de datos, podremos cargarla directamente
usando la funcion loadtxt() de la libreria NumPy. En este dataset, podemos apreciar 8 datos

27
Herramientas modernas en redes neuronales: la librerı́a keras

de entrada, y 1 variable de salida (la última columna). Una vez cargado, podemos separar los
datos en variables de entrada y targets.
dataset = numpy.loadtxt("pima-indians-diabetes.csv", delimiter=",")
X = dataset[:,0:8]
Y = dataset[:,8]

4.1.2. Definiendo el modelo

Como se ha comentado en el capı́tulo 3, los módelos en Keras se definen como una secuencia
de capas. La primera cosa de la que hay que asegurarse, es de que la capa de entrada tiene el
número correcto de entradas. Esto se define mediante el argumento input_dim, cuando se crea
la primera capa.
Las capas totalmente conectadas se definen usando la clase Dense. Podemos especificar el núme-
ro de neuronas de la capa utilizando el primer argumento, el método de inicialización con el
segundo (init), y la función de activación usando el argumento activation.
En este caso, se inicializarán los pesos de la red con pequeños números aleatorios de una distri-
bución Gaussiana (normal). Se usará la función de activación rectificadora (relu) en las primeras
dos capas, y la función sigmoide en la capa de salida. Las funciones sigmoide e hiperbólica solı́an
ser las funciones de activación más utilizadas. Sin embargo, a dı́a de hoy, se consiguen mejores
resultados utilizando la función de activación rectificadora. La función sigmoide en la capa de
salida será necesaria para asegurarse que la salida de nuestro modelo comprende valores entre
0 y 1.
La primera capa tendrá 12 neuronas y espera 8 variables de entrada. La segunda tiene 8 neuro-
nas, y la ultima solo 1, la cual reflejará en su salida la predicción sobre si para los datos médicos
introducidos como entrada, se tendrá diabetes o no.
model = Sequential()
model.add(Dense(12, input_dim=8, init=’normal’, activation=’relu’))
model.add(Dense(8, init=’normal’, activation=’relu’))
model.add(Dense(1, init=’normal’, activation=’sigmoid’))

4.1.3. Compilando el modelo

Una vez que se ha definido el modelo, el siguiente paso es compilarlo. Aquı́ es donde entra
en juego el backend elegido (Theano o Tensorflow), ya que Keras utiliza sus librerı́as numéricas.
El propio backend es el encargado de elegir la mejor forma para entrenar la red y de hacer
predicciones con ella, utilizando la CPU, la GPU o ambas a la vez.
En la fase de compilación, se deben especificar algunas propiedades adicionales para entrenar la
red (recordar que entrenar una red significa encontrar los mejores pesos para hacer predicciones
de un problema). Debemos especificar la función de perdida para evaluar los pesos, el optimi-
zador usado para elegir entre los diferentes pesos, y métricas opcionales para recoger y mostrar
los datos durante el entrenamiento.
En este ejemplo, se utilizará una función de perdida logarı́tmica, que para los problemas de
clasificación está definida en Keras como binary_crossentropy. Como optimizador se utilizará el
algoritmo de gradiente descendiente adam, el cual usa Keras por defecto.
Finalmente, como se trata de un problema de clasificación, se recogerá y mostrará la eficiencia
de la clasificación, o lo que es lo mismo, el porcentaje de aciertos (argumento accuracy).
model.compile(loss=’binary_crossentropy’, optimizer=’adam’, metrics=[’accuracy’])

28 CAPÍTULO 4. KERAS: DISEÑO Y DESARROLLO DE MODELOS


Herramientas modernas en redes neuronales: la librerı́a keras

4.1.4. Ajustando el modelo

Una vez compilado, el siguiente paso es ejecutar el modelo con los datos de entrada. Podemos
entrenar o ajustar nuestro modelo cargando los datos utilizando la función fit().
El proceso de entrenamiento se ejecutará para un número de iteraciones definido mediante el
argumento nb_epoch. También podemos definir el número de entradas que serán evaluadas antes
de que haya una actualización de los pesos de la red mediante el argumento batch_size). De
nuevo, estas medidas pueden ser elegidas experimentalmente a base de prueba y error.
model.fit(X, Y, nb_epoch=150, batch_size=10)

4.1.5. Evaluando el modelo

Una vez entrenada la red neuronal, podemos evaluar el rendimiento de esta utilizando el
mismo dataset. Esto nos puede dar una idea de cómo hemos modelado los datos de entrada,
pero no tendremos idea de como de bien clasificará los nuevos datos nuestro modelo.
Para evaluar nuestra red, se utiliza la función evaluate(). En este ejemplo, se le pasarán las
mismas entradas que cuando se entrenó la red, generando ası́ una predicción por cada par de
entrada-salida, además de mostrar información sobre las la perdida media y la precisión de
nuestro modelo.
eva = model.evaluate(X, Y)
print(" %s: %.2f % %" % (model.metrics_names[1], eva[1]*100))

4.1.6. Analizando datos

Al ejecutar el código, podemos ver un mensaje por cada 150 ciclos mostrando la pérdida y
la precisión de cada uno, seguido de los resultados finales.
Epoch 1/150
768/768 [==============================] - 0s - loss: 0.6829 - acc: 0.6471
Epoch 2/150
768/768 [==============================] - 0s - loss: 0.6654 - acc: 0.6510
Epoch 3/150
768/768 [==============================] - 0s - loss: 0.6556 - acc: 0.6510
...
Epoch 148/150
768/768 [==============================] - 0s - loss: 0.4487 - acc: 0.7826
Epoch 149/150
768/768 [==============================] - 0s - loss: 0.4444 - acc: 0.7839
Epoch 150/150
768/768 [==============================] - 0s - loss: 0.4456 - acc: 0.7747
32/768 [>.............................] - ETA: 0
sacc: 77.34 %

El siguiente paso es adaptar el ejemplo anterior y utilizarlo para generar predicciones sobre el
dataset de entrenamiento, simulando que nos encontramos ante un nuevo dataset que nunca
hemos analizado previamente. Mediante la función model.predict, podremos realizar estas pre-
dicciones fácilmente.
Con las siguientes lineas, se mostrarán predicciones para cada entrada del dataset, que en su
mayor parte, coincidirán con los datos de salida ya descritos en el dataset. Recordar que 1 es
padecer diabetes, y 0 lo contrario.
predicciones = model.predict(X)
rounded = [round(x) for x in predicciones]
print(rounded)

CAPÍTULO 4. KERAS: DISEÑO Y DESARROLLO DE MODELOS 29


Herramientas modernas en redes neuronales: la librerı́a keras

4.2. Predicción del precio de una vivienda - Regresión lineal

4.2.1. Descripcion del problema

En este caso, nos encontramos ante un problema de regresión lineal. El dataset describe 13
propiedades numéricas de 506 casas de los suburbios de Boston, con el precio de dichas casas en
millones de dolares. Este conocido dataset puede ser adquirido en el repositorio de UCI Machine
Learning [16]. Como atributos de entrada, disponemos de:

CRIM: ratio de crimen per capita por población.


ZN: proporción de tierras residenciales zonificadas con más de 25000 pies cuadrados.
INDUS: proporción de acres no comerciales por ciudad
CHAS: Charles River dummy variable ( 1 si el tramo se encuentra en el rı́o, 0 en caso
contrario).
NOX: concentración de óxidos nı́tricos.
RM: número medio de habitaciones por vivienda.
AGE: proporción de viviendas ocupadas construidas antes de 1940.
DIS: distancias ponderadas a cinco centros de empleo.
RAD: ı́ndice de accesibilidad a las autopistas radiales.
TAX: ratio de impuestos a la propiedad por cada 10.000$.
PTRATIO: ratio de alumnos-profesores.
B: 1000(Bk − 0,63)2 donde Bk es la proporción de ciudadanos negros por población.
LSTAT: porcentaje de la población de clase baja.

Como target, nos proporcionan el valor medio de las casas ocupadas, en miles de dolares.
Un rendimiento razonable en modelos actuales usando el Error cuadrático medio (MSE) como
método de evaluación está en torno a 20 (miles de dolares al cuadrado). Veamos si podemos
igualar estos resultados.

4.2.2. Desarrollo de la red neuronal

Lo primero, será cargar todas las librerı́as necesarias, ası́ como el dataset.
dataframe = pandas.read_csv("housing.csv", delim_whitespace=True, header=None)
dataset = dataframe.values

X = dataset[:,0:13]
Y = dataset[:,13]

En este ejemplo se crearán modelos en Keras, y serán ajustados y evaluados utilizando la librerı́a
Scikit-learn. Esta librerı́a Python open source de Machine Learning es bastante potente a la
hora de evaluar modelos con pocas lineas de código.
El siguiente paso por tanto es crear el modelo de la red neuronal. Para el problema Boston-
Housing basta con diseñar un modelo de red con una sola capa oculta totalmente conectada
con el mismo número de neuronas que de entradas (13). Como función de activación en la
capa oculta se usa la función rectificadora. Para la capa de salida no se usa ninguna función
de activación debido a que nos encontramos ante un problema de regresión, y el objetivo es
predecir valores numéricos directamente sin aplicarles ningún tipo de transformación. Como
algoritmo de optimización usaremos adam, y como función de perdida el error cuadrático medio.
Estas métricas también serán usadas para evaluar el rendimiento del modelo. Se ha elegido
esta métrica ya que al usar la raı́z cuadrada, se nos presenta un valor de error directamente
entendible en el contexto del problema (miles de dolares).

30 CAPÍTULO 4. KERAS: DISEÑO Y DESARROLLO DE MODELOS


Herramientas modernas en redes neuronales: la librerı́a keras

def baseline_model():
model = Sequential()
model.add(Dense(13, input_dim=13, init=’normal’, activation=’relu’))
model.add(Dense(1, init=’normal’))
model.compile(loss=’mean_squared_error’, optimizer=’adam’)
return model

El wrapper de Keras para usar Scikit-Learn como un estimador de regresión se llama KerasRe-
gressor. Podemos crear una instancia y pasarle como argumentos:

1. El nombre de la función que define la red neuronal (baseline_model())


2. Parámetros que se le pasarán a la funcion fit(), como el número de ciclos o el tamaño de
los lotes.

Como siempre, además se debe inicializar una semilla aleatoria constante para asegurarnos que
la comparación de los modelos es consistente.
numpy.random.seed(4)
estimator = KerasRegressor(build_fn=baseline_model, nb_epoch=100, batch_size=5, verbose=0)

El siguiente paso es evaluar el modelo. Para ello, se usará una validación cruzada de 10 itera-
ciones.
kfold = KFold(n_splits=10, random_state=seed)
results = cross_val_score(estimator, X, Y, cv=kfold)
print("Resultados: %.2f ( %.2f) MSE" % (results.mean(), results.std()))

Ejecutando todo el código veremos una estimación del rendimiento del modelo. El resultado
muestra el error cuadrático medio incluyendo la media y la desviación tı́pica a lo largo de las
10 iteraciones de la evaluación por validación cruzada.
Resultados: 31.35 (25.45) MSE

4.2.3. Mejorando los resultados

Aunque ya hayamos conseguido entrenar nuestra red para obtener resultados, existen muchas
maneras de mejorar nuestro modelo. En este ejemplo, veremos tres:

Normalizar el dataset de entrada


Aumentar el número de capas
Aumentar el número de neuronas en las capas

Normalizando el dataset

Un factor muy importante en el dataset de Boston-housing es que los atributos de entrada


varı́an mucho sus escalas, ya que miden cantidades diferentes. Por este tipo de razones, siempre
suele ser una buena práctica preparar los datos antes de modelarlos usando nuestra red neuronal.
Para ver la diferencia con esta mejora, se va a usar el mismo modelo de red neuronal que en
el apartado anterior. Se va a usar el framework Pipeline de Scikit-Learn para estandarizar
el modelo de datos durante el proceso de evaluación dentro de cada pliegue de la validación
cruzada. Esto asegura que no haya datos de nuestro set de entrenamiento sin evaluar en cada
pliegue de la validación cruzada.
numpy.random.seed(seed)
estimators = []
estimators.append((’standardize’, StandardScaler()))
estimators.append((’mlp’, KerasRegressor(build_fn=baseline_model, nb_epoch=50, batch_size=5,
verbose=0)))

CAPÍTULO 4. KERAS: DISEÑO Y DESARROLLO DE MODELOS 31


Herramientas modernas en redes neuronales: la librerı́a keras

pipeline = Pipeline(estimators)
kfold = KFold(n_splits=10, random_state=seed)
results = cross_val_score(pipeline, X, Y, cv=kfold)
print("Estandarizado: %.2f ( %.2f) MSE" % (results.mean(), results.std()))

En el código anterior, se crea un Pipeline de Scikit-Learn, donde primero se estandarizan los


datos y luego se evalúa el modelo desarrollado en el apartado anterior. Al ejecutar todo el
código, vemos una mejora en el rendimiento respecto al modelo sin estandarizar los datos.
Estandarizado: 30.78 (29.41) MSE

Red neuronal más profunda

Otra manera de mejorar nuestra red neuronal es añadirle capas, lo cual permitirá al modelo
extraer más cantidad de caracterı́sticas del dataset.
En este apartado se evaluará el efecto de añadir más de una capa al modelo. Ésto es tan fácil
como crear una nueva función copia de la anterior, pero insertando nuevas lineas después de
la primera capa oculta. En este ejemplo, cada capa tendrá la mitad de neuronas que la capa
anterior.
def modelo_profundo():
model = Sequential()
model.add(Dense(13, input_dim=13, init=’normal’, activation=’relu’))
model.add(Dense(6, init=’normal’, activation=’relu’))
model.add(Dense(1, init=’normal’))
model.compile(loss=’mean_squared_error’, optimizer=’adam’)
return model

Como podemos apreciar, los datos pasarán por una capa de entrada de 13 neuronas, después
por una de 6, para acabar en una capa de salida de una sola neurona. La forma de evaluar el
modelo será la misma que en el apartado anterior, usando la estandarización de los datos de
entrada para mejorar aún más el rendimiento.
Ejecutando todo el código podemos ver otra importante mejora en el rendimiento respecto al
apartado anterior:
Resultados: 24.10 (28.45) MSE

Red neuronal más ancha

Otra forma de incrementar la capacidad de nuestro modelo es crear un red más ancha. En
este apartado se evaluará el efecto de añadir a nuestra arquitectura una capa oculta con el doble
de neuronas de las que tiene la capa de entrada.
De nuevo, se ha de definir una nueva función como en los ejemplos anteriores, pero que cuente
con una capa oculta entre la capa de entrada y la de salida de 20 neuronas.
def modelo_ancho():
model = Sequential()
model.add(Dense(20, input_dim=13, init=’normal’, activation=’relu’))
model.add(Dense(1, init=’normal’))
model.compile(loss=’mean_squared_error’, optimizer=’adam’)
return model

Como podemos ver, nuestros datos pasarán de una capa de entrada de 13 neuronas, a una capa
oculta de 20, para luego acabar en una capa de salida de una sola neurona. De nuevo, la forma de
evaluar el modelo será la misma que en los dos apartados anteriores, usando la estandarización
de los datos de entrada para mejorar el rendimiento.
Ejecutando el código podemos ver una mejora aún mayor que la que se consiguió con la red
neuronal más profunda. No es nada mal resultado para este tipo de problema:

32 CAPÍTULO 4. KERAS: DISEÑO Y DESARROLLO DE MODELOS


Herramientas modernas en redes neuronales: la librerı́a keras

Resultados: 21.66 (24.12) MSE

Como se ha comentado anteriormente, no es del todo fácil ver que con una red más profunda se
consigan mejores resultados en este tipo de problemas. Esto demuestra la importancia de tener
que testear varios tipos de modelos, para conseguir ası́ los mejores resultados.

4.3. Clasificador de números escritos a mano - Perceptrón vs


Red convolucional

El dataset MNIST fue desarrollado con el objetivo de evaluar modelos de redes neuronales
utilizando el problema de clasificación de dı́gitos escritos a mano. Este dataset esta constitui-
do por un gran número de documentos escaneados por el National Institute of Standards and
Technology (NIST), a los cuales se le han extraı́do y normalizado sus caracteres. Cada imagen
es de 28x28 pı́xeles, y se usan 60.000 imágenes para entrenar el modelo, y otras 10.000 para
probarlo.
Estamos hablando de una tarea de reconocimiento de dı́gitos. Al haber 10 dı́gitos (del 0 al 9),
hay 10 clases para clasificar. El estado del arte del error de predicción está en el 0,2 %, que
puede ser alcanzado con grandes redes neuronales convolucionales en las que se aplican técnicas
avanzadas como DropConnect o aumento de patrones.

4.3.1. Cargando el dataset

Mediante la librerı́a Keras, es posible descargarse el dataset de manera automática. Para


ello, se llamará a la función mnist.load_data(), que almacenará la información en el directorio
˜/.keras/datasets/mnist.pkl.gz.

Figura 4.1: Patrones dataset MNIST


No es estrictamente necesaria una red neuronal convolucional para conseguir buenos resultados
con el dataset MNIST. Mediante una red neuronal sencilla, con una sola capa oculta, podemos
alcanzar un ratio de error del 1.74 %. Se usará este dato como base para comparar más modelos
de redes convolucionales más adelante.
Lo primero de todo, como ya hemos visto, es cargar los módulos necesarios, generar una semilla
aleatoria (aunque fija), y cargar el dataset.
El set de entrenamiento está estructurado como un array tridimensional compuesto por la
imagen, su ancho y su alto. Para poder utilizarlo con un perceptrón, tenemos que convertir las
imágenes en un vector de pı́xeles. En este caso, las imágenes de 28x28 se convertirán en 748
valores de entrada. Podemos hacer esto fácilmente con la función reshape() de NumPy.
numpy.random.seed(4)

n_pixels = X_train.shape[1] * X_train.shape[2]


X_train = X_train.reshape(X_train.shape[0], n_pixels).astype(’float32’)
X_test = X_test.reshape(X_test.shape[0], n_pixels).astype(’float32’)

CAPÍTULO 4. KERAS: DISEÑO Y DESARROLLO DE MODELOS 33


Herramientas modernas en redes neuronales: la librerı́a keras

Los valores van de 0 a 255, en una escala de grises. Cuando se trabaja con modelos de
redes neuronales, suele ser buena idea escalar o normalizar los datos de entrada. Para ello, se
convertirán estos valores del rango 0-255 al 0-1.
Además, la salida será un entero entre 0 y 9 (ya que como hemos dicho, tenemos 10 clases en
las que nuestra imagen puede ser clasificada). Nos encontramos ante un problema de multicla-
sificación, por lo que será útil codificar el vector de enteros en una matriz binaria:
X_train = X_train / 255
X_test = X_test / 255

y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)
num_classes = y_test.shape[1]

Con todo esto, ya se puede crear el modelo de la red neuronal. En este ejemplo, vamos a
diseñar tanto un modelo de red neuronal basado en un perceptrón multicapa como un modelo
convolucional, para ver sus diferencias y rendimientos a la hora de tratar imágenes.

Perceptrón multicapa

def perceptron_model():
model = Sequential()
model.add(Dense(n_pixels, input_dim=n_pixels, init=’normal’, activation=’relu’))
model.add(Dense(num_classes, init=’normal’, activation=’softmax’))
model.compile(loss=’categorical_crossentropy’, optimizer=’adam’, metrics=[’accuracy’])
return model

Como podemos observar, se trata de un modelo con una sola capa oculta, con el mismo número
de neuronas que de entradas, es decir, 784. Además, sobre ella se aplica una función de activa-
ción rectificadora.
En la capa de salida, se usa la función de activación softmax para convertir las salidas en una
probabilidad, y permitir que se seleccionen una de las 10 clases que el modelo ha de predecir.
Como función de perdida, se utiliza la perdida logarı́tmica (en Keras, categorical_crossentropy).
Por último, para que la red entrene y aprenda los pesos, se utiliza el algoritmo gradiente des-
cendiente adam.

Red convolucional

def convolutional_model():
model = Sequential()
model.add(Convolution2D(32, 5, 5, init=’glorot_uniform’, border_mode=’valid’,
input_shape=(1, 28, 28), activation=’relu’))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.2))
model.add(Flatten())
model.add(Dense(128, activation=’relu’))
model.add(Dense(num_classes, activation=’softmax’))
model.compile(loss=’categorical_crossentropy’, optimizer=’adam’, metrics=[’accuracy’])
return model

Como podemos ver, las redes convolucionales son bastante más complejas que los perceptrones
multicapa. En resumen, nuestro modelo cuenta con las siguientes capas:

1. La primera capa es una capa convolucional (Convolution2D). Cuenta con 32 mapeado-


res, de tamaño 5x5, una función de activación rectificadora, y un inicializador de tipo
glorot_uniform (usado por defecto en las capas convolucionales de Keras) . Al ser la capa
de entrada, esperará imágenes con la forma [[ı́pxeles][ancho][alto]].

34 CAPÍTULO 4. KERAS: DISEÑO Y DESARROLLO DE MODELOS


Herramientas modernas en redes neuronales: la librerı́a keras

2. Después se define una capa pooling que utilizará la función máximo, con un tamaño de
2x2.
3. La siguiente capa (Dropout) será regularizadora. Se ha configurado para excluir aleatoria-
mente el 20 % de las neuronas de la capa y ası́ reducir el sobreajuste.
4. La siguiente capa (Flatten) convertirá la matriz de 2 dimensiones en un vector, permitiendo
de esta forma que la salida pueda ser procesada por una capa totalmente conectada.
5. Después se ha añadido una capa totalmente conectada con 128 neuronas y una función
de activación rectificadora.
6. Finalmente, la capa de salida tendrá 10 neuronas, una por cada clase a predecir, y una
función de activación softmax para hacer una aproximación de la probabilidad de que
cada entrada se corresponda con cada clase (es decir, con cada número).

Como en el ejemplo del perceptrón multicapa, el modelo se entrenará usando la función de


pérdida logarı́tmica y el algoritmo adam de gradiente descendiente.

4.3.2. Resultados

Ahora ya podemos ajustar y evaluar los modelos. Estos se ajustán cada 10 ciclos, con
actualizaciones cada 200 imágenes. Finalmente, se muestra el ratio de error de clasificación.
model = perceptron_model() // model.convolutional_model
model.fit(X_train, y_train, validation_data=(X_test, y_test), nb_epoch=10, batch_size=200,
verbose=2)
scores = model.evaluate(X_test, y_test, verbose=0)
print("Baseline Error: %.2f % %" % (100-scores[1]*100))

Ejecutando todo el código anterior utilizando el modelo del perceptrón multicapa, veremos la
siguiente salida. Como podemos observar, esta red neuronal tiene un ratio de error de 1.88 %.
Epoch 1/10
10s - loss: 0.2792 - acc: 0.9206 - val_loss: 0.1358 - val_acc: 0.9615
Epoch 2/10
8s - loss: 0.1096 - acc: 0.9681 - val_loss: 0.0917 - val_acc: 0.9720
Epoch 3/10
8s - loss: 0.0704 - acc: 0.9799 - val_loss: 0.0727 - val_acc: 0.9780
...
Epoch 8/10
9s - loss: 0.0152 - acc: 0.9963 - val_loss: 0.0620 - val_acc: 0.9797
Epoch 9/10
10s - loss: 0.0104 - acc: 0.9978 - val_loss: 0.0598 - val_acc: 0.9821
Epoch 10/10
9s - loss: 0.0089 - acc: 0.9980 - val_loss: 0.0640 - val_acc: 0.9812
Classification Error: 1.88 %

Sin embargo, si ejecutamos el código utilizando el modelo convolucional, tendrı́amos un ratio


de error de 1.02 %, y la siguiente salida:
Epoch 1/10
162s - loss: 0.2484 - acc: 0.9289 - val_loss: 0.0799 - val_acc: 0.9773
Epoch 2/10
151s - loss: 0.0752 - acc: 0.9777 - val_loss: 0.0519 - val_acc: 0.9833
Epoch 3/10
151s - loss: 0.0531 - acc: 0.9841 - val_loss: 0.0376 - val_acc: 0.9883
...
Epoch 8/10
150s - loss: 0.0191 - acc: 0.9938 - val_loss: 0.0298 - val_acc: 0.9898
Epoch 9/10
156s - loss: 0.0173 - acc: 0.9945 - val_loss: 0.0306 - val_acc: 0.9901
Epoch 10/10
155s - loss: 0.0162 - acc: 0.9949 - val_loss: 0.0323 - val_acc: 0.9898
Classification Error: 1.02 %

CAPÍTULO 4. KERAS: DISEÑO Y DESARROLLO DE MODELOS 35


Herramientas modernas en redes neuronales: la librerı́a keras

Como se puede observar, hemos reducido el error de clasificación del 1.88 % al 1.02 %. Pero...
¿podrı́amos obtener mejores resultados? La respuesta es sı́. En este ejemplo, se ha utilizado una
red convolucional muy simple. Sin embargo, añadiendo más capas convolucionales, de pooling
y totalmente conectadas, podemos acercarnos a ratios de error muy cercanos al estado del
arte actual. Por ejemplo, añadiendo una nueva capa convolucional y de pooling (model.add(
Convolution2D(15, 3, 3, activation=’relu’)), model.add(MaxPooling2D(pool\_size=(2, 2)))),y una
nueva capa totalmente conectada (model.add(Dense(50, activation=’relu’))), obtendrı́amos un
ratio de error de 0.89 %.

4.4. Generador de textos - Red LSTM

En este ejemplo, se va a intentar generar textos que más o menos tengan sentido. Hasta la
aparición de las redes neuronales, que un ordenador pudiese llevar a cabo esta tarea parecı́a una
idea sacado de una pelı́cula de ciencia ficción. Sin embargo, con las redes LSTM esto empieza
a ser posible.
Las redes neuronales, además de ser usadas para predecir modelos, pueden ser utilizadas para
aprender secuencias de un problema y generar mediante estos conocimientos nuevas secuencias.
Los modelos que generan nuevas secuencias como éste, no solo son útiles para saber como de bien
ha aprendido nuestra máquina un problema, sino también para saber más sobre un problema
en sı́ mismo.
En este ejemplo, se va a utilizar el libro ”La metamorfosis”de Kafka como dataset para nuestra
red neuronal. Ésta, va a aprender las dependencias entre los distintos caracteres que se vaya
encontrando a lo largo del texto ası́ como las probabilidades de que estos caracteres aparezcan,
con el objetivo de generar una nueva secuencia de caracteres, formando ası́ un nuevo texto y
una nueva historia. Este ejemplo también es válido para otro tipo de textos: poemas, código
fuente... Siempre que éstos se encuentren en código ASCII.

4.4.1. Aprendiendo secuencias de caracteres

Primero se importan las clases que se van a utilizar en el problema y se carga el texto
convirtiéndolo todo a minúsculas.
filename = "kafka.txt"
raw_text = open(filename).read()
raw_text = raw_text.lower()

Una vez cargado el libro en memoria, debemos prepararlo para ser tratado por una red neuronal.
Una buena idea es convertir los caracteres a números enteros. Para ello, primero se identifican
todos los caracteres que componen el texto y se asocia un número a cada uno de ellos. Además,
para reducir el número de caracteres a analizar, se eliminarán los caracteres repetidos.
chars = sorted(list(set(raw_text)))
char_to_int = dict((c, i) for i, c in enumerate(chars))

El siguiente paso es definir el conjunto de entrenamiento. Se dividirá el texto en conjuntos de


caracteres (en este ejemplo 100), para pasárselos como entrada a la red neuronal. El objetivo es
que la red prediga el carácter 101. Esto se conseguirá desplazando de 1 en 1 los 100 caracteres
seleccionados, permitiendo ası́ que cada carácter sea aprendido por los 100 caracteres que le
preceden. Por ejemplo, si hiciésemos divisiones de 5 en 5, y tuviésemos la palabra CAPITULO,
las iteraciones serı́an:
CAPIT -> U
APITU -> L
PITUL -> O

36 CAPÍTULO 4. KERAS: DISEÑO Y DESARROLLO DE MODELOS


Herramientas modernas en redes neuronales: la librerı́a keras

Dado que las redes neuronales trabajan con números en vez de caracteres, debemos convertir
estos caracteres a enteros usando la tabla que generamos anteriormente.
seq_length = 100
dataX = []
dataY = []
for i in range(0, n_chars - seq_length, 1):
seq_in = raw_text[i:i + seq_length]
seq_out = raw_text[i + seq_length]
dataX.append([char_to_int[char] for char in seq_in])
dataY.append(char_to_int[seq_out])
n_patterns = len(dataX)
print "Patrones totales: ", n_patterns

Una vez que hemos preparado el dataset, necesitamos transformarlo para que pueda ser usa-
do por Keras. Primero, debemos transformar la lista de entradas (seq_in) en una secuencia
de la forma [muestra, intervalo de tiempo, caracteristica], que será lo que espere nuestra red
LSTM. Después, se necesita escalar los enteros al rango 0-1 para conseguir patrones más fáciles
de aprender por la red neuronal, que usará la función de activación sigmoide. Finalmente, se
convertirán los patrones de salida. Para ello, se representará la salida como una probabilidad de
que aparezca cada uno de los 43 caracteres distintos que componen el texto, en vez de intentar
predecir estrictamente el siguiente carácter. Cada valor será convertido a un vector de longitud
43, relleno de ceros salvo un uno que concidirá con la columna de la letra que el patrón represen-
ta. Por ejemplo, si la letra fuese la C (entero número 3), la codificación serı́a... [0,0,1,0,0,0,0,0...0]
Esto se consigue mediante las siguientes lineas de código.
X = numpy.reshape(dataX, (n_patterns, seq_length, 1))
X = X / float(n_vocab)
y = np_utils.to_categorical(dataY)

Una vez que tenemos los datos preparados, es hora de definir nuestra red LSTM. Para este
ejemplo, se definirán dos capas ocultas LSTM con 256 unidades de memoria. Se usará la técnica
de regularización conocida como Dropout con una probabilidad del 20 % para evitar el sobreajus-
te. La capa de salida será una capa Dense que usará softmax como función de activación para
producir una salida en función de la probabilidad de que aparezca uno de los 43 caracteres.
En realidad, podemos observar que el problema es realmente un problema de clasificación con
43 clases, y por ello se define la función de perdida logarı́tmica categorical_crossentropy y se
aplica el algoritmo de optimización adam para mejorar la velocidad.
model = Sequential()
model.add(LSTM(256, input_shape=(X.shape[1], X.shape[2])))
model.add(Dropout(0.2))
model.add(LSTM(256))
model.add(Dropout(0.2))
model.add(Dense(y.shape[1], activation=’softmax’))
model.compile(loss=’categorical_crossentropy’, %optimizer=’adam’)

En este ejemplo, el interés no está en la precisión de la clasificación, ya que se crearı́a un


modelo que predecirı́a cada carácter del conjunto de entrenamiento perfectamente. En vez de
eso, estamos interesados en una generalización del dataset que minimice la función de perdida.
Es decir, estamos buscando un balance entre generalización y sobreajuste.
Esta red es lenta de entrenar. Por ello, se ha decidido usar una serie de checkpoints para
almacenar todos los pesos de la red en un fichero al final de cada ciclo cada vez que se observe
una mejora en la perdida. Usaremos los mejores pesos (menores pérdidas) para generar nuestro
modelo en punto 4.4.2.
filepath="weights-improvement-{epoch:02d}-{loss:.4f}.hdf5"
checkpoint = ModelCheckpoint(filepath, monitor=’loss’, verbose=1, save_best_only=True, mode=’
min’)
callbacks_list = [checkpoint]

CAPÍTULO 4. KERAS: DISEÑO Y DESARROLLO DE MODELOS 37


Herramientas modernas en redes neuronales: la librerı́a keras

Por último, ya solo queda ajustar nuestro modelo. Usaremos 50 ciclos y una tamaño de lote de
64 patrones.
model.fit(X, y, nb_epoch=50, batch_size=64, callbacks=callbacks_list)

Cada vez que se ejecute el modelo, nos encontramos ante diferentes valores. Esto es debido a
la naturaleza aleatoria del modelo y a que es difı́cil elegir una semilla aleatoria para las redes
LSTM que reproduzcan los resultados con un 100x100 de exactitud. A pesar de ello, éste no es
el objetivo del modelo.
Una vez ejecutado el script completo, se deben haber generado una serie de archivos checkpoint
con los mejores pesos de cada ciclo. Para ejecutar el código del siguiente apartado donde ya se
generarán nuevas secuencias de caracteres, se usarán los valores del último archivo ya que son
los que tienen un menor valor de pérdida.

4.4.2. Generando secuencias de caracteres

Una vez entrenada nuestra red, se han cargar los pesos que se han calculado y guardado en
nuestro checkpoint.
filename = "weights-improvement-49-1.1691-bigger.hdf5"
model.load_weights(filename)
model.compile(loss=’categorical_crossentropy’, optimizer=’adam’)

Además, también se ha de crear un mapeo inverso de caracteres a enteros para convertir de


nuevo los enteros utilizados en la red a caracteres.
int_to_char = dict((i, c) for i, c in enumerate(chars))

Por último, solo queda hacer las predicciones. La manera más simple es iniciar con una secuen-
cia de semillas como entrada, generar el siguiente carácter, después actualizar la secuencia de
semillas para añadir el carácter generado al final, y quitar el primer carácter. Este proceso se re-
petirá mientras queramos generar nuevos carácteres. Elegiremos un patrón aleatorio de entrada
como nuestra secuencia de semillas, y se mostrarán los caracteres según se vayan generando.
start = numpy.random.randint(0, len(dataX)-1)
pattern = dataX[start]
print "Semilla:"
print "\"", ’’.join([int_to_char[value] for value in pattern]), "\""

for i in range(300):
x = numpy.reshape(pattern, (1, len(pattern), 1))
x = x / float(n_vocab)
prediction = model.predict(x, verbose=0)
index = numpy.argmax(prediction)
result = int_to_char[index]
seq_in = [int_to_char[value] for value in pattern]
sys.stdout.write(result)
pattern.append(index)
pattern = pattern[1:len(pattern)]

4.4.3. Analizando resultados

Debido a la carga computacional, las pruebas de este apartado han sido llevadas a cabo
en una máquina de tipo g2.2xlarge de Amazon Web Services, una instancia optimizada para
aplicaciones con uso intensivo de gráficos. Gracias a esta instancia, que destaca por su gran GPU,
se consiguieron llevar a cabo las pruebas en un tiempo relativamente aceptable, consiguiendo
aproximadamente que cada uno de los cincuenta ciclos se llevase a cabo en diez minutos.
Una vez que se ha entrenado la red, al ejecutar el código que genera textos con los pesos ya
aprendidos, se genera el siguiente texto:

38 CAPÍTULO 4. KERAS: DISEÑO Y DESARROLLO DE MODELOS


Herramientas modernas en redes neuronales: la librerı́a keras

Caracteres totales: 121492


Vocabulario total: 46
Patrones totales: 121392
Seed:
decisiones desesperadas. en tales momentos dirigia sus ojos lo mas agudamente posible hacia
la vent "
ana y la hermana se habia acierto la puerta del cuarto de estar hacia el senor de estar con
la habitacion de gregorio. el padre se despar de la cabeza con la mano derecha
comenzarse a la madre que estaba en la cama en la habitacion de gregorio.

Como podemos ver, los resultados no son perfectos. Hay palabras que sı́ han sido generadas
correctamente (como hermana), y otras que sin embargo, no tienen mucho sentido en el texto
(como despar). Aunque el texto en su conjunto no tenga mucho sentido, podemos apreciar varios
detalles:

El primero, es que nuestra red ha sido capaz de predecir la palabra que se ha quedado a
la mitad en la semilla (ventana).
En segundo lugar, vemos como nuestra red utiliza la mayor parte de las veces las palabras
que más se repiten en el libro. Para los que no lo hayan leı́do, los personajes principales
son Gregorio, su padre, su madre, y su hermana, y la mayor parte de la historia transcurre
en la habitación de Gregorio. Esto demuestra que la red ha aprendido de nuestro texto
para poder generar el suyo propio. Si se quisiese un vocabulario más extenso, una buena
opción serı́a nutrir a nuestra red con más textos e historias.
Por último, pese a que el texto en su conjunto no tenga mucho sentido, podemos apreciar
como nuestra red parece que ha aprendido reglas gramaticales del español. Por ejemplo,
construye las frases con la estructura sujeto, verbo y predicado, y es capaz de utilizar
pronombres, adverbios... para dar más sentido a las frases.

No obstante, existen una serie de técnicas que ayudarı́an a mejorar nuestro nuevo texto, pero
que en este ejemplo no han sido aplicadas. Algunas de ellas son:

Predecir menos caracteres de salida por semilla.


Borrar todos los signos de puntuación del texto y por tanto, del vocabulario del modelo.
Añadir más capas al modelo.
Reducir el tamaño de lote (el más eficiente serı́a de 1, pero el modelo tardarı́a demasiado
en entrenarse)

CAPÍTULO 4. KERAS: DISEÑO Y DESARROLLO DE MODELOS 39


Conclusiones y lı́neas futuras
5
Como se ha podido comprobar, el uso de las redes neuronales en ámbitos comunes es ya
una realidad. Este TFG empezó describiendo varias ideas que parecı́an más bien sacadas de una
pelı́cula de ciencia ficción, pero como se ha podido observar, estamos muy cerca de conseguirlas.
Afirmar que las redes neuronales son el futuro ya no tienen tanto sentido como hace unos años.
Ya no son el futuro, sino el presente. A dı́a de hoy, el mundo de las redes neuronales es una
de las mayores lı́neas de investigación tanto en informática como en el estudio y recreación del
cerebro humano, y merece la pena entender su funcionamiento básico. Si seguimos rompiendo
barreras en cuanto a capacidad de computación se refiere, y adaptamos las nuevas tecnologı́as
de procesamiento en GPU y CPU a nuestras redes neuronales, seremos capaces de llegar a
resultados hasta hace unos años inimaginables.
En cuanto a los objetivos de este Trabajo de Fin de Grado se han cumplido todos ellos.
Primero, se llevó a cabo un primer acercamiento al mundo de las redes neuronales, describien-
do su funcionamiento, arquitectura, y caracterı́sticas básicas. Después, se presentó Keras, una
librerı́a Python que se ejecuta sobre Tensorflow o Theano (dos de los backend más conocidos de
redes neuronales) y que facilita mucho la programación de los modelos de redes. Por último, me-
diante cuatro ejemplos, se aplicaron todos los conocimientos descritos en este documento para
demostrar la facilidad que existe hoy en dı́a para programar cualquier tipo de red neuronal.
Siguiendo la lı́nea de investigación, los siguientes pasos podrı́an ser aplicar las técnicas estu-
diadas y descritas en este documento para resolver problemas más complejos. Podrı́amos adaptar
la red neuronal convolucional utilizada para resolver el problema del MNIST para resolver pro-
blemas más enrevesados como por ejemplo, la lectura de documentos completos escritos a mano.
Si ampliamos el rango de clasificación de números a caracteres alfanúmericos, no estarı́amos tan
lejos de conseguirlo. O por ejemplo, podrı́amos adaptar la red LSTM que genera frases y textos,
para que generase historias completas. Para conseguir buenos resultados, necesitarı́amos tanto
ordenadores más potentes computacionalmente hablando, como una mayor cantidad de datos
de entrenamiento. Y como podemos intuir, estos requisitos ya están disponibles para cualquiera
que los necesite.

40
Glosario de acrónimos

FNN: Feed-forward Neural Network

LSTM: Long Short-Term Memory

RNN: Recurrent Neural Network

41
Bibliografı́a

[1] Edgar Nelson Sánchez Camperos, Alma Yolanda Alanı́s Garcı́a. Redes neuronales: concep-
tos fundamentales y aplicaciones a control automático. Pearson Educación, 2006, 2006.

[2] Laurene Fausett, editor. Fundamentals of Neural Networks: Architectures, Algorithms, and
Applications. Prentice-Hall, Inc., Upper Saddle River, NJ, USA, 1994.

[3] Ines M. Galvan Leon Pedro Isasi Viñuela. Redes neuronales artificiales Un enfoque práctico.
Pearson, 2004.

[4] David Beazley and Brian K. Jones. Python Cookbook. O’Reilly Media, Inc., 2013.

[5] Keras Documentation. https://keras.io/.

[6] François Chollet. Keras github. https://github.com/fchollet/keras, 2015.

[7] Michela Paganini. An Introduction to Deep Learning with Keras. 2nd Developers@CERN
Forum. May 2016.

[8] Dan Van Boxel. Keras Playlist. https://www.youtube.com/playlist?list=


PLFxrZqbLojdKuK7Lm6uamegEFGW2wki6P.

[9] Tensorflow. https://www.tensorflow.org/.

[10] Documentación Scikit-Learn. http://scikit-learn.org/stable/


documentation.html.

[11] F. Pedregosa, G. Varoquaux, A. Gramfort, V. Michel, B. Thirion, O. Grisel, M. Blondel,


P. Prettenhofer, R. Weiss, V. Dubourg, J. Vanderplas, A. Passos, D. Cournapeau, M. Bru-
cher, M. Perrot, and E. Duchesnay. Scikit-learn: Machine learning in Python. Journal of
Machine Learning Research, 12:2825–2830, 2011.

[12] Jason Brownlee. Deep Learning with Python. 1 edition, 2016.

[13] Diederik P. Kingma and Jimmy Ba. Adam: A method for stochastic optimization. CoRR,
abs/1412.6980, 2014.

[14] Sebastian Ruder. An overview of gradient descent optimization algorithms. CoRR, ab-
s/1609.04747, 2016.

[15] Documentacion del dataset Diabetes. https://archive.ics.uci.edu/ml/


datasets/Diabetes.

42
Herramientas modernas en redes neuronales: la librerı́a keras

[16] Documentación del dataset Housing. https://archive.ics.uci.edu/ml/


datasets/Housing.

[17] The MNIST database of handwritten digits. http://yann.lecun.com/exdb/mnist/.

[18] Ilya Sutskever, James Martens, and Geoffrey E. Hinton. Generating text with recurrent
neural networks. In Proceedings of the 28th International Conference on Machine Learning,
ICML 2011, Bellevue, Washington, USA, June 28 - July 2, 2011, pages 1017–1024, 2011.

[19] Documentación de Amazon Elastic Compute Cloud (EC2). https://aws.amazon.com/


es/documentation/ec2/.

[20] Tung Duc Nguyen, Kazuki Mori, and Ruck Thawonmas. Image colorization using a deep
convolutional neural network. CoRR, abs/1604.07904, 2016.

[21] Andrew Owens, Phillip Isola, Josh H. McDermott, Antonio Torralba, Edward H. Adelson,
and William T. Freeman. Visually indicated sounds. In 2016 IEEE Conference on Compu-
ter Vision and Pattern Recognition, CVPR 2016, Las Vegas, NV, USA, June 27-30, 2016,
pages 2405–2413, 2016.

[22] Google Traductor. https://support.google.com/translate/answer/


6142483?hl=es.

[23] Live on Live. https://lifeonlive.es/.

[24] AlphaGo. https://hipertextual.com/2016/03/alphago.

CAPÍTULO 5. CONCLUSIONES Y LÍNEAS FUTURAS 43


Códigos fuente
A
Las ideas con las que han sido elaboradas los siguientes códigos han sido extraı́das de [12].

A.1. 4.1. Problema de diabetes - Regresión logı́stica


from keras.models import Sequential
from keras.layers import Dense
import numpy
# se elige una semilla aleatoria para reproducir el mismo ejemplo varias veces
numpy.random.seed(4)
# carga del dataset de diabetes en indios americanos
dataset = numpy.loadtxt("pima-indians-diabetes.csv", delimiter=",")
# se separa el dataset en X (entrada) e Y (salida)
X = dataset[:,0:8]
Y = dataset[:,8]
# creacion del modelo
model = Sequential()
model.add(Dense(12, input_dim=8, init=’normal’, activation=’relu’))
model.add(Dense(8, init=’normal’, activation=’relu’))
model.add(Dense(1, init=’normal’, activation=’sigmoid’))
# compilacion del modelo
model.compile(loss=’binary_crossentropy’, optimizer=’adam’, metrics=[’accuracy’])
# ajuste del modelo
model.fit(X, Y, nb_epoch=150, batch_size=10)
# evaluacion del modelo
eva = model.evaluate(X, Y)
print(" %s: %.2f % %" % (model.metrics_names[1], eva[1]*100))

# calculo de predicciones
predicciones = model.predict(X)
# redondeo de predicciones
rounded = [round(x) for x in predicciones]
print(rounded)

A.2. 4.2. Problema Boston Housing - Regresión lineal

A.2.1. Modelo estándar


import numpy
import pandas
from keras.models import Sequential
from keras.layers import Dense
from keras.wrappers.scikit_learn import KerasRegressor
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import KFold
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline

44
Herramientas modernas en redes neuronales: la librerı́a keras

# definicion del modelo


def baseline_model():
# creacion del modelo
model = Sequential()
model.add(Dense(13, input_dim=13, init=’normal’, activation=’relu’))
model.add(Dense(1, init=’normal’))
# compilacion del modelo
model.compile(loss=’mean_squared_error’, optimizer=’adam’)
return model

# carga del dataset de boston-housing


dataframe = pandas.read_csv("housing.csv", delim_whitespace=True, header=None)
dataset = dataframe.values
# se separa el dataset en las variables X (entradas) e Y (salida)
X = dataset[:,0:13]
Y = dataset[:,13]
# se elige una semilla aleatoria para reproducir el mismo ejemplo varias veces
numpy.random.seed(4)
# evaluacion del modelo
estimator = KerasRegressor(build_fn=baseline_model, nb_epoch=100, batch_size=5, verbose=0)

kfold = KFold(n_splits=10, random_state=4)


results = cross_val_score(estimator, X, Y, cv=kfold)
print("Resultados: %.2f ( %.2f) MSE" % (results.mean(), results.std()))

A.2.2. Modelo con datos de entrada normalizados


import numpy
import pandas
from keras.models import Sequential
from keras.layers import Dense
from keras.wrappers.scikit_learn import KerasRegressor
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import KFold
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline

# definicion del modelo de red neuronal


def baseline_model():
# ócreacin del modelo
model = Sequential()
model.add(Dense(13, input_dim=13, init=’normal’, activation=’relu’))
model.add(Dense(1, init=’normal’))
# compilacion del modelo
model.compile(loss=’mean_squared_error’, optimizer=’adam’)
return model

# carga del dataset


dataframe = pandas.read_csv("housing.csv", delim_whitespace=True, header=None)
dataset = dataframe.values
# se separa el dataset en las variables X (entradas) e Y (salida)
X = dataset[:,0:13]
Y = dataset[:,13]
# se elige una semilla aleatoria para reproducir el mismo ejemplo varias veces
numpy.random.seed(4)
# se úevala el modelo con el dataset normalizado
estimators = []
estimators.append((’standardize’, StandardScaler()))
estimators.append((’mlp’, KerasRegressor(build_fn=baseline_model, nb_epoch=50, batch_size=5,
verbose=0)))
pipeline = Pipeline(estimators)

kfold = KFold(n_splits=10, random_state=4)


results = cross_val_score(pipeline, X, Y, cv=kfold)
print("Estandarizado: %.2f ( %.2f) MSE" % (results.mean(), results.std()))

A.2.3. Modelo más profundo


import numpy
import pandas

APÉNDICE A. CÓDIGOS FUENTE 45


Herramientas modernas en redes neuronales: la librerı́a keras

from keras.models import Sequential


from keras.layers import Dense
from keras.wrappers.scikit_learn import KerasRegressor
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import KFold
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline

# definicion del modelo de red neuronal mas profundo


def larger_model():
# creacion del modelo
model = Sequential()
model.add(Dense(13, input_dim=13, init=’normal’, activation=’relu’))
model.add(Dense(6, init=’normal’, activation=’relu’))
model.add(Dense(1, init=’normal’))
# compilacion del modelo
model.compile(loss=’mean_squared_error’, optimizer=’adam’)
return model

# carga del dataset


dataframe = pandas.read_csv("housing.csv", delim_whitespace=True, header=None)
dataset = dataframe.values
# se separa el dataset en las variables X (entradas) e Y (salida)
X = dataset[:,0:13]
Y = dataset[:,13]
# se elige una semilla aleatoria para reproducir el mismo ejemplo varias veces
numpy.random.seed(4)

estimators = []
estimators.append((’standardize’, StandardScaler()))
estimators.append((’mlp’, KerasRegressor(build_fn=larger_model, nb_epoch=50, batch_size=5,
verbose=0)))
pipeline = Pipeline(estimators)

kfold = KFold(n_splits=10, random_state=4)


results = cross_val_score(pipeline, X, Y, cv=kfold)
print("Resultados: %.2f ( %.2f) MSE" % (results.mean(), results.std()))

A.2.4. Modelo más ancho

import numpy
import pandas
from keras.models import Sequential
from keras.layers import Dense
from keras.wrappers.scikit_learn import KerasRegressor
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import KFold
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline

# definicion del modelo de red neuronal mas ancho


def wider_model():
# creacion del modelo
model = Sequential()
model.add(Dense(20, input_dim=13, init=’normal’, activation=’relu’))
model.add(Dense(1, init=’normal’))
# compilacion del modelo
model.compile(loss=’mean_squared_error’, optimizer=’adam’)
return model

# carga del dataset


dataframe = pandas.read_csv("housing.csv", delim_whitespace=True, header=None)
dataset = dataframe.values
# se separa el dataset en las variables X (entradas) e Y (salida)
X = dataset[:,0:13]
Y = dataset[:,13]
# se elige una semilla aleatoria para reproducir el mismo ejemplo varias veces
numpy.random.seed(4)

estimators = []
estimators.append((’standardize’, StandardScaler()))

46 APÉNDICE A. CÓDIGOS FUENTE


Herramientas modernas en redes neuronales: la librerı́a keras

estimators.append((’mlp’, KerasRegressor(build_fn=wider_model, nb_epoch=100, batch_size=5,


verbose=0)))
pipeline = Pipeline(estimators)

kfold = KFold(n_splits=10, random_state=4)


results = cross_val_score(pipeline, X, Y, cv=kfold)
print("Resultados: %.2f ( %.2f) MSE" % (results.mean(), results.std()))

A.3. 4.3 MNIST - Perceptrón multicapa vs Red convolucional

A.3.1. Perceptrón multicapa


import numpy
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.utils import np_utils

# definicion del modelo de red neuronal


def baseline_model():
# creacion del modelo
model = Sequential()
model.add(Dense(num_pixels, input_dim=num_pixels, init=’normal’, activation=’relu’))
model.add(Dense(num_classes, init=’normal’, activation=’softmax’))
# compilacion del modelo
model.compile(loss=’categorical_crossentropy’, optimizer=’adam’, metrics=[’accuracy’])
return model

# se elige una semilla aleatoria para reproducir el mismo ejemplo varias veces
numpy.random.seed(4)

# carga del dataset


(X_train, y_train), (X_test, y_test) = mnist.load_data()

# conversion de las imagenes a un vector para ser tratado por la red neuronal
num_pixels = X_train.shape[1] * X_train.shape[2]
X_train = X_train.reshape(X_train.shape[0], num_pixels).astype(’float32’)
X_test = X_test.reshape(X_test.shape[0], num_pixels).astype(’float32’)

# ónormalizacin de los valores de entrada de 0-255 a 0-1


X_train = X_train / 255
X_test = X_test / 255

# codificacion de la variable de salida


y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)
num_classes = y_test.shape[1]

model = baseline_model()
# ajuste del modelo
model.fit(X_train, y_train, validation_data=(X_test, y_test), nb_epoch=10, batch_size=200,
verbose=2)
# evaluacion del modelo
scores = model.evaluate(X_test, y_test, verbose=0)
print("Baseline Error: %.2f % %" % (100-scores[1]*100))

A.3.2. Red convolucional


import numpy
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.layers import Flatten
from keras.layers.convolutional import Convolution2D
from keras.layers.convolutional import MaxPooling2D
from keras.utils import np_utils
from keras import backend as K
K.set_image_dim_ordering(’th’)

APÉNDICE A. CÓDIGOS FUENTE 47


Herramientas modernas en redes neuronales: la librerı́a keras

def baseline_model():
# creacion del modelo
model = Sequential()
model.add(Convolution2D(32, 5, 5, border_mode=’valid’, input_shape=(1, 28, 28),
activation=’relu’))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.2))
model.add(Flatten())
model.add(Dense(128, activation=’relu’))
model.add(Dense(num_classes, activation=’softmax’))
# compilacion del modelo
model.compile(loss=’categorical_crossentropy’, optimizer=’adam’, metrics=[’accuracy’])
return model

# se elige una semilla aleatoria para reproducir el mismo ejemplo varias veces
numpy.random.seed(4)

# carga del dataset


(X_train, y_train), (X_test, y_test) = mnist.load_data()
# reshape to be [samples][pixels][width][height]
X_train = X_train.reshape(X_train.shape[0], 1, 28, 28).astype(’float32’)
X_test = X_test.reshape(X_test.shape[0], 1, 28, 28).astype(’float32’)

# ónormalizacin de los valores de entrada de 0-255 a 0-1


X_train = X_train / 255
X_test = X_test / 255
# codificacion de la variable de salida
y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)
num_classes = y_test.shape[1]

model = baseline_model()
# ajuste del modelo
model.fit(X_train, y_train, validation_data=(X_test, y_test), nb_epoch=10, batch_size=200,
verbose=2)
# evaluacion del modelo
scores = model.evaluate(X_test, y_test, verbose=0)
print("Baseline Error: %.2f % %" % (100-scores[1]*100))

A.4. 4.4 Generación de textos - Red LSTM

A.4.1. Entrenamiento de la red


import numpy
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.layers import LSTM
from keras.callbacks import ModelCheckpoint
from keras.utils import np_utils
# se carga el texto y se convierten todos los caracteres a úminscula
filename = "kafka.txt"
raw_text = open(filename).read()
raw_text = raw_text.lower()
# creacion del mapeo caracter-entero
chars = sorted(list(set(raw_text)))
char_to_int = dict((c, i) for i, c in enumerate(chars))
# resumen del dataset de entrada
n_chars = len(raw_text)
n_vocab = len(chars)
print "Total Characters: ", n_chars
print "Total Vocab: ", n_vocab
# se prepara el dataset en pares codificados como enteros
seq_length = 100
dataX = []
dataY = []
for i in range(0, n_chars - seq_length, 1):
seq_in = raw_text[i:i + seq_length]
seq_out = raw_text[i + seq_length]
dataX.append([char_to_int[char] for char in seq_in])

48 APÉNDICE A. CÓDIGOS FUENTE


Herramientas modernas en redes neuronales: la librerı́a keras

dataY.append(char_to_int[seq_out])
n_patterns = len(dataX)
print "Total Patterns: ", n_patterns
# se formatea la entrada a un array de forma [muestra, intervalo de tiempo, caracteristicas]
X = numpy.reshape(dataX, (n_patterns, seq_length, 1))
# ónormalizacin de los datos de entrada
X = X / float(n_vocab)
# codificacion de la variable de salida
y = np_utils.to_categorical(dataY)
# definicion del modelo de red neuronal LSTM
model = Sequential()
model.add(LSTM(256, input_shape=(X.shape[1], X.shape[2]), return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(256))
model.add(Dropout(0.2))
model.add(Dense(y.shape[1], activation=’softmax’))
model.compile(loss=’categorical_crossentropy’, optimizer=’adam’)
# definicion de los checkpoint (punto de guardado de pesos)
filepath="weights-improvement-{epoch:02d}-{loss:.4f}-bigger.hdf5"
checkpoint = ModelCheckpoint(filepath, monitor=’loss’, verbose=1, save_best_only=True, mode=’
min’)
callbacks_list = [checkpoint]
# ajuste del modelo
model.fit(X, y, nb_epoch=50, batch_size=64, callbacks=callbacks_list)

A.4.2. Generacion de texto

import sys
import numpy
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.layers import LSTM
from keras.callbacks import ModelCheckpoint
from keras.utils import np_utils
# se carga el texto y se convierten todos los caracteres a úminscula
filename = "kafka.txt"
raw_text = open(filename).read()
raw_text = raw_text.lower()
# creacion del mapeo caracter-entero, y su inverso
chars = sorted(list(set(raw_text)))
char_to_int = dict((c, i) for i, c in enumerate(chars))
int_to_char = dict((i, c) for i, c in enumerate(chars))
# resumen del dataset de entrada
n_chars = len(raw_text)
n_vocab = len(chars)
print "Total Characters: ", n_chars
print "Total Vocab: ", n_vocab
# se prepara el dataset en pares codificados como enteros
seq_length = 100
dataX = []
dataY = []
for i in range(0, n_chars - seq_length, 1):
seq_in = raw_text[i:i + seq_length]
seq_out = raw_text[i + seq_length]
dataX.append([char_to_int[char] for char in seq_in])
dataY.append(char_to_int[seq_out])
n_patterns = len(dataX)
print "Total Patterns: ", n_patterns
# reshape X to be [samples, time steps, features]
X = numpy.reshape(dataX, (n_patterns, seq_length, 1))
# ónormalizacin de los datos de entrada
X = X / float(n_vocab)
# codificacion de la variable de salida
y = np_utils.to_categorical(dataY)
# definicion del modelo de red neuronal LSTM
model = Sequential()
model.add(LSTM(256, input_shape=(X.shape[1], X.shape[2]), return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(256))
model.add(Dropout(0.2))
model.add(Dense(y.shape[1], activation=’softmax’))

APÉNDICE A. CÓDIGOS FUENTE 49


Herramientas modernas en redes neuronales: la librerı́a keras

# carga de los pesos de la red a partir de los checkpoints generados previamente


filename = "weights-improvement-49-1.1691-bigger.hdf5"
model.load_weights(filename)
model.compile(loss=’categorical_crossentropy’, optimizer=’adam’)
# se elige una semilla aleatoria para reproducir el mismo ejemplo varias veces
start = numpy.random.randint(0, len(dataX)-1)
pattern = dataX[start]
print "Seed:"
print "\"", ’’.join([int_to_char[value] for value in pattern]), "\""
# generacion de caracteres
for i in range(300):
x = numpy.reshape(pattern, (1, len(pattern), 1))
x = x / float(n_vocab)
prediction = model.predict(x, verbose=0)
index = numpy.argmax(prediction)
result = int_to_char[index]
seq_in = [int_to_char[value] for value in pattern]
sys.stdout.write(result)
pattern.append(index)
pattern = pattern[1:len(pattern)]

50 APÉNDICE A. CÓDIGOS FUENTE

También podría gustarte