KERAS
KERAS
KERAS
HERRAMIENTAS MODERNAS
EN REDES NEURONALES: LA
LIBRERÍA KERAS
Enero 2017
Herramientas modernas en redes neuronales: la librerı́a keras
HERRAMIENTAS MODERNAS
EN REDES NEURONALES: LA
LIBRERÍA KERAS
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
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
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
vi
Herramientas modernas en redes neuronales: la librerı́a keras
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
viii
Introducción
1
1.1. Motivacion
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
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:
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.
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
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
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:
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.
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.
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.
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.
Efecto excitador o inhibidor de una conexión ⇐⇒ Signo del peso de una conexió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:
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
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.
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
0 x<0
f (x) = (2.7) Figura 2.9: Función rectificadora
x x≥0
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
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.
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.
Aprendizaje
1. Inicialización de variables
2. Bucle de iteraciones:
3. Salida
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.
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).
2.3.1. Propagación
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.
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.
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.
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.
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.
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.
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
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.
La reducción del tamaño provoca una menor sobrecarga de cálculo en las próximas capas
de la red.
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.
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.
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
problema. Su principal caracterı́stica es que son redes con bucles, que permiten que la informa-
ción persista.
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:
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.
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.
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.
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-
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.
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:
3.2. Instalación
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.
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)
3.4. Capas
A la hora de diseñar las capas de nuestra red neuronal, tenemos una serie de funciones
disponibles:
Activation:Se aplica una función de activación a una salida. Las principales funciones que
nos ofrece Keras son:
• softsign
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.
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.
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 :
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:
3.7.1. Regularizadores
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.
History(): Callback aplicado en cada modelo Keras que almacena eventos en un objeto de
tipo History.
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).
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:
3.12. Visualización
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:
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.
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
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]
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’))
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’])
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)
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))
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)
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:
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.
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).
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:
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
Aunque ya hayamos conseguido entrenar nuestra red para obtener resultados, existen muchas
maneras de mejorar nuestro modelo. En este ejemplo, veremos tres:
Normalizando el dataset
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()))
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
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:
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.
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.
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:
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).
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 %
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 %.
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.
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))
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’)
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.
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’)
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)]
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:
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:
40
Glosario de acrónimos
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.
[7] Michela Paganini. An Introduction to Deep Learning with Keras. 2nd Developers@CERN
Forum. May 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.
42
Herramientas modernas en redes neuronales: la librerı́a keras
[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.
[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.
# calculo de predicciones
predicciones = model.predict(X)
# redondeo de predicciones
rounded = [round(x) for x in predicciones]
print(rounded)
44
Herramientas modernas en redes neuronales: la librerı́a keras
estimators = []
estimators.append((’standardize’, StandardScaler()))
estimators.append((’mlp’, KerasRegressor(build_fn=larger_model, nb_epoch=50, batch_size=5,
verbose=0)))
pipeline = Pipeline(estimators)
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
estimators = []
estimators.append((’standardize’, StandardScaler()))
# se elige una semilla aleatoria para reproducir el mismo ejemplo varias veces
numpy.random.seed(4)
# 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’)
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))
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)
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))
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)
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’))