máster universitario en ingeniería de...
TRANSCRIPT
Equation Chapter 1 Section 1
Trabajo Fin de Máster
Máster Universitario en Ingeniería de
Telecomunicación
Reconocimiento de Texto Manuscrito con Deep
Learning
Autor: José Carlos Aradillas Jaramillo
Tutor: Juan José Murillo Fuentes
Dep. Teoría de la Señal y Comunicaciones
Escuela Técnica Superior de Ingeniería
Universidad de Sevilla
Sevilla, 2017
iii
Trabajo Fin de Máster
Máster Universitario en Ingeniería de Telecomunicación
Reconocimiento de Texto Manuscrito con Deep
Learning
Autor:
José Carlos Aradillas Jaramillo
Tutor:
Juan José Murillo Fuentes
Prof. Catedrático de Universidad
Dep. de Teoría de la Señal y Comunicaciones
Escuela Técnica Superior de Ingeniería
Universidad de Sevilla
Sevilla, 2017
v
Trabajo Fin de Máster: Reconocimiento de Texto Manuscrito con Deep Learning
Autor: José Carlos Aradillas Jaramillo
Tutor: Juan José Murillo Fuentes
El tribunal nombrado para juzgar el Proyecto arriba indicado, compuesto por los siguientes miembros:
Presidente:
Vocales:
Secretario:
Acuerdan otorgarle la calificación de:
Sevilla, 2017
El Secretario del Tribunal
vii
A mi familia
A mis amigos
A mis profesores
ix
Agradecimientos
La realización de este trabajo implica la finalización de mi etapa como estudiante que comenzó hace más de 20
años en Segura de León, en el colegio Ntra. Sra. de Guadalupe, continuando por el I.E.S Ildefonso Serrano y
culminando con los últimos años en la Universidad de Sevilla. Agradecer en primer lugar a todos los maestros
y profesores que he tenido en todas estas etapas implicados en mi formación personal, académica y profesional,
cada uno de ellos ha puesto su granito de arena para conseguir que llegue a donde estoy.
Agradecer a los profesores y compañeros del Departamento de Teoría de la Señal y Comunicaciones que han
tenido una mayor influencia en los últimos años de grado y máster, en especial el tutor de este trabajo Juan José
Murillo por su confianza en mí, su ayuda y por permitirme formar parte sus proyectos. También agradecer a
Pablo Martínez Olmos por sus aportaciones a este trabajo.
En estas etapas también ha sido muy importante el apoyo de los compañeros que he ido conociendo a lo largo
de todo el recorrido y me han acompañado dentro y fuera de las aulas. Hay algunos que se merecen un
agradecimiento individual. Con estas líneas quiero dar las gracias a todos, sin vosotros esta vida no sería tan
interesante, emocionante y divertida.
Finalmente agradecer a mi familia por estar siempre ahí, en especial a mis padres José y Gregoria por su infinita
dedicación sin la que seguramente no habría conseguido nada de lo que tengo. A mi novia Ana por apoyarme
en lo que hago y haberme aguantado en todos los momentos difíciles sufridos a lo largo de los últimos años de
la carrera y la realización de este máster.
José Carlos Aradillas Jaramillo
Sevilla, 2017
xi
Resumen
El reconocimiento y transcripción de textos manuscritos es una tarea muy importante, entre otras cosas para el
mantenimiento del patrimonio histórico, ya que permite crear copias digitales de libros con muchos años de
antigüedad. Tradicionalmente, esta tarea ha sido realizada manualmente y esto conlleva una cantidad de tiempo
que impide la transcripción de bibliotecas completas en un periodo razonable.
Este proceso se puede automatizar con algoritmos de aprendizaje máquina dentro de los que se destacan los
algoritmos deep learning, basados en redes neuronales. La idea es que, a partir de imágenes escaneadas de las
páginas de los libros, un ordenador sea capaz de extraer el texto con el menor error de transcripción posible. Para
tener un sistema capaz de realizar la transcripción automática, es necesario un previo entrenamiento del mismo
a partir de textos ya transcritos manualmente o por algún otro procedimiento.
Hay muchos autores trabajando en este campo y en los últimos años se han propuesto diferentes esquemas para
realizar esta tarea; estos algoritmos van desde la automatización de la transcripción de cada carácter individual
con una previa segmentación y un procesado posterior, hasta la automatización de la transcripción de páginas
completas sin necesidad de realizar ningún tipo de procesado auxiliar. La tendencia actual es la de transcribir
tras una previa segmentación de las líneas o de las palabras del texto. El objetivo de este trabajo es abordar las
técnicas más utilizadas para realizar la transcripción, comenzando con una exposición teórica y concluyendo
con la aplicación sobre algunas bases de datos disponibles para la iniciación en estas técnicas.
xiii
Abstract
Offline handwriting recognition is a quite important task for the maintenance of historical heritage, since it
allows the creation of digital copies of books with many years of antiquity. This task has traditionally been done
manually, and entails an amount of time that prevents the transcription of complete libraries within a reasonable
time.
This process can be automated with machine learning algorithms, among which are the deep learning algorithms
based on neural networks. The idea is that, from scanned images of the pages of books, a computer could extract
the text with the smallest possible error. In order to have a system capable of performing automatic transcription
it is necessary to train it from texts that have been transcribed manually or by some other procedure.
There are many authors who work in this field and in the last few years different schemes have been proposed
to carry out this task, ranging from the automation of the transcription of each individual character with a
previous segmentation and post processing until the automation of the transcription of forms without the
necessity of performing any kind of auxiliary processing. The current trend is to transcribe line by line or word
by word. The aim of this work is to approach the most used techniques, beginning with a theoretical exposition
and concluding with the application on the public databases which are available for the initiation in these tasks.
Índice
Agradecimientos ix
Resumen xi
Abstract xiii
Índice xiv
Índice de Tablas xvi
Índice de Figuras xviii
1 Introducción 1
2 El problema de Clasificación Temporal 3 2.1 Análisis formal del problema de clasificación temporal 3 2.2 Función de error utilizada para el problema de clasificación temporal 4 2.3 Objetivo del trabajo 4
3 Redes Neuronales Artificiales 5 3.1 El perceptrón 5 3.2 Redes neuronales artificiales, el perceptrón multicapa. 6
3.2.1 Función de coste 8 3.3 Aplicaciones 2D. Redes neuronales convolucionales 8
3.3.1 Deep Learning con CNN 11 3.4 Dependencia temporal, redes neuronales recurrentes 12 3.5 Dependencia temporal no causal, RNN bidireccionales 13 3.6 Memoria a largo y corto plazo (LSTM) 14 3.7 Información contextual en 2D. Redes multidimensionales. 17
4 Sequence Labelling 23 4.1 Connectionist Temporal Classification 23
4.1.1 Transformación de la salida de la red en secuencias de etiquetas. 23 4.1.2 Construcción del clasificador 24
5 Software 27 5.1 TensorFlow 27 5.2 Implementación MDLSTM 33
6 Configuración de servidor con GPUs para deep learning 39 6.1 Características Hardware de la máquina 40 6.2 Configuración Software 40
6.2.1 Instalación del sistema operativo Ubuntu 16.04.2 LTS 40 6.2.2 Instalación de los Drivers Nvidia y librerías CUDA. 42 6.2.3 Instalación de las librerías cuDNN 46 6.2.4 Instalación de paquetes python necesarios para machine learining y deep learning 47 6.2.5 Gestión de los discos 48
6.3 Conexión remota 49 6.3.1 Instalación del servidor SSH: 49 6.3.2 Instalación de teamviewer 49 6.3.3 Instalación de x2go 49
xv
6.3.4 Configuraciones de seguridad 52 6.3.5 Resolución de la pantalla para escritorio remoto 52
7 Aplicación a Reconocimiento de Números 55 7.1 Modelo con perceptrón multicapa 55 7.2 Modelo con redes neuronales convolucionales 59 7.3 Modelo con MDLSTM 63
7.3.1 Estructura sin dividir los datos a la entrada en bloques de 2x2 píxeles y sin Dropout 64 7.3.2 Estructura dividiendo los datos a la entrada en bloques de 2x2 píxeles y sin Dropout 64 7.3.3 Estructura dividiendo los datos a la entrada en bloques de 2x2 píxeles y con probabilidad de Dropout de 0.5 64 7.3.4 Estructura dividiendo los datos a la entrada en bloques de 2x2 píxeles y con probabilidad de Dropout de 0.2 64
7.4 Comparativa 64
8 Aplicación a Reconocimiento de Palabras 65 8.1 Base de datos del IAM 65 8.2 Modelo con redes neuronales convolucionales 72 8.3 Modelo con BI-LSTM 73 8.4 Modelo con MDLSTM 75
9 Aplicación a Reconocimiento de Líneas 77 9.1 Modelo compuesto por 3 capas MDLSTM - convolucional 78 9.2 Modelo compuesto por 5 capas convolucional-LSTM 79
9.2.1 Análisis de la salida de la capa CTC 81 9.2.2 Análisis de la transcripción de un párrafo 81
9.3 Comparativa 84
10 Conclusiones y trabajo futuro 85
Referencias 87
Anexos 90 Anexo I: Consejos para deep learning 90
Glosario 91
ÍNDICE DE TABLAS
Tabla 7-1 Resultados sobre la base de datos MNIST 64
Tabla 9-1. Transcripción de la imagen de la Figura 9-6 mediante la red neuronal de la Sección 9.2 83
Tabla 9-2. Resultados de la evaluación de la transcripción de la Figura 9-6. 83
Tabla 9-3. Comparativa error redes neuronales aplicadas a reconocimiento de líneas. 84
xvii
ÍNDICE DE FIGURAS
Figura 1-1. Ejemplo de texto manuscrito y su transcripción. (Fuente IAM database). 1
Figura 2-1. Diferencia entre clasificación temporal y clasificación de caracteres individuales. 3
Figura 3-1. La neurona (Fuente [10]) 5
Figura 3-2. Esquema del perceptrón (Fuente Wikipedia) 6
Figura 3-3. Funciones de activación de un perceptrón 6
Figura 3-4. Esquema de una red neuronal sin bucles MLP. 7
Figura 3-5. Comparación entre neurona MLP y neurona CNN. 9
Figura 3-6. Aplicación de una neurona CNN a varios canales. 10
Figura 3-7. Funcionamiento de una capa convolucional completa. 11
Figura 3-8. Capa de pooling. 11
Figura 3-9. Estructura de una red con capas CNN, capas de pooling y MLP a la salida. 12
Figura 3-10. Ejemplo de red neuronal recurrente. 13
Figura 3-11. Ejemplo de red neuronal recurrente bidireccional. 14
Figura 3-12. Problema del desvanecimiento del gradiente. (Fuente [8]). 15
Figura 3-13. Estructura de una celda LSTM. (Fuente [8] modificado) 15
Figura 3-14. Computación 2D RNN. (Fuente [8] ) 18
Figura 3-15. Orden en la computación 2D RNN. (Fuente [8] ) 18
Figura 3-16. Píxeles influyentes en la activación de la salida en el pixel actual 19
Figura 3-17. Direcciones posibles para recorrer una imagen. (Fuente [8] ) 20
Figura 3-18. Esquema capa MDRNN 20
Figura 5-1. Logo de TensorFlow 28
Figura 5-2. Logo de NumPy 28
Figura 5-3. Estructura del grafo implementado en este ejemplo. (Fuente [18]) 30
Figura 5-4. Estructura del grafo con placeholders. (Fuente [18]) 31
Figura 5-5. Estructura del grafo en el problema de regresión lineal. 33
Figura 6-1. Comparación rendimiento GPU frente CPU. 39
Figura 6-2. Configuración de Rufus para la creación de un USB drive 41
xix
Figura 6-3. Detección correcta de las tarjetas Nvidia por parte del sistema operativo. 42
Figura 6-4. Búsqueda de controladores NVIDIA para Tesla P100 y SO Linux en la página del fabricante 42
Figura 6-5. Búsqueda de librerías CUDA, instalador tipo runfile(local) 43
Figura 6-6. Comprobación de versión de driver nvidia y librerías cuda instaladas 45
Figura 6-7. Comprobación de que las GPUs y las librerías pasan el test “deviceQuery” 45
Figura 6-8. Monitorización de las GPUs Nvidia. 46
Figura 6-9. Configuración RAID 1. (Fuente: Wikipedia) 48
Figura 6-10. Ventana de configuración de sesión en x2goclient 50
Figura 6-11. Solicitud de instalación XQuartz 51
Figura 6-12. Descarga XQuartz para Mac OS X 51
Figura 6-13. Generación de modeline para una resolución de 1720 x 1173 @ 60 Hz. 52
Figura 6-14. Fichero /usr/share/X11/xorg.conf.d/10-monitor.conf para una resolución 1920x1173. 53
Figura 7-1. Ejemplos base de datos MNIST. (Fuente [21]) 55
Figura 7-2. Red neuronal propuesta en este ejemplo. 56
Figura 7-3. Grafo creado para el entrenamiento MNIST con ANN. 57
Figura 7-4. Evaluación de la función de coste a lo largo del entrenamiento de una red ANN 58
Figura 7-5. Evaluación de la precisión del aprendizaje de una red ANN sobre el problema MNIST 58
Figura 7-6. Red neuronal convolucional propuesta en la Sección 7.2. 59
Figura 7-7. Grafo creado para MNIST con CNN. 61
Figura 7-8. Evaluación de la función de coste a lo largo del entrenamiento de una red CNN 62
Figura 7-9. Evaluación de la precisión del aprendizaje de una red CNN sobre el problema MNIST 62
Figura 7-10. Red neuronal convolucional propuesta en la Sección 7.3. 63
Figura 8-1. Ejemplo de página completa base de datos IAM. (Fuente [1]) 65
Figura 8-2. Ejemplo de línea extraída de una página de la base de datos del IAM. (Fuente [1]) 66
Figura 8-3. Ejemplo palabras extraídas base de datos IAM. (Fuente [1]) 66
Figura 8-4. Extracto del archivo words.txt base de datos IAM. (Fuente [1]) 67
Figura 8-5. Extracto de un archivo XML de la base de datos IAM. (Fuente [1]) 68
Figura 8-6. Red neuronal convolucional propuesta en la Sección 8.2. 73
Figura 8-7. Esquema propuesto en la Sección 8.3. 74
Figura 8-8. Tabla de resultados obtenidos por diversos autores. 74
Figura 8-9. Estructura propuesta en [4]. (Fuente [4]). 75
Figura 9-1. Ejemplo de fichero de configuración para rnn.py. 77
Figura 9-2. Esquema propuesto en la Sección 9.1. 78
Figura 9-3. Evolución del Character Error Rate (CER) durante el entrenamiento en el modelo 79
Figura 9-4. Esquema propuesto en la Sección 9.2. 80
Figura 9-5. Evolución del Character Error Rate (CER) durante el entrenamiento en el modelo 80
Figura 9-6. Salida de la capa CTC tras la transcripción de una línea del conjunto de test. 81
Figura 9-7. Imagen escaneada extraída de la base de datos IAM. 82
1
1 INTRODUCCIÓN
l “aprendizaje máquina” se sitúa como uno de los campos de investigación más abordados en los últimos
años debido a su amplia variedad de aplicaciones en diversos campos. El objetivo de cualquier problema
de aprendizaje máquina es entrenar a un algoritmo para que aprenda a resolver una tarea concreta,
intentando emular el aprendizaje que realiza una persona humana.
En este trabajo, se aborda el problema de reconocimiento de texto manuscrito que se puede clasificar dentro de
los problemas de etiquetado de secuencias. Se considera etiquetado de secuencias ya que el objetivo es etiquetar
cada uno de los caracteres manuscritos dentro de un texto asignando el valor que representa dentro del conjunto
de símbolos posibles (letras, números, signo de puntuación…) y concatenar después estas etiquetas para formar
el texto que se representa en la imagen. Un ejemplo de la tarea a realizar se puede observar en la Figura 1-1,
extraída de una de las bases de datos utilizadas en este trabajo, la base de datos IAM [1].
Figura 1-1. Ejemplo de texto manuscrito y su transcripción. (Fuente IAM database).
Los primeros algoritmos implementados para realizar tareas de reconocimiento de texto manuscrito comenzaban
con la segmentación de la imagen de partida a nivel de carácter; procediendo a una clasificación multiclase por
cada carácter y un procesado posterior para construir el texto a partir de los caracteres transcritos de forma
individual e independiente.
Actualmente, con el avance en las técnicas de aprendizaje máquina, se intenta automatizar este proceso de
segmentación previa y procesado posterior incluyéndolo todo dentro de las tareas de aprendizaje y realizándolo
a nivel de palabra o de línea de texto [2], [3], [4], [5], [6]. Gracias a esos avances se consigue aprovechar la
dependencia existente entre los diferentes caracteres en un texto, que es información que se pierde cuando se
clasifica a nivel de carácter.
Normalmente en la bibliografía se explican los algoritmos de forma teórica y no se mencionan las dificultades
computacionales que se puedan tener a la hora de implementarlos. En este documento se analiza de forma
resumida el software para la implementación de técnicas de aprendizaje máquina.
E
Introducción
2
2
La estructura de este trabajo se presenta de la siguiente forma: en el Capítulo 2, se explica con más detalle en
qué consiste el problema de aprendizaje máquina de clasificación temporal; en el Capítulo 3, se abordan
teóricamente los diferentes algoritmos de aprendizaje máquina relacionados con el problema de transcripción
de textos manuscritos a partir de redes neuronales, partiendo del perceptrón y terminando con redes neuronales
más evolucionadas que tienen en cuenta el contexto espacio-temporal de las secuencias. En el Capítulo 4 se
exponen técnicas aplicables a la salida de una red neuronal para el etiquetado de secuencias; en el Capítulo 5, se
analiza el software utilizado para la implementación de los algoritmos teóricos explicados en los Capítulos 3 y
4; en el Capítulo 6 se realiza la configuración de una máquina para deep learning; y finalmente en los Capítulos
7, 8 y 9, se muestran los experimentos realizados para la aplicación de los diferentes algoritmos para
reconocimiento de números, palabras y líneas respectivamente. Se finaliza el documento con una sección en la
que se define la línea que se desea seguir en el futuro con esta investigación y las conclusiones del trabajo.
3
2 EL PROBLEMA DE CLASIFICACIÓN
TEMPORAL
xisten dos problemas fundamentales de aprendizaje máquina: la regresión o estimación, y la clasificación
o detección [7]. Dentro del problema de clasificación se tienen la clasificación binaria y la clasificación
multiclase, a la que pertenece el problema abordado en este trabajo. Se trata un problema llamado
“Clasificación Temporal” dentro del subtipo “Etiquetado de secuencias” [8], el cual está presente en varias
situaciones del mundo real, como pueden ser el reconocimiento de texto manuscrito, el reconocimiento de voz
o el reconocimiento de gestos.
Cada uno de los problemas mencionados se podría subdividir en problemas más específicos de clasificación.
Por ejemplo, el reconocimiento de cada carácter individual dentro de la secuencia en el caso de reconocimiento
de textos manuscritos, el reconocimiento de cada fonema individual en el caso del reconocimiento de voz y en
el reconocimiento de cada gesto individual, en el caso del reconocimiento de gestos. Sin embargo, al subdividir
el problema, se está desaprovechando la relación temporal entre los diferentes caracteres, fonemas o gestos
individuales perdiendo una información que puede resultar muy importante para aprovechar la potencia de los
distintos algoritmos de aprendizaje máquina.
Figura 2-1. Diferencia entre clasificación temporal y clasificación de caracteres individuales.
2.1 Análisis formal del problema de clasificación temporal
Si procede ahora a analizar formalmente el problema de aprendizaje máquina consistente en clasificación
temporal como caso especial dentro de las tareas de etiquetado de secuencias.
E
El problema de Clasificación Temporal
4
4
Se parte [9] de un conjunto de entrenamiento 𝑆 procedente de una distribución 𝒟𝒳𝑥𝒵. El espacio de entrada
𝒳 = (ℝ𝑚)∗ se corresponde con el conjunto de todas las secuencias de vectores m-dimensionales, (siendo m el
número de características de cada elemento de la secuencia y “∗” la longitud de la secuencia. Cada secuencia
dentro del conjunto tiene una longitud concreta). El espacio de salida 𝒵 = 𝐿∗ se corresponde con conjunto de
todas las secuencias procedentes de un alfabeto finito 𝐿 de etiquetas (de igual forma que en el espacio de entrada,
“∗” denota que cada secuencia de dicho espacio tiene una longitud concreta). En este documento se toma cada
elemento de 𝐿∗ como una secuencia de etiquetas. Cada muestra dentro del conjunto de entrenamiento 𝑆 consiste
en un par de secuencias (x,z). La secuencia de etiquetas de salida 𝒛 = (𝑧1, 𝑧2, … , 𝑧𝑈) tiene como máximo la
misma longitud que la secuencia de entrada 𝒙 = (𝑥1, 𝑥2, … , 𝑥𝑇), es decir 𝑈 ≤ 𝑇. Por lo tanto, se tiene a la
entrada una secuencia de T vectores de características y a la salida una secuencia de U etiquetas, que a priori
están desalineadas.
Por lo tanto, el objetivo de este problema de aprendizaje máquina consiste en entrenar un clasificador temporal
ℎ ∶ 𝒳 → 𝒵, que minimice alguna función de error a la hora de clasificar nuevas secuencias.
En el caso de la transcripción de textos manuscritos, en una secuencia de salida 𝒛 = (𝑧1, 𝑧2, … , 𝑧𝑈), cada
elemento 𝑧𝑖 se corresponde con un carácter, por lo tanto 𝒛 es una palabra o frase, mientras que en una secuencia
de entrada 𝒙 = (𝑥1, 𝑥2, … , 𝑥𝑇), cada elemento 𝑥𝑖 se corresponde con un vector de características que pueden
ser por ejemplo el valor de los píxeles de una columna de la imagen y por lo tanto 𝒙 se correspondería con la
imagen.
2.2 Función de error utilizada para el problema de clasificación temporal
La función del error que se toma como referencia para evaluar los algoritmos implementados sobre el conjunto
de evaluación se define como label error rate (LER) y se calcula como la distancia media de Levenshtein editada
normalizada [9] entre la clasificación realizada y la secuencia de etiquetas reales a la salida del conjunto de
evaluación.
𝐿𝐸𝑅(ℎ, 𝑆′) =1
|𝑆′|∑
𝐸𝐷(ℎ(𝐱), 𝐳)
|𝐳|(𝐱,𝐳)∈𝑆′
Donde 𝐸𝐷(𝐚, 𝐛) es la distancia editada de Levenshtein entre dos secuencias 𝐚 y b, [9], es decir, el número
mínimo de inserciones, sustituciones y eliminaciones que hay que hacer en la secuencia a para que sea igual que
b.
En el caso que se aborda en este trabajo, que es el de transcripción de textos manuscritos, esta medida del error
permite comprobar y promediar el número de caracteres erróneos dentro de una palabra o frase, dependiendo
del problema.
2.3 Objetivo del trabajo
En este trabajo, se revisan las aproximaciones más relevantes que se han realizado en los últimos años para
abordar este problema de clasificación temporal y su aplicación al caso del reconocimiento de textos
manuscritos. En segundo lugar, se realiza la prueba de varios algoritmos actuales sobre bases de datos bien
conocidas para comprobar la efectividad de los mismos. El objetivo final del mismo es la implementación de un
marco de trabajo donde se incluyan los algoritmos actuales, permitiendo la inclusión de nuevos algoritmos con
el objetivo de poder resolver otros problemas que se propongan. Este trabajo se encuentra dentro de un proyecto
de mayor dimensión que consiste en la resolución de un problema real de transcripción de textos manuscritos
antiguos del Archivo General de Indias.
5
3 REDES NEURONALES ARTIFICIALES
n este capítulo se realiza un análisis de los diferentes tipos de redes neuronales principales que se están
utilizando actualmente, partiendo del elemento más sencillo de una red neuronal y añadiendo complejidad
basándose en similitudes con el aprendizaje humano. Se expone en cada caso la utilidad que pueda tener
cada tipo de red neuronal y como se pueden utilizar para resolver problemas de reconocimiento de texto
manuscrito.
3.1 El perceptrón
En biología, el elemento básico de un cerebro humano es la neurona, que es una célula caracterizada por tener
una serie de elementos de entrada llamados dendritas y una salida llamada axón. Las dendritas reciben señales
eléctricas de otras neuronas que llegan al cuerpo de la misma, que activan una función llamada sinapsis la cual
provoca una señal eléctrica en el axón [7]. Normalmente el axón de una neurona está conectado a la dendrita de
otra, y la conexión de múltiples neuronas de esta forma forman estructuras complejas como puede ser el cerebro
humano. El esquema de una neurona se puede ver en la Figura 3-1.
Figura 3-1. La neurona (Fuente [10])
El funcionamiento de una neurona se toma como modelo para diseñar el perceptrón, que es el elemento básico
de las redes neuronales artificiales. Un perceptrón es una estructura que tiene una serie de entradas a las que se
realiza una combinación lineal, al resultado de dicha combinación se le aplica un sesgo y posteriormente una
función de activación obteniendo una salida. Formalmente la salida del perceptrón se puede definir en función
de la entrada con la expresión:
𝑦 = 𝑓 (∑ 𝑤𝑖𝑥𝑖
𝑖
+ 𝑏) (3–1)
Donde 𝑥𝑖 son las entradas del perceptrón, 𝑤𝑖 son los pesos sinápticos que realizan la combinación lineal y 𝑏 es
el sesgo aplicado. Tanto los parámetros 𝑤𝑖 como 𝑏 son entrenables, es decir, son los parámetros que se desean
E
Redes Neuronales Artificiales
6
6
obtener tras el entrenamiento del sistema y una vez calculados el perceptrón entra en funcionamiento obteniendo
una salida para cada entrada que se proporcione.
Figura 3-2. Esquema del perceptrón (Fuente Wikipedia)
De la expresión del perceptrón sólo queda por comentar la función de activación 𝑓(𝑥), la cual proporciona la
salida final del mismo. Las funciones de activación más utilizadas son las siguientes:
Figura 3-3. Funciones de activación de un perceptrón. (Fuente
https://carchenilla.wordpress.com/2016/06/27/80/)
El perceptrón como tal no se puede aplicar a problemas complejos de clasificación multiclase, pero sí se puede
aplicar, por ejemplo, a algunos problemas de regresión lineal o de clasificación binaria.
3.2 Redes neuronales artificiales, el perceptrón multicapa.
Con el perceptrón se pueden resolver varios problemas de aprendizaje máquina, como pueden ser problemas
sencillos de regresión y problemas de clasificación binaria. Sin embargo, la estructura propuesta para el
perceptrón permite conectar varios de ellos entre sí para formar estructuras más complejas intentando simular
las conexiones biológicas que sufren las neuronas. Con este tipo de estructuras se pueden abordar problemas de
aprendizaje máquina más complejos, como problemas de clasificación multiclase [7]. Con este tipo de
estructuras aparece el concepto de deep learning.
Una red neuronal es una estructura formada por unidades de procesamiento, a los que en la literatura se les puede
llamar celdas, neuronas o nodos, unidas entre sí mediante conexiones pesadas. Cada uno de estos nodos recibe
una serie de entradas y mediante una función de activación proporciona una salida que se propaga a lo largo de
la red, como entradas a otros nodos o como salida final de la red en el caso de que se trate de nodos de salida.
7
7 Reconocimiento de Texto Manuscrito con Deep Learning
Dependiendo de si existen bucles en las conexiones entre las neuronas, se distinguen dos tipos de redes
neuronales, las redes neuronales sin bucles conocidas como FNN (Feedforward Neural Network en inglés) y las
redes neuronales con bucles conocidas como RNN (Recurrent/Recursive Neural Network en inglés) [7] [8]. En
esta sección se revisan las redes FNN que son las más utilizadas tradicionalmente para resolver problemas de
aprendizaje máquina y en la sección 3.4 se proponen las RNN como una de las soluciones a problemas de
clasificación temporal, donde realmente pueden mejorar a las FNN. En el resto de aplicaciones donde no hay
dependencia temporal entre las entradas, la existencia de bucles es innecesaria y por lo tanto las FNN funcionan
mejor que las RNN.
Si nos centramos en las FNN, estas redes se componen de una serie de capas de perceptrones que reciben como
entrada las salidas de los perceptrones de la capa anterior y sus salidas se conectan a las entradas de la capa
siguiente. Debido su estructura, estas redes también son conocidas como perceptrón multicapa (MLP). Todas
las redes neuronales tienen una capa de entrada, compuesta por un número de neuronas igual al número de
características de los datos de entrada, y una capa de salida compuesta por un número de neuronas igual al
número de salidas que se desea obtener, por ejemplo, en un problema de clasificación multiclase, normalmente
se diseña con un número de neuronas de salida igual al número de clases, y la clasificación se realiza tomando
la clase que reciba un valor mayor en la activación de su neurona en la capa de salida.
El esquema de una red neuronal de este tipo se puede ver en la Figura 3-4, donde se muestra una red neuronal
para resolver un problema multiclase con 3 clases y entradas de dimensión 3 (3 características), utilizando dos
capas ocultas de 5 y 4 neuronas respectivamente.
Figura 3-4. Esquema de una red neuronal sin bucles MLP.
Se ha demostrado [11] que una red neuronal MLP con una única capa oculta puede aproximar cualquier función
continua dentro del espacio de los datos de entrada con una precisión arbitraria. Por lo que se dice que el
perceptrón multicapa es un aproximador univesal de funciones.
La formulación para las distintas capas dentro de las redes neuronales sin bucles es la siguiente:
Si se tiene una capa de entrada con 𝐼 neuronas, y se configura una primera capa oculta con 𝐻1 neuronas, la salida
de cada neurona ℎ de esta primera capa es la siguiente:
𝑎ℎ = 𝑓 (∑ 𝑤𝑖ℎ𝑥𝑖
𝐼
𝑖=1
+ 𝑏ℎ)
(3–2)
Redes Neuronales Artificiales
8
8
donde,
𝑤𝑖ℎ se define como el peso de la conexión entre la neurona de entrada 𝑖 y la neurona de la primera capa
oculta ℎ.
𝑥𝑖 es el valor de la característica 𝑖 de los datos de entrada.
𝑏ℎ es el sesgo aplicado a la neurona ℎ de la primera capa oculta.
𝑓(𝑥) es la función de activación, que normalmente toma la forma de las indicadas en la Figura 3-3.
Una vez calculadas las salidas de las neuronas de la primera capa oculta, las salidas de las siguientes capas se
pueden calcular de la siguiente forma:
𝑎ℎ = 𝑓 ( ∑ 𝑤ℎ′ℎ𝑎ℎ′
𝐻𝑙−1
ℎ′=1
+ 𝑏ℎ)
(3–3)
donde,
𝑤ℎ′ℎ se define como el peso de la conexión entre la neurona de la capa oculta anterior ℎ′ y la neurona
ℎ de la capa actual.
𝑎ℎ′ es el valor de la salida de la función de activación de la neurona ℎ′ de la capa anterior
𝑏ℎ es el sesgo aplicado a la neurona ℎ de la capa actual.
𝑓(𝑥) es la función de activación, que normalmente toma la forma de las indicadas en la Figura 3-3.
Finalmente, la capa de salida se rige por la expresión.
�̂�𝑜 = 𝑓 (∑ 𝑤ℎ𝑜𝑎ℎ
𝐻𝑚
ℎ=1
+ 𝑏𝑜)
(3–4)
Donde los parámetros siguen la misma definición que los explicados para las demás capas, destacando que 𝐻𝑚
es el número de neuronas de la última capa oculta. En un problema de clasificación multiclase se puede entender
la salida de la una neurona 𝑜 como la probabilidad de que el dato a la entrada pertenezca a dicha clase.
3.2.1 Función de coste
Hay varias funciones de coste que se pueden aplicar a las redes neuronales que derivan de diferentes formas de
calcular el error de una clasificación o regresión. En [12] se enumeran las funciones objetivo más utilizadas para
cada aplicación. En el caso de la clasificación multiclase la más utilizada es la función objetivo conocida como
entropía cruzada. que sigue la siguiente expresión.
𝐿𝑂𝑆𝑆 = − ∑ ∑ �̂�𝑘 ln 𝑧𝑘 + (1 − 𝑧𝑘) ln �̂�𝑘
𝐾
𝑘=1(𝑥,𝑧)∈𝑆
(3–5)
Donde 𝐾 es el número de neuronas de salida, �̂�𝑘 es la salida estimada para la neurona 𝑘 y 𝑧𝑘 es la salida real
para la neurona 𝑘. 𝑆 es el conjunto compuesto por todas las muestras (𝑥, 𝑧).
3.3 Aplicaciones 2D. Redes neuronales convolucionales
Antes de analizar el caso de las redes neuronales con bucles, cuya aplicación se extiende a problemas en los que los datos de entrada tienen dependencia temporal, se va a exponer la extensión de las redes neuronales del tipo MLP a aplicaciones a imágenes.
9
9 Reconocimiento de Texto Manuscrito con Deep Learning
Cuando se trata de problemas donde los datos de entrada son imágenes que se desean clasificar, para aplicar una red neuronal del tipo MLP, en primer lugar hay que extraer una serie de características de la imagen realizando algún tipo de procesado, o simplemente pasar la imagen en crudo a la red neuronal, tomando como características el valor de los pixeles [12].
Las dos alternativas tienen una serie de inconvenientes, ya que en el caso de que se extraigan características de la imagen, se está realizando un procesado que extrae dichas características, pero hay posibilidad de perder mucha información aportada por la imagen que en principio el ser humano no ha sido capaz de detectar.
En el caso de que se tome la imagen en crudo tomando un valor por cada uno de los píxeles como característica no se está perdiendo ningún tipo de información más allá de la transformación de una imagen en 2D a un vector de características. El inconveniente de esta alternativa se debe a que, para imágenes muy grandes, de por ejemplo 500x500, píxeles se tienen un total de 250000 características a la entrada y si tras ello se configura una capa oculta de por ejemplo 300 neuronas, se tiene un total de 75.000.000 parámetros (pesos) a entrenar. Por lo que está sobredimensionando un problema sencillo.
Como solución para trabajar con imágenes una propuesta fue la de obtener las características de forma automática a partir de la imagen en 2D, teniendo en cuenta que el procesado que se aplica a la imagen suele consistir en filtros 2D con parámetros predefinidos como puede ser el caso de la detección de bordes. La solución consiste en aplicar filtros 2D con parámetros entrenables, dejando al sistema de aprendizaje libertad para detectar nuevas características en problemas concretos. Una vez que se han obtenido las características a partir de filtros de este tipo, se puede aplicar una red neuronal tipo MLP como las explicadas en la sección anterior para realizar la clasificación.
La reducción del número de parámetros se debe a que una neurona de una capa convolucional difiere de una neurona de una capa MLP en que la neurona de la capa MLP está conectada a todas las salidas de las neuronas de la capa anterior, utilizando un peso por cada conexión, mientras que una neurona de una capa convolucional está conectada a todas las salidas de neuronas de la capa anterior, pero se reutilizan los pesos de una sección de salidas (secciones de la imagen) a otras.
Figura 3-5. Comparación entre neurona MLP y neurona CNN.
Redes Neuronales Artificiales
10
10
En la Figura 3-5 se muestra la diferencia entre una neurona de una red neuronal tipo MLP, y una neurona de una red convolucional. En este ejemplo se tiene una imagen a la entrada de 5x5 píxeles, por lo que la neurona de ejemplo que se muestra tiene 25 pesos más el sesgo que entrenar, lo que hace un total de 26 parámetros por neurona que entrenar. En el caso de que se tuvieran por ejemplo 40 neuronas en la primera capa oculta se tendrían un total de 1040 parámetros que entrenar. En el caso de la capa convolucional, cada neurona tiene un total de 9 pesos (filtros 3x3) más el sesgo, lo que hacen un total de 10 parámetros por neurona. Si se tuvieran 40 neuronas ocultas se tendrían que entrenar un total de 400 pesos. Además, este tipo de neuronas está teniendo en cuenta la relación espacial de los píxeles de la imagen, al aplicar filtros locales en 2D. La reducción del número de parámetros a entrenar es más notable cuanto mayor es la imagen, si se tiene por ejemplo una imagen de 512x512 píxeles, la red neuronal de 40 neuronas propuesta tiene un total de 10.485.800 parámetros a entrenar, mientras una red convolucional de 40 neuronas seguiría teniendo el mismo número de parámetros que en el caso de que la imagen de entrada fuera de 5x5, es decir, 400. En las capas convolucionales el número de parámetros no depende de la dimensión de las imágenes de entrada.
Además, las capas convolucionales permiten utilizar filtros en 3D, para tener en cuenta imágenes a la entrada de varios canales, como pueden ser las imágenes RGB compuestas por 3 canales.
Figura 3-6. Aplicación de una neurona CNN a varios canales.
En la Figura 3-6 se puede ver cómo opera una neurona CNN con una imagen de 3 canales a la entrada. Utiliza un filtro de 2x3x3 que recorre la imagen obteniendo una salida por cada paso, por lo tanto, a la salida de una neurona convolucional se obtiene una nueva “imagen” o matriz de características en 2D del mismo tamaño que la imagen original.
Una vez que se ha definido como opera una neurona, hay que analizar cómo opera una capa CNN compuesta por varias neuronas.
Como se puede ver en la Figura 3-5 en las redes neuronales MLP, por cada neurona de una capa se obtiene un valor, y como se explicó en la sección anterior, si se tiene una capa con 𝐻 neuronas ocultas se obtienen 𝐻 valores que se corresponden con la entrada de la capa siguiente. En el caso de una neurona CNN, por cada neurona de la capa se obtiene una imagen del mismo tamaño que la imagen de entrada, por lo tanto, si se tienen 𝐻 neuronas, se obtienen a la salida 𝐻 imágenes del mismo tamaño que la imagen de entrada, por lo tanto los filtros utilizados en la capa siguiente deben tener esa profundidad.
11
11 Reconocimiento de Texto Manuscrito con Deep Learning
Figura 3-7. Funcionamiento de una capa convolucional completa.
Como se muestra en la Figura 3-7, a la salida de una capa convolucional se tienen tantas imágenes como neuronas tenga dicha capa convolucional.
3.3.1 Deep Learning con CNN
Una vez explicado cómo funciona una capa convolucional hay que analizar cómo incluirlas dentro de un sistema de deep learning. Deep learning se define como los algoritmos dentro del aprendizaje máquina que usan una serie de capas de redes neuronales en cascada, donde la salida de cada capa se corresponde con la entrada de la capa siguiente [13].
Ya se ha mostrado el funcionamiento de una CNN para obtener las características a la entrada de una red neuronal, pero a la salida de una capa convolucional se obtienen imágenes o matrices de valores del mismo tamaño que la imagen original. En algún punto es necesario reducir el tamaño de estas imágenes para poder aplicar una red neuronal tipo MLP evitando el problema que surge debido al elevado número de parámetros que tiene una capa MLP con una entrada de tales dimensiones.
Para solucionar este problema aparece la capa de agrupamiento o pooling, que consiste en reducir el tamaño de las matrices de salida de una capa convolucional agrupando los valores como se puede ver en la Figura 3-8, donde a una matriz de dimensión 6x6 se le realiza un agrupamiento 2x2, obteniendo una imagen de salida de 3x3.
Figura 3-8. Capa de pooling.
Redes Neuronales Artificiales
12
12
En el ejemplo mostrado en la Figura 3-8 se muestra un pooling del tipo max-pooling. En general hay dos tipos de agrupamiento o pooling.
Max-Pooling: se toma el valor mayor de cada agrupación mxn.
Mean-Pooling: se toma la media de los valores de cada agrupación mxn.
Por lo general, cuando se realiza pooling mxn se está reduciendo en 𝑚 la dimensión vertical de la imagen y en 𝑛 la dimensión horizontal.
Con la introducción de este nuevo tipo de capas se pueden configurar varias capas convolucionales en cascada introduciendo capas de pooling entre ellas, y finalmente cuando la imagen se haya reducido lo suficiente colocar al final una capa MLP para realizar a clasificación. En la Figura 3-9 se puede observar gráficamente la estructura de una red neuronal convolucional.
Figura 3-9. Estructura de una red con capas CNN, capas de pooling y MLP a la salida.
3.4 Dependencia temporal, redes neuronales recurrentes
Las redes neuronales explicadas hasta el momento no tenían bucles en las conexiones entre neuronas, es decir,
no hay ningún camino entre la salida de una neurona y la entrada de la misma [8]. Estos bucles no son necesarios
cuando se trata de problemas de aprendizaje máquina donde las muestras a la entrada son independientes unas
de otras, por lo que la salida de una red neuronal sólo depende de la entrada actual.
En el caso de los problemas de aprendizaje de secuencias, la adición de bucles en las redes neuronales aporta
importantes ventajas. Se han propuesto a lo largo de los años muchas formas de configurar los bucles, pero las
más extendidas son las llamadas redes neuronales recurrentes (RNN) en las que las salidas de una capa oculta
de una red neuronal se realimentan a la entrada de las neuronas de la propia capa.
Las redes neuronales recurrentes se diferencian de las redes neuronales sin bucles en la medida de que almacenan
información histórica de las muestras anteriores de la entrada que influyen en la salida actual de la red, cuando
las redes neuronales sin bucles sólo tienen en cuenta la muestra actual para tomar la decisión. Por lo tanto, se
puede decir que las redes neuronales recurrentes son redes con memoria.
En la Figura 3-10 se puede observar el esquema de una red neuronal recurrente, con 3 neuronas de entrada, dos
neuronas en la capa oculta y una neurona de salida. En este caso los bucles se aplican solamente a la capa oculta,
por lo que cada neurona de dicha capa tiene dos nuevas entradas correspondientes con la salida de dichas
13
13 Reconocimiento de Texto Manuscrito con Deep Learning
neuronas, además de las tres entradas provenientes de la capa de entrada.
Figura 3-10. Ejemplo de red neuronal recurrente.
La expresión que define la salida de estas neuronas al añadirle el término temporal es la siguiente:
𝑎ℎ𝑡 = 𝑓 (∑ 𝑤𝑖ℎ𝑥𝑖
𝑡
𝐼
𝑖=1
+ ∑ 𝑤ℎ′ℎ𝑎ℎ′𝑡−1
𝐻
ℎ′=1
+ 𝑏ℎ)
(3–6)
Donde, a parte de los términos ya conocidos se ha añadido:
𝑎ℎ𝑡 : ahora es importante el instante temporal en las salidas, se indica mediante el superíndice 𝑡
∑ 𝑤ℎ′ℎ𝑎ℎ′𝑡−1𝐻
ℎ′=1 : se añade un segundo término a la ecuación compuesta por la suma ponderada de las salidas
de todas las neuronas de la propia capa.
La ecuación se puede interpretar como que la salida de una neurona es la función de activación aplicada a la
suma ponderada de las entradas más las salidas de la propia capa en el instante anterior, al que se le suma un
sesgo como término independiente.
La expresión de la capa de salida no se ve afectada.
3.5 Dependencia temporal no causal, RNN bidireccionales
Con la inclusión de conexiones de realimentación en las neuronas de las capas ocultas se ha analizado cómo la
salida en un instante 𝑡 de una red neuronal puede ser afectada tanto por la entrada actual tanto como por las
salidas de los instantes anteriores [8]. Se puede extender esta idea a la influencia de los instantes futuros sobre
la salida actual ya que muchos problemas de clasificación de secuencias no son a tiempo real y, por lo tanto, se
tiene información de las muestras futuras.
Esto se puede conseguir fácilmente configurando capas ocultas en paralelo, y cada una de ellas se conecta a una
secuencia de entrada que se recorre de pasado a futuro en la primera capa oculta y de futuro a pasado en la
Redes Neuronales Artificiales
14
14
segunda, como se puede ver en la Figura 3-11.
Figura 3-11. Ejemplo de red neuronal recurrente bidireccional.
En la Figura 3-11 se muestra un ejemplo de red neuronal recurrente bidireccional BRNN, compuesta por una
neurona de entrada, dos neuronas ocultas, una por cada dirección y una neurona de salida. La figura representa
la evaluación de la red en dos instantes de tiempo, se observa como en el instante 𝑡 la neurona de la capa oculta
en la dirección backward tiene conectadas a la entrada tanto la entrada 𝑥𝑡 como la salida de la propia neurona
en el instante 𝑡 + 1 (naranja). La otra neurona pertenece a la capa oculta que recibe la secuencia de entrada en
la dirección forward, y en el instante 𝑡 recibe a la entrada el valor 𝑥𝑡 y la salida de la propia neurona en el instante
𝑡 − 1 (roja). Esta neurona no está representada en la imagen, sólo se representa la salida.
3.6 Memoria a largo y corto plazo (LSTM)
La idea de almacenamiento de un estado interno propuesto en las RNN tiene un inconveniente, y es que la
distancia temporal desde que se almacena la memoria está limitada, debido a que, en cada neurona recurrente,
la salida se define como la suma ponderada de su vector de entrada y el vector de salidas de la propia capa en el
instante anterior. Los pesos que ponderan el vector de entrada son los mismos de un dato a otro, pero la influencia
de la salida en un instante de tiempo lejano se atenúa debido a la cadena de pesos. Este problema se denomina
desvanecimiento del gradiente y limita la memoria que pueda tener una red RNN [8]. Este fenómeno se ve
ilustrado en la Figura 3-12, donde se muestra el peso que tiene la entrada en el instante 1 sobre el resto de
instantes con niveles de gris. Se observa que en el instante 6 ya no tiene influencia.
15
15 Reconocimiento de Texto Manuscrito con Deep Learning
Figura 3-12. Problema del desvanecimiento del gradiente. (Fuente [8]).
Se han propuesto varias alternativas para solucionar esto, de las cuales algunas evitan el uso de algoritmos que
dependan del gradiente, sin embargo, la solución más extendida es la de utilizar un tipo de neuronas llamadas
LSTM (Long Short Term Memory en inglés).
Una neurona LSTM se puede entender como una neurona RNN modificada, donde a partir de unas puertas se
controla la duración temporal de la memoria que se almacena en su interior en comparación con las nuevas
entradas. La estructura de una celda LSTM se puede ver en la Figura 3-13.
Figura 3-13. Estructura de una celda LSTM. (Fuente [8] modificado)
En la misma se observa la entrada en la parte inferior de la imagen y la salida en la parte superior. La entrada es
un vector formado por las salidas de las capas predecesoras y las salidas de la propia capa en el instante anterior.
Este vector de entrada se aplica tanto a los círculos que en la imagen se denominan NET INPUT, INPUT GATE,
FORGET GATE y OUTPUT GATE. El círculo azul NET INPUT se corresponde con los pesos entrenables a
la entrada, que multiplican al vector de entrada. Hay otra serie de pesos en INPUT GATE que multiplican
Redes Neuronales Artificiales
16
16
también al mismo vector de entradas, y cuya salida es un parámetro que controla la influencia de las nuevas
entradas en la neurona. La puerta FORGET GATE tiene unos pesos que controlan la memoria almacenada en
la celda, y la puerta OUTPUT GATE controla la salida. Las ecuaciones que rigen la neurona LSTM en la versión
que se ha utilizado en este trabajo son:
Para la puerta de entrada:
𝑎𝜄𝑡 = 𝑓 (∑ 𝑤𝑖𝜄𝑥𝑖
𝑡
𝐼
𝑖=1
+ ∑ 𝑤ℎ𝜄𝑎ℎ𝑡−1
𝐻
ℎ=1
+ ∑ 𝑤𝑐𝜄𝑠𝑐𝑡−1
𝐶
𝑐=1
+ 𝑏𝜄)
(3–7)
Para la puerta de olvido:
𝑎𝜙𝑡 = 𝑓 (∑ 𝑤𝑖𝜙𝑥𝑖
𝑡
𝐼
𝑖=1
+ ∑ 𝑤ℎ𝜙𝑎ℎ𝑡−1
𝐻
ℎ=1
+ ∑ 𝑤𝑐𝜙𝑠𝑐𝑡−1
𝐶
𝑐=1
+ 𝑏𝜙)
(3–8)
Para la puerta de salida:
𝑎𝜔𝑡 = 𝑓 (∑ 𝑤𝑖𝜔𝑥𝑖
𝑡
𝐼
𝑖=1
+ ∑ 𝑤ℎ𝜔𝑎ℎ𝑡−1
𝐻
ℎ=1
+ ∑ 𝑤𝑐𝜔𝑠𝑐𝑡
𝐶
𝑐=1
+ 𝑏𝜔)
(3–9)
Actualización de las celdas de memoria:
𝑎𝑐𝑡 = ∑ 𝑤𝑖𝑐𝑥𝑖
𝑡
𝐼
𝑖=1
+ ∑ 𝑤ℎ𝑐𝑎ℎ𝑡−1
𝐻
ℎ=1
(3–10)
𝑠𝑐𝑡 = 𝑎𝜙
𝑡 𝑠𝑐𝑡−1 + 𝑎𝜄
𝑡𝑔(𝑎𝑐𝑡) (3–11)
Y finalmente la salida de la neurona se calcula como:
𝑎ℎ𝑡 = 𝑎𝜔
𝑡 ℎ(𝑠𝑐𝑡) (3–12)
Explicación de parámetros:
Entradas y salida de la neurona:
o 𝑥𝑖𝑡 : característica del vector de entrada, de dimensión 𝐼
o 𝑎ℎ𝑡 : salida de una neurona de la propia capa en el instante 𝑡, componente de un vector de
dimensión 𝐻. (Capa con 𝐻 neuronas LSTM)
Parámetros entrenables:
o 𝑤𝑖𝜄 : vector de pesos en la puerta de entrada que multiplica al vector de entrada 𝑥.
o 𝑤ℎ𝜄: vector de pesos en la puerta de entrada que multiplica al vector de salida en el instante
anterior.
o 𝑤𝑐𝜄: vector de pesos en la puerta de entrada que multiplica al vector de estados de la propia
neurona.
o 𝑏𝜄: sesgo aplicado a la puerta de entrada
17
17 Reconocimiento de Texto Manuscrito con Deep Learning
o 𝑤𝑖𝜙 : vector de pesos en la puerta de olvido que multiplica al vector de entrada 𝑥.
o 𝑤ℎ𝜙: vector de pesos en la puerta de olvido que multiplica al vector de salida en el instante
anterior.
o 𝑤𝑐𝜙: vector de pesos en la puerta de olvido que multiplica al vector de estados de la propia
neurona.
o 𝑏𝜙: sesgo aplicado a la puerta de olvido.
o 𝑤𝑖𝜔 : vector de pesos en la puerta de salida que multiplica al vector de entrada 𝑥.
o 𝑤ℎ𝜔: vector de pesos en la puerta de salida que multiplica al vector de salida en el instante
anterior.
o 𝑤𝑐𝜔: vector de pesos en la puerta de salida que multiplica al vector de estados de la propia
neurona.
o 𝑏𝜙𝜔: sesgo aplicado a la puerta de salida.
Valores calculados a partir de las entradas y los parámetros entrenables:
o 𝑎𝜄𝑡: valor de la puerta de entrada.
o 𝑎𝜙𝑡 : valor de la puerta de olvido.
o 𝑎𝜔𝑡 : valor de la puerta de salida.
o 𝑎𝑐𝑡 : valor calculado a la entrada.
o 𝑠𝑐𝑡: valor almacenado en el elemento de memoria 𝑐 de la propia neurona. Vector de tamaño 𝐶.
3.7 Información contextual en 2D. Redes multidimensionales.
Las capas RNN y LSTM proporcionan una cierta memoria a las redes neuronales a lo largo del eje temporal,
como ya se ha explicado en secciones anteriores. En algunas aplicaciones como el reconocimiento de texto
manuscrito, donde el eje temporal se interpreta como el ancho de la imagen, también puede aportar información
la relación entre los píxeles de la imagen en la dirección vertical. Esta información es explotada por las redes
neuronales convolucionales ya explicadas, pero tan sólo a nivel local dado que usan filtros con anchos reducidos,
por ejemplo, 3x3 alrededor de cada píxel, y por lo tanto no tienen en cuenta la influencia de píxeles lejanos que
podrían aportar información contextual.
Como se ha mencionado, si se desean usar redes neuronales para tareas multidimensionales lo mejor es aplicar
redes neuronales convolucionales [14] para el procesamiento de imágenes. Una desventaja de las redes
neuronales convolucionales es que como no son recurrentes, confían en tamaño de filtros establecidos
manualmente para tener en cuenta el contexto alrededor de cada píxel. Otra desventaja es que las CNN no
escalan bien con el tamaño de las imágenes y se ha probado [14] que para problemas de etiquetado de secuencias
de dígitos manuscritos es necesario presegmentar en caracteres individuales para que funcionen eficientemente.
La idea de las redes neuronales recurrentes multidimensionales es añadir a la conexión recurrente entre la salida
y la entrada de una neurona en una capa oculta una conexión más por cada dimensión en los datos de entrada.
A la hora de calcular una salida en una neurona de este tipo, se reciben a la entrada las características del pixel
actual y todas las salidas de las neuronas de la capa donde se encuentre la neurona en todas las dimensiones de
los datos de entrada. Se habla de secuencias bidimensionales cuando se trata de imágenes, y secuencias
tridimensionales cuando se trata de vídeos. Nos centraremos en las bidimensionales.
Se puede ver un ejemplo en la Figura 3-14, donde se ilustra como la salida del píxel (i,j) depende del píxel de la
entrada en la misma dimensión, del píxel anterior en la primera dimensión (i-1,j) y del píxel anterior e la segunda
dimensión (i,j-1).
Redes Neuronales Artificiales
18
18
Figura 3-14. Computación 2D RNN. (Fuente [8] )
Con las capas MDRNN cada píxel o grupo de píxeles de la imagen, según como se defina, se considera como
un dato dentro de la secuencia, por lo tanto, hay que ir alimentando la red píxel a píxel siguiendo un orden. El
orden que se sigue se puede ver en la Figura 3-15, y es de arriba hacia abajo y de izquierda a derecha.
Figura 3-15. Orden en la computación 2D RNN. (Fuente [8] )
El algoritmo que permite recorrer la imagen en la dirección indicada y calcular la activación en cada punto a la
salida de la capa MDRNN es el siguiente: [8]
for 𝑝1 = 0 to 𝐷1 − 1 do
for 𝑝2 = 0 to 𝐷2 − 1 do
for ℎ = 1 to 𝐻 do
𝑎ℎ(𝑝1,𝑝2)
= ∑ 𝑥𝑖(𝑝1,𝑝2)𝐼
𝑖=1 𝑤𝑖ℎ
if 𝑝1 > 0 then
𝑎ℎ(𝑝1,𝑝2)
+= ∑ 𝑏ℎ`(𝑝1−1,𝑝2)𝐻
ℎ′=1 𝑤ℎ′ℎ1
if 𝑝2 > 0 then
𝑎ℎ(𝑝1,𝑝2)
+= ∑ 𝑏ℎ`(𝑝1,𝑝2−1)𝐻
ℎ′=1 𝑤ℎ′ℎ2
𝑏ℎ(𝑝1,𝑝2)
= 𝑓(𝑎ℎ(𝑝1,𝑝2)
)
Algoritmo 3-1. Activación capa MDRNN
19
19 Reconocimiento de Texto Manuscrito con Deep Learning
La notación que se sigue es la misma que en secciones anteriores, pero ahora el superíndice de cada variable
indica la posición en la imagen. Por lo tanto, se tiene:
𝐷1: anchura de la imagen
𝐷2: altura de la imagen
𝐻: número de neuronas en la capa oculta
𝐼: número de neuronas en la capa anterior, se considera capa de entrada
𝑥𝑖(𝑝1,𝑝2)
: valor de la característica 𝑖 en el vector de entrada o salida de la capa anterior.
𝑤𝑖ℎ: peso entre la entrada y la neurona ℎ de salida.
𝑏ℎ`(𝑝1−1,𝑝2)
: salida de la neurona la neurona ℎ′ en el píxel superior al actual.
𝑏ℎ`(𝑝1,𝑝2−1)
: salida de la neurona la neurona ℎ′ en el píxel a la izquierda del actual
𝑤ℎ′ℎ1 : peso entre la salida de la neurona ℎ′ del pixel superior y la neurona ℎ del pixel actual
𝑤ℎ′ℎ2 : peso entre la salida de la neurona ℎ′ del pixel a la izquierda y la neurona ℎ del pixel actual.
𝑎ℎ(𝑝1,𝑝2)
: salida de la neurona ℎ en el píxel actual antes de la activación
𝑏ℎ(𝑝1,𝑝2)
: salida de la neurona ℎ en el píxel actual tras la activación.
De igual modo que se discutió con la capa RNN bidireccional en la que además de tener en cuenta la información
contextual pasada, también se tienen en cuenta la información contextual futura, en el caso de las capas MDRNN
en dos dimensiones aparecen 4 contextos que se deben tener en cuenta, ya que hasta ahora solo se ha considerado
la influencia de los píxeles a la izquierda y superior al actual, como se puede ver en la Figura 3-16
Figura 3-16. Píxeles influyentes en la activación de la salida en el pixel actual en una capa
2DRNN unidireccional. (Fuente [8] )
Sin embargo, se puede observar que en el caso 2D se tienen cuatro direcciones posibles en las que se puede
recorrer la imagen, que se ilustran en la Figura 3-17. Para computar las 4 direcciones posibles es necesario
establecer 4 capas 2DRNN en paralelo utilizando el mismo esquema que se llevó a cabo en la Figura 3-11 para
el caso 1DRNN bidireccional.
Este tipo de redes se denominan redes MDRNN multidireccionales.
Redes Neuronales Artificiales
20
20
Figura 3-17. Direcciones posibles para recorrer una imagen. (Fuente [8] )
En la Figura 3-18 se puede visualizar el funcionamiento de una capa MDRNN, se ilustra un esquema en el que
se tiene una imagen de entrada RGB, una capa con 20 neuronas MDRNN y la salida de la misma. Se observa
que la salida de la misma es un número de imágenes igual al número de neuronas en la capa y del mismo tamaño
que las imágenes de entrada. También se visualiza como para computar la salida de cada neurona en un píxel,
se tienen en cuenta el valor del píxel en los tres canales de entrada y la salida de todas las neuronas de la capa en
los píxeles anteriores tanto en la dirección horizontal como en la vertical.
Figura 3-18. Esquema capa MDRNN
Todo lo expuesto para las redes MDRNN y MDRNN multidireccional se puede aplicar sustituyendo la neurona
RNN por una neurona LSTM que como ya se indicó en secciones anteriores, soluciona el problema del
desvanecimiento del gradiente y consigue acceder a información contextual a todos los píxeles de la imagen.
Esta es la idea de las capas MDLSTM.
En el caso 2D, la neurona LSTM pasa a tener ahora dos puertas de olvido, una para cada dimensión, y el resto
de puertas se ven modificadas ya que ahora reciben 3 vectores de activación, el de la entrada (o salida de la capa
anterior), el vector de activación de salida del pixel anterior en la dimensión horizontal y el vector de activación
de salida del pixel anterior en la dimensión vertical. Por lo tanto, las expresiones quedan de la siguiente forma:
21
21 Reconocimiento de Texto Manuscrito con Deep Learning
Para la puerta de entrada:
𝑎𝜄(𝑝1,𝑝2)
= 𝑓 (∑ 𝑤𝑖𝜄𝑥𝑖(𝑝1,𝑝2)
𝐼
𝑖=1
+ ∑ 𝑤ℎ𝜄1 𝑎ℎ
(𝑝1−1,𝑝2)
𝐻
ℎ=1𝑝1>0
+ ∑ 𝑤ℎ𝜄2 𝑎ℎ
(𝑝1,𝑝2−1)
𝐻
ℎ=1𝑝2>0
+ ∑ 𝑤𝑐𝜄1 𝑠𝑐
(𝑝1−1,𝑝2)
𝐶
𝑐=1𝑝1 >0
+ ∑ 𝑤𝑐𝜄2 𝑠𝑐
(𝑝1,𝑝2−1)
𝐶
𝑐=1𝑝2 >0
)
(3–13)
Para la puerta de olvido en la dimensión horizontal:
𝑎𝜙,1(𝑝1,𝑝2)
= 𝑓 (∑ 𝑤𝑖(𝜙,1)𝑥𝑖(𝑝1,𝑝2)
𝐼
𝑖=1
+ ∑ 𝑤ℎ(𝜙,1)1 𝑎ℎ
(𝑝1−1,𝑝2)
𝐻
ℎ=1𝑝1 >0
+ ∑ 𝑤ℎ(𝜙,1)2 𝑎ℎ
(𝑝1,𝑝2−1)
𝐻
ℎ=1𝑝2 >0
+ ∑ 𝑤𝑐(𝜙,1)𝑠𝑐(𝑝1−1,𝑝2)
𝐶
𝑐=1𝑝1 >0
)
(3–14)
Para la puerta de olvido en la dimensión vertical:
𝑎𝜙,2(𝑝1,𝑝2)
= 𝑓 (∑ 𝑤𝑖(𝜙,2)𝑥𝑖(𝑝1,𝑝2)
𝐼
𝑖=1
+ ∑ 𝑤ℎ(𝜙,2)1 𝑎ℎ
(𝑝1−1,𝑝2)
𝐻
ℎ=1𝑝1 >0
+ ∑ 𝑤ℎ(𝜙,2)2 𝑎ℎ
(𝑝1,𝑝2−1)
𝐻
ℎ=1𝑝2 >0
+ ∑ 𝑤𝑐(𝜙,2)𝑠𝑐(𝑝1,𝑝2−1)
𝐶
𝑐=1𝑝2>0
)
(3–15)
Para la puerta de salida:
𝑎𝜔(𝑝1,𝑝2)
= 𝑓 (∑ 𝑤𝑖𝜔𝑥𝑖(𝑝1,𝑝2)
𝐼
𝑖=1
+ ∑ 𝑤ℎ𝜔1 𝑎ℎ
(𝑝1−1,𝑝2)
𝐻
ℎ=1𝑝1 >0
+ ∑ 𝑤ℎ𝜔2 𝑎ℎ
(𝑝1,𝑝2−1)
𝐻
ℎ=1𝑝2 >0
+ ∑ 𝑤𝑐𝜔𝑠𝑐(𝑝1,𝑝2)
𝐶
𝑐=1
)
(3–16)
Actualización de las celdas de memoria:
𝑎𝑐(𝑝1,𝑝2)
= ∑ 𝑤𝑖𝑐𝑥𝑖(𝑝1,𝑝2)
𝐼
𝑖=1
+ ∑ 𝑤ℎ𝑐1 𝑎ℎ
(𝑝1−1,𝑝2)
𝐻
ℎ=1𝑝1 >0
+ ∑ 𝑤ℎ𝑐2 𝑎ℎ
(𝑝1,𝑝2−1)
𝐻
ℎ=1𝑝1 >0
(3–17)
𝑠𝑐(𝑝1,𝑝2)
= 𝑎𝜙,1(𝑝1,𝑝2)
𝑠𝑐(𝑝1−1,𝑝2)
+ 𝑎𝜙,2(𝑝1,𝑝2)
𝑠𝑐(𝑝1,𝑝2−1)
+ 𝑎𝜄(𝑝1,𝑝2)
𝑔 (𝑎𝑐(𝑝1,𝑝2)
) (3–18)
Y finalmente la salida de la neurona se calcula como:
𝑎ℎ(𝑝1,𝑝2)
= 𝑎𝜔(𝑝1,𝑝2)
ℎ (𝑠𝑐(𝑝1,𝑝2)
) (3–19)
23
4 SEQUENCE LABELLING
on las redes neuronales recurrentes (RNN) y sus diversas variantes como puede ser LSTM, se proporciona
una solución a la hora de tener en cuenta la dependencia entre etiquetas en un problema de etiquetado de
secuencias. Este tipo de estructuras etiqueta cada punto de la secuencia de entrada teniendo en cuenta su
dependencia temporal, gracias al estado interno de la red. Sin embargo, este tipo de métodos no se pueden aplicar
directamente sobre secuencias sin segmentar previamente, ya que las RNN sólo se pueden entrenar para
proporcionar una etiqueta de salida por cada vector de características a la entrada.
Es decir, para aplicar RNN directamente sobre un problema de etiquetado de secuencias es necesario pre-
segmentar los datos de entrada y realizar un procesamiento posterior a la salida para obtener la secuencia final.
En el caso del problema de transcripción de textos manuscritos (Offline Handwriting Recognition, OHR)
consistiría en segmentar las imágenes para separar los caracteres individualmente, aplicar el entrenamiento con
estos caracteres separados y finalmente unir a la salida las diferentes etiquetas correspondientes a cada carácter
para formar palabras, frases, etc…
Para realizar el etiquetado de secuencias se han propuesto varios algoritmos, como pueden ser los modelos
híbridos ocultos de Markov (Hybrid hidden Markov Models HMM), los cuales se han utilizado normalmente
para el reconocimiento de voz. Estas arquitecturas se han utilizado en conjunto con redes MLP [15]. Sin
embargo, estas estructuras tienen varios inconvenientes y la más utilizada a día de hoy es la técnica que se
presenta a continuación.
4.1 Connectionist Temporal Classification
Las técnicas mencionadas en la introducción de esta sección para el etiquetado de secuencias se han probado
con éxito en muchos problemas de aprendizaje máquina [16] [12], sin embargo, tienen algunos inconvenientes.
Entre ellos se destaca el procesado de los datos que hay que hacer, así como el conocimiento específico de cada
problema que se quiere resolver. Por ejemplo, es necesario diseñar los modelos de estado para HMM o elegir
las características de entrada para su resolución. [9]
Además, el entrenamiento con modelos ocultos de Markov es generativo, y el problema que se tiene entre manos,
que es el etiquetado de secuencias es un problema discriminativo.
En esta sección se propone una capa a la salida de una RNN (o cualquier otro tipo de red neuronal equivalente)
denominada Connectionist Temporal Classification (CTC). Esta capa realiza automáticamente el etiquetado de
secuencias a la salida de la red sin necesidad de presegmentar los datos de entrada y realizar un procesado
posterior. Dicha capa se puede integrar directamente con la estructura de la RNN y entrenar todo como un
conjunto, ya que el modelo matemático de dicha capa es diferenciable por lo que se puede aplicar back-
propagation que es el método más extendido para el entrenamiento de redes neuronales.
El objetivo de la capa CTC es transformar la salida de la red neuronal en una distribución de probabilidad
condicional sobre secuencias de etiquetas.
4.1.1 Transformación de la salida de la red en secuencias de etiquetas.
Una capa CTC [9] es una capa de salida de una red neuronal que proporciona una salida suave, que puede ser
interpretada como probabilidades. Se compone de un número de neuronas igual a 𝐿 + 1, donde 𝐿 es el número
total de etiquetas que hay en el alfabeto. Por ejemplo, en el caso de detección de manuscritos en inglés cada una
de las primeras 𝐿 neuronas de salida se correspondería con la probabilidad de detectar cada uno de los caracteres
del abecedario inglés, (extensible a mayúsculas, minúsculas, signos de puntuación,…). La neurona extra se
corresponde con la probabilidad de observar lo que se conoce como ‘blank’, que consiste en no observar ninguna
C
Sequence Labelling
24
24
etiqueta, (no confundir con los espacios en blanco, un espacio en blanco dentro de una frase tiene asignada una
etiqueta dentro de las 𝐿 primeras). La adición de la etiqueta ‘blank’ es muy importante para el funcionamiento
de la detección con la capa CTC, ya que normalmente marca la separación entre dos caracteres, en el caso de
transcripción de manuscritos.
En cada instante de tiempo o en cada posición sobre el eje horizontal dentro de una imagen, la red neuronal con
capa CTC ofrece a la salida la probabilidad de observar cada uno de los caracteres del alfabeto. En conjunto, las
salidas definen las probabilidades de todas las secuencias de etiquetas posibles dada una entrada.
Formalmente, si se tiene una secuencia de entrada x de longitud 𝑇 definido en un espacio de 𝑚 características
𝒳 = (ℝ𝑚)𝑇, se aplica una red neuronal de cualquier tipo a la entrada que se define como un conjunto de pesos
𝜔 que realizan una transformación 𝒩𝜔: (ℝ𝑚)𝑇 → (ℝ𝑛)𝑇, es decir, se pasan de tener T muestras de dimensión
m a tener T muestras de dimensión n. La salida de la red neuronal se define como 𝐲 = 𝒩𝜔(𝒙). Se define 𝑦𝑘𝑡
como la activación de la neurona de salida 𝑘, que se corresponde con un carácter del alfabeto o blank, en el
instante 𝑡. Tomando estas probabilidades se define una distribución de probabilidad sobre el conjunto de todas
las secuencias de etiquetas posibles a la salida de longitud T, que hacen un total de (𝐿 + 1)𝑇, donde 𝐿 es el
número de etiquetas posibles dentro del alfabeto y se suma una unidad para tener en cuenta el blank. Se denota
cada secuencia posible dentro del conjunto mencionado anteriormente como 𝜋. Por lo tanto, la probabilidad
condicional de cada secuencia de etiquetas se define como:
𝑝(𝜋|𝐱) = ∏ 𝑦𝜋𝑡𝑡
𝑇
𝑡=1
(4–1)
En este punto es necesario entender que cada una de las secuencias de etiquetas 𝜋 está compuesta por etiquetas
correspondientes a caracteres y etiquetas blank. Por lo tanto, para obtener la secuencia de etiquetas real a la salida
hay que definir una función que mapee estas secuencias a secuencias sin blank. ℬ: (𝐿 + 1)𝑇 → 𝐿≤𝑇. Esta
función elimina los blanks y además los caracteres repetidos consecutivamente. Por ejemplo ℬ(𝑎 − 𝑎𝑏 −) =ℬ(−𝑎𝑎 − −𝑎𝑏𝑏) = 𝑎𝑎𝑏. La salida de la capa CTC asigna una probabilidad condicionada a la entrada a cada
una de estas secuencias 𝐳 ∈ 𝐿≤𝑇, que es la suma de las probabilidades de todas las secuencias que se mapean a
la secuencia 𝐳.
𝑝(𝐳|𝐱) = ∑ 𝑝(𝜋|𝐱)
𝜋∈ℬ−1(𝐳)
(4–2)
4.1.2 Construcción del clasificador
Una vez que la capa CTC ofrece a la salida la probabilidad condicional para cada una de las secuencias de
etiquetas posibles dada una secuencia de entrada, el clasificador no tiene más que seleccionar la secuencia que
ofrezca una mayor probabilidad condicional:
ℎ(𝐱) = 𝑎𝑟𝑔 𝑚𝑎𝑥𝒛∈𝐿≤𝑇
𝑝(𝒛|𝒙) (4–3)
Sin embargo, no se ha encontrado forma de implementar actualmente el cálculo de la probabilidad condicional
𝑝(𝐳|𝐱), debido a la cantidad combinaciones que puedan dar la misma secuencia 𝐳 al aplicar la función ℬ. Para
solucionarlo se han implementado dos métodos aproximados.
El primero de ellos se denomina “best path decoding” y en el mismo se asume que la secuencia de etiquetas más
probable 𝑝(𝐳|𝐱) se corresponde con la secuencia de salida más probable 𝑝(𝜋|𝐱) a la que posteriormente se
aplica la función ℬ.
25
25 Reconocimiento de Texto Manuscrito con Deep Learning
ℎ(𝐱) ≈ ℬ (𝑎𝑟𝑔 𝑚𝑎𝑥𝜋∈(𝐿+1)𝑇
𝑝(𝜋|𝐱)) (4–4)
Este método es aproximado y no garantiza que se obtenga la secuencia de mayor probabilidad.
El segundo método se denomina “prefix search decoding”. Y se basa en la división de la secuencia de salida
completa en subsecuencias delimitadas por la aparición de un blank en sus extremos y se decodifican dichas
secuencias individualmente tras lo que se concatenan. Ver con más detalle en [9].
Este segundo método siempre obtiene la secuencia más probable, sin embargo, la complejidad computacional
crece exponencialmente con la longitud de la secuencia de entrada. Hay cierta investigación para implementar
este método de forma más eficiente.
27
5 SOFTWARE
n esta sección se muestran las diferentes herramientas disponibles actualmente para la implementación de
redes neuronales. Se centra en la exposición de las herramientas que se han utilizado activamente durante
la realización de este trabajo, mencionando ligeramente otras alternativas con sus ventajas e
inconvenientes.
Hay varias alternativas de herramientas de alto nivel que ofrecen interfaces de usuario para poder configurar
estructuras a medida de deep learning con sencillas líneas de código, pero las más extendidas son Matlab,
Python, Lua y Java.
Indicar aquí que las tareas de deep learning necesitan de unos requisitos hardware muy potentes para poder
obtener resultados en un tiempo coherente, por lo que normalmente se lanzan los algoritmos de entrenamiento
en máquinas que tienen varios núcleos de procesamiento que pueden ser tanto CPU como GPU, siendo las GPU
las más utilizadas ya que ofrecen mayor capacidad de procesamiento. Para poder realizar la gestión de los
diferentes núcleos de procesamiento dentro de una máquina, tanto las librerías en Matlab como Python están
soportadas por código C++ a más bajo nivel, actuando como interfaz al hardware. Especialmente las librerías
CUDA escritas en C++ permiten controlar el uso de las GPU.
Con respecto a Matlab mencionar que, aunque contiene librerías para la implementación de algoritmo de deep
learning, actualmente no implementa las capas tipo LSTM o CTC, por lo que se ha descartado su uso en este
trabajo. Además, el uso de Matlab para este tipo de tareas no se encuentra muy extendido actualmente entre los
autores, por lo que la documentación es limitada.
En Lua se tiene a Torch, y en Java está DeepLearning4J, sin embargo, estas librerías están muy lejos en lo que
se refiere a la velocidad de computación y resultados obtenidos comparados con las librerías de Python [17].
En el caso de Python, hay varias librerías dedicadas a deep learning, como pueden ser Theano, TensorFlow y
Keras. Cada una de ellas tiene su forma de implementar las diferentes estructuras y a la hora de implementar un
marco de trabajo para poder comparar algoritmos es necesario centrarse en alguna de ellas. En [17] se realiza
una comparativa entre las diferentes herramientas y se llega a la conclusión de que Theano es más sencillo con
respecto al número de líneas necesario y dependiendo de la tarea a realizar uno es más rápido y ofrece mejores
resultados que el otro. Por lo tanto, elegir uno u otro es en principio indiferente teniendo en cuenta estos aspectos.
Se ha tomado como criterio la documentación disponible para cada librería, donde TensorFlow supera a Theano,
además debido a que está soportado por Google, el número de investigadores que utilizan TensorFlow es
superior, a lo que se suma que varios frameworks de organizaciones con años de experiencia en este campo y
que tradicionalmente implementaban en Theano están migrando a TensorFlow.
Finalmente aclarar que se ha analizado también la implementación de los distintos algoritmos y capas explicadas
en la Sección 3. Durante la primera etapa de la realización de este trabajo, las capas MDRNN y MDLSTM no
estaban implementadas en TensorFlow ni Theano, por lo que una de las tareas del presente trabajo ha sido la
programación de dicha capa.
5.1 TensorFlow
TensorFlow es una herramienta multiplataforma desarrollada por Google y orientada a la implementación de
algoritmos de aprendizaje máquina. Está compuesta por un conjunto de librerías en Python, C y Java, aunque se
encuentra más extendida su versión en Python ya que implementa la mayoría de los algoritmos y es la más
utilizada en la actualidad, por lo que recibe soporte y actualizaciones continuamente.
E
Software
28
28
Figura 5-1. Logo de TensorFlow
Ofrece una API en [18] donde se explica con ejemplos la mayoría de módulos que contiene, además de varios
tutoriales. Implementa la mayoría de capas y operaciones necesarias para trabajar con datos y algoritmos de
aprendizaje máquina. En general trabaja con datos del tipo Numpy, que es una librería en Python que permite
realizar operaciones con matrices además de soportar todo tipo de funciones necesarias para trabajar con datos
numéricos.
Figura 5-2. Logo de NumPy
La filosofía a la hora de programar en TensorFlow es complicada de entender la primera vez que se intenta
implementar algún algoritmo, pues difiere de cualquier otro tipo de software de programación numérica. La
ejecución de cualquier operación se realiza en nodos dentro de un grafo de computación. Estos nodos se
comunican mediante tensores, es decir, cada nodo del grafo de computación recibe como entrada cero o más
tensores y devuelve a la salida un tensor.
Los tensores son datos numéricos manejables con funciones de la librería NumPy mencionada anteriormente.
Estos datos se tratan como matrices multidimensionales, y se incluyen desde matrices 0-dimensionales que se
corresponden con escalares, 1-dimensionales como vectores hasta N-dimensionales, siendo N cualquier número,
por lo que se pueden tratar estructura de datos muy complejas.
Con respecto a los nodos dentro de un grafo de computación, se pueden diferenciar 5 tipos importantes:
Las constantes: son nodos que no reciben nada como entrada y ofrecen a la salida un dato que almacena
en su interior.
Las operaciones matemáticas: reciben como entrada uno o más tensores y devuelven a la salida un
tensor, tras realizar las operaciones sobre los tensores de entrada.
Las variables: son nodos que sólo tienen sentido en los grafos de aprendizaje máquina, pues tienen la
misma estructura que las constantes, salvo que el valor almacenado en su interior es entrenable. Se
utilizan para implementar los parámetros entrenables dentro de una red neuronal. Pueden inicializarse.
Los “placeholders”, son nodos que se definen vacíos durante la definición del grafo y reciben valores
29
29 Reconocimiento de Texto Manuscrito con Deep Learning
para almacenar posteriormente en la ejecución de las sesiones. Las sesiones son un punto importante a
entender que se explica con posterioridad.
Optimizadores: son nodos que reciben a la entrada un tensor a minimizar con respecto a los nodos
“variables” que se definieron anteriormente, calcula un nuevo valor para estas variables donde son
finalmente almacenados.
Una vez se han clasificado los diferentes tipos de datos es hora de pasar a realizar un ejemplo para ver cómo
funciona TensorFlow.
Ejemplo 5–1. Funcionamiento de constantes en TensorFlow
En este ejemplo se muestra como se definen nodos de tipo constante y como se puede obtener el valor
almacenado en ellas.
node1 = tf.constant(3.0, dtype=tf.float32)
node2 = tf.constant(4.0)
print(node1, node2)
A la salida del código anterior se obtiene lo siguiente:
Tensor("Const:0", shape=(), dtype=float32) Tensor("Const_1:0", shape=(),
dtype=float32)
Se observa que directamente si se intenta imprimir la constante por su nombre lo que se imprime son las
características del nodo tales como el nombre, la forma y el tipo de datos. Esto se debe al propio funcionamiento
de TensorFlow, en la que los datos solo se pueden evaluar como tensores a la salida de los distintos nodos. Para
evaluar los nodos de un grafo TensorFlow es necesario ejecutarlo dentro de una sesión. Por ejemplo, para evaluar
el grafo anterior compuesto por dos constantes, se crearía una sesión y se ejecutarían los nodos de la siguiente
forma:
sess = tf.Session()
print(sess.run([node1, node2]))
A la salida de la ejecución del este código, se obtiene lo siguiente;
[3.0, 4.0]
Que se corresponde con los valores 3.0 y 4.0 almacenados en los nodos de tipo constantes que se definieron en
el propio código.
A continuación, se muestra un segundo ejemplo en el que se puede entender el funcionamiento de las
operaciones matemáticas, y del flujo de tensores sobre la red.
Ejemplo 5–2. Funcionamiento de operaciones matemáticas en TensorFlow
En este ejemplo se muestra como se realiza una suma en TensorFlow
node1 = tf.constant(3.0, dtype=tf.float32)
node2 = tf.constant(4.0)
node3 = tf.add(node1, node2)
Software
30
30
sess = tf.Session()
print("node3: ", node3)
print("sess.run(node3): ",sess.run(node3))
A la salida del código anterior se obtiene lo siguiente:
node3: Tensor("Add:0", shape=(), dtype=float32)
sess.run(node3): 7.0
En este ejemplo se observa otro aspecto importante de TensorFlow, que es la dependencia entre nodos. A la hora
de ejecutar el nodo “Add:0” dentro de la sesión sólo hay que llamar a la ejecución de dicho nodo, que
automáticamente hace que se ejecuten todos los nodos de los que tenga dependencia hacia atrás.
En la Figura 5-3 se ilustra la estructura del grafo que se ha configurado para este ejemplo.
Figura 5-3. Estructura del grafo implementado en este ejemplo. (Fuente [18])
Se podría pensar que TensorFlow es muy complicado a la hora de hacer una simple suma, sin embargo, la
interpretación de cualquier operación como nodo y resultados como tensores facilitan la construcción de
cualquier sistema de aprendizaje máquina.
Ya se ha comprobado el funcionamiento de los nodos de tipo constante y un ejemplo de un nodo de tipo
operación. Con este tipo de nodos solo se han podido ejecutar operaciones sobre datos predefinidos ya que los
puntos de entrada al grafo han sido nodos constantes. Para poder aplicar un grafo a datos de entrada variables
como pueden ser las secuencias de entrada de un clasificador para deep learning, hay que utilizar los nodos de
tipos placeholder, como se puede ver en el siguiente ejemplo:
Ejemplo 5–3. Funcionamiento de los nodos placeholders en TensorFlow
En este ejemplo se crean dos nodos de tipo placeholder que pueden tomar cualquier valor que se le indique, se
crea otro nodo de tipo suma que realiza la suma de los valores insertados en los placehoders y finalmente se
define otro nodo que multiplica el valor de salida del nodo suma por tres.
a = tf.placeholder(tf.float32)
b = tf.placeholder(tf.float32)
adder_node = tf.add(a, b)
add_and_triple = adder_node * 3
sess = tf.Session()
print(sess.run(add_and_triple, {a: 3, b:4.5}))
31
31 Reconocimiento de Texto Manuscrito con Deep Learning
A la salida del código anterior se obtiene lo siguiente:
22.5
De nuevo, en el código anterior se muestra que para obtener la salida del nodo sólo hay que ejecutar el nodo de
salida, que en este caso es add_and_triple, ya que automáticamente se ejecutan sus dependencias hacia atrás que
en este caso es el nodo “adder_node” y los placeholders “a” y “b”. Cuando se realiza la ejecución con la función
“sess.run”, se puede observar cómo se le pasa un segundo parámetro constituido por un diccionario de Python
donde se indican los valores de todos los placeholders de los que depende el nodo que se desea ejecutar.
Figura 5-4. Estructura del grafo con placeholders. (Fuente [18])
Gráficamente se puede visualizar el grafo que se ha montado en la Figura 5-4
Una vez se han mostrado los nodos básicos, se van a analizar los dos tipos de nodos restantes para cuyo uso se
necesita de alguna aplicación donde haya que entrenar al sistema, estos nodos son el de tipo variable y el de tipo
optimizador.
Para ello se implementa uno de los ejemplos más sencillos de aprendizaje máquina, como es la regresión lineal.
Ejemplo 5–4. Ejemplo de regresión lineal
Este es ya un ejemplo de aplicación de TensorFlow a un problema de aprendizaje máquina de regresión lineal,
a continuación se muestra el código completo.
import numpy as np
import tensorflow as tf
# Variables que se pueden entrenar
Software
32
32
W = tf.Variable([.3], dtype=tf.float32)
b = tf.Variable([-.3], dtype=tf.float32)
# Se definen los placeholders para los datos de entrada y salida asi como
las operaciones a realizar con dichos datos
x = tf.placeholder(tf.float32)
linear_model = W * x + b
y = tf.placeholder(tf.float32)
# Nodo de tipo operacion que calculara el error MSE
loss = tf.reduce_sum(tf.square(linear_model - y)) # MSE
# Nodo optimizador
optimizer = tf.train.GradientDescentOptimizer(0.01)
train = optimizer.minimize(loss)
# Se definen los datos con los que se alimentara el sistema
x_train = [1,2,3,4]
y_train = [0,-1,-2,-3]
# Nodo inicializador de variables
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init) # Se ejecuta el iniciador de variables
# Entrenamiento
for i in range(1000):
sess.run(train, {x:x_train, y:y_train})
# Se ejecutan los parámetros para ser evaluados
curr_W, curr_b, curr_loss = sess.run([W, b, loss], {x:x_train, y:y_train})
print("W: %s b: %s loss: %s"%(curr_W, curr_b, curr_loss))
A la salida del código anterior se obtiene lo siguiente:
W: [-0.9999969] b: [ 0.99999082] loss: 5.69997e-11
El código anterior incluye comentarios que pueden hacer que se entienda mejor. A parte de lo explicado en los
ejemplos anteriores, en este ejemplo se incluye el nodo de tipo Variable y el de tipo optimizador.
En el mismo se intenta resolver el problema de regresión que sigue la siguiente expresión:
𝑦 = 𝑊𝑥 + 𝑏 (5–1)
Donde los valores de W y b son desconocidos y a partir de pares de datos 𝑥, 𝑦 se entrena el sistema para
calcularlos. Como se muestra en el código, se han definido los nodos 𝑥, 𝑦 como placeholders en el sistema, que
reciben un valor posteriormente en el entrenamiento y los nodos 𝑊, 𝑏 como variables, con un valor inicial de
W = 0.3 y b = -0.3.
También se define el nodo “train”, que es un nodo de tipo optimizador, y se le ha pasado como parámetro el
nodo “loss”, que es un nodo de tipo operación matemática e implementa la función de pérdidas. El nodo de tipo
train, toma el nodo loss e internamente implementa el método de descenso de gradiente el cual proporciona un
nuevo valor para las variables 𝑊, 𝑏 cada vez que dicho nodo es ejecutado. Se puede observar como se ejecuta
33
33 Reconocimiento de Texto Manuscrito con Deep Learning
dicho nodo en un bucle de 1000 iteraciones el cual va minimizando el valor del nodo loss mediante la
modificación de 𝑊, 𝑏.
Finalmente, también se puede observar como finalmente se imprime el valor final de los valores 𝑊, 𝑏 y la
función 𝑙𝑜𝑠𝑠. Se comprueba que de la misma forma que se ejecuta el nodo train con la función sess.run, también
se ejecutan los nodos W, b y loss. La diferencia está que la ejecución train modifica los valores de W y b mientras
que el resto no. Se pueden ejecutar nodos de la red de forma independiente.
Figura 5-5. Estructura del grafo en el problema de regresión lineal.
Gráficamente se puede visualizar el grafo que se ha programado para resolver el problema de regresión lineal
en la Figura 5-5
5.2 Implementación MDLSTM
A la hora de implementar una estructura que contenga cualquier tipo de capas neuronales de las presentadas en
la Secciones 3 y 4, en TensorFlow se dispone de todos los elementos necesarios, incluyendo capas MLP, capas
CNN, capas RNN y capas LSTM. Sin embargo, las capas multidimensionales MDRNN y MDLSTM no se
encuentran implementadas.
Ha habido muchos intentos de programar esta estructura y varios grupos de trabajo han incluido en sus
Software
34
34
publicaciones resultados mediante estructuras con capas MDRNN y MDLSTM, sin embargo, no han publicado
el código utilizado. En [19] se explica el problema computacional que surge al programar este tipo de estructuras
y realizan un esfuerzo para programarlo directamente sobre librerías CUDA donden controlan el procesamiento
de las GPUs. En enero de 2017 los mismos autores publican un framework que incluye todas las estructuras
neuronales, incluyendo las capas MDLSTM, pero dicho framework necesita de máquinas con GPUs para su
ejecución.
Previamente en este proyecto se ha programado la capa MDLSTM para su versión en 2D y su aplicación a
imágenes, con el objetivo de realizar estructuras para el reconocimiento de texto manuscrito. Se ha programado
en TensorFlow siguiendo su filosofía de programación aplicada a las redes neuronales.
Se ha programado una interfaz similar a la utilizada en la capa convolucional disponible en la API de TensorFlow
[18]. La función de la capa convolucional recibe a la entrada un tensor de 4 dimensiones, [batchSize, width,
height, nFeatures], donde:
batchSize: es el número de imágenes (datos de entrada) que se procesan a la vez.
width: es la dimensión horizontal de la imagen.
height: es la dimensión vertical de la imagen.
nFeatures: es el número de características (canales) de la imagen.
Se ha programado la capa MDLSTM para que las matrices a la entrada y a la salida tengan la misma dimensión,
para poder configurar posteriormente las estructuras de redes neuronales conectando las salidas de una capa
convolucional a la entrada de una capa MDLSTM y viceversa.
Para poder recorrer las imágenes en las 4 direcciones que ofrece el caso 2DLSTM, se ha añadido un parámetro
en la llamada a la función para indicar esta dirección. A partir de esta dirección y con la función
tensorflow.reverse se invierte la imagen en la dirección que se le indique para posteriormente recorrerla con el
filtro LSTM.
Para procesar la imagen con LSTM se recorre la misma con dos bucles, un bucle externo que recorre la imagen
de izquierda a derecha y un bucle interno que la recorre de arriba hacia abajo (en el caso que se indique esta
dirección de recorrerlo con el parámetro explicado en el párrafo anterior).
También se realiza un conjunto de transposiciones de matrices de 4 dimensiones para poder llevar a cabo la
multiplicación de matrices, la concatenación y finalmente devolver una matriz con las dimensiones originales.
El siguiente código muestra la implementación que se ha realizado:
import numpy as np
import tensorflow as tf
def m2dlstm_layer(inputs,direction,nCells):
"""Create a mdlstm with m=2 slice in the direction read way for 2D input
data. Parameters: input is a training batch PlaceHolder tensor of shape
(batchSize,heigh,width,nInputFeatures). direction is a string which indicate
the way the inputs images are going to be scanned ('downward-
forward','upward-forward','downward-backward','upward-backward’) nCells is
the number of cells(features) required to be extracted at the output. It
returns tensors of shape (batchSize, height, width, nCells) """
# Change direction to read image in the appropriate way
if(direction=='upward-forward'):
inputs=tf.reverse(inputs,[1])
elif(direction=='downward-backward'):
inputs=tf.reverse(inputs,[2])
elif(direction=='upward-backward'):
inputs=tf.reverse(inputs,[1,2])
35
35 Reconocimiento de Texto Manuscrito con Deep Learning
elif(direction=='downward-forward'):
pass
else:
print('Invalid direction')
nInputFeatures=int(inputs.shape[3])
# Input gates weights(input, previous bidirectional outputs,
previous bidirectional states) and bias
w_i_iota=tf.Variable(tf.random_normal([nInputFeatures,nCells],
mean=0.0,stddev=0.01))
w_dhor_h_iota=tf.Variable(tf.random_normal([nCells,nCells],
mean=0.0,stddev=0.01))
w_dver_h_iota=tf.Variable(tf.random_normal([nCells,nCells],
mean=0.0,stddev=0.01))
w_dhor_c_iota=tf.Variable(tf.random_normal([nCells,nCells],
mean=0.0,stddev=0.01))
w_dver_c_iota=tf.Variable(tf.random_normal([nCells,nCells],
mean=0.0,stddev=0.01))
bias_iota=tf.Variable(tf.random_normal([nCells],
mean=0.0,stddev=0.01))
# Forget horizontal gates weights (input, previous bidirectional
outputs, previous bidirectional states) and bias
w_i_phi_dhor=tf.Variable(tf.random_normal(
[nInputFeatures,nCells],mean=0.0,stddev=0.01))
w_dhor_h_phi_dhor=tf.Variable(tf.random_normal(
[nCells,nCells],mean=0.0,stddev=0.01))
w_dver_h_phi_dhor=tf.Variable(tf.random_normal(
[nCells,nCells],mean=0.0,stddev=0.01))
w_dhor_c_phi_dhor=tf.Variable(tf.random_normal(
[nCells,nCells],mean=0.0,stddev=0.01))
w_dver_c_phi_dhor=tf.Variable(tf.random_normal(
[nCells,nCells],mean=0.0,stddev=0.01))
bias_phi_dhor=tf.Variable(tf.random_normal(
[nCells], mean=0.0, stddev=0.01))
# Forget vertical gates weights (input, previous bidirectional
outputs, previous bidirectional states) and bias
w_i_phi_dver=tf.Variable(tf.random_normal(
[nInputFeatures,nCells],mean=0.0,stddev=0.01))
w_dhor_h_phi_dver=tf.Variable(tf.random_normal(
[nCells,nCells],mean=0.0,stddev=0.01))
w_dver_h_phi_dver=tf.Variable(tf.random_normal(
[nCells,nCells],mean=0.0,stddev=0.01))
w_dhor_c_phi_dver=tf.Variable(tf.random_normal(
[nCells,nCells],mean=0.0,stddev=0.01))
Software
36
36
w_dver_c_phi_dver=tf.Variable(tf.random_normal(
[nCells,nCells],mean=0.0,stddev=0.01))
bias_phi_dver=tf.Variable(tf.random_normal(
[nCells], mean=0.0, stddev=0.01))
# Cells weights (input, previous bidirectional outputs) and bias
w_i_c=tf.Variable(tf.random_normal(
[nInputFeatures,nCells],mean=0.0,stddev=0.01))
w_dhor_h_c=tf.Variable(tf.random_normal(
[nCells,nCells],mean=0.0,stddev=0.01))
w_dver_h_c=tf.Variable(tf.random_normal(
[nCells,nCells],mean=0.0,stddev=0.01))
bias_c=tf.Variable(tf.random_normal(
[nCells], mean=0.0, stddev=0.01))
# Output Gates weigths and bias weights (input, previous
bidirectional outputs, previous bidirectional states) and bias
w_i_o=tf.Variable(tf.random_normal(
[nInputFeatures,nCells],mean=0.0,stddev=0.01))
w_dhor_h_o=tf.Variable(tf.random_normal(
[nCells,nCells],mean=0.0,stddev=0.01))
w_dver_h_o=tf.Variable(tf.random_normal(
[nCells,nCells],mean=0.0,stddev=0.01))
w_c_o=tf.Variable(tf.random_normal(
[nCells,nCells],mean=0.0,stddev=0.01))
bias_o=tf.Variable(tf.random_normal(
[nCells], mean=0.0, stddev=0.01))
# Variable saving previous bidirectional outputs and states
# Each saves the batchSize x nCells outputs or states for the last
vertical element in the image
saved_output=tf.Variable(tf.zeros([1,nCells]),trainable=False)
saved_state=tf.Variable(tf.zeros([1,nCells]),trainable=False)
# Definition of the 2D-cell computation
def m2dlstm_cell(new_input,prev_out_v,
prev_out_h,prev_state_v,prev_state_h):
input_gate=tf.sigmoid(tf.matmul(new_input,w_i_iota)
+tf.matmul(prev_out_h,w_dhor_h_iota)
+tf.matmul(prev_out_v,w_dver_h_iota)
+tf.matmul(prev_state_h,w_dhor_c_iota)
+tf.matmul(prev_state_v,w_dver_c_iota)+bias_iota)
forget_horizontal_gate=tf.sigmoid(
tf.matmul(new_input,w_i_phi_dhor)
+tf.matmul(prev_out_h,w_dhor_h_phi_dhor)
37
37 Reconocimiento de Texto Manuscrito con Deep Learning
+tf.matmul(prev_out_v,w_dver_h_phi_dhor)
+tf.matmul(prev_state_h,w_dhor_c_phi_dhor)
+tf.matmul(prev_state_v,w_dver_c_phi_dhor)
+bias_phi_dhor)
forget_vertical_gate=tf.sigmoid(
tf.matmul(new_input,w_i_phi_dver)
+tf.matmul(prev_out_h,w_dhor_h_phi_dver)
+tf.matmul(prev_out_v,w_dver_h_phi_dver)
+tf.matmul(prev_state_h,w_dhor_c_phi_dver)
+tf.matmul(prev_state_v,w_dver_c_phi_dver)
+bias_phi_dver)
update=tf.matmul(new_input,w_i_c)
+tf.matmul(prev_out_h,w_dhor_h_c)
+tf.matmul(prev_out_v,w_dver_h_c)
state=input_gate*tf.tanh(update)
+prev_state_v*forget_vertical_gate
+prev_state_h*forget_horizontal_gate
output_gate=tf.sigmoid(tf.matmul(new_input,w_i_o)
+tf.matmul(prev_out_h,w_dhor_h_o)
+tf.matmul(prev_out_v,w_dver_h_o)
+tf.matmul(state,w_c_o))
output=output_gate*tf.tanh(state)
return output, state
# Outputs is a list of list of vertical elements which contain
bathcSize x nCells elements
prev_output_v=saved_output
prev_output_h=saved_output
prev_state_v=saved_state
prev_state_h=saved_state
output_column=list()
state_column=list()
for hInd in range(inputs.shape[2]): # Horizontal direction
for vInd in range(inputs.shape[1]): # Vertical direction
if(hInd!=0): #If is not the first vertical border,
prev_output_h=output_column[vInd]
prev_state_h=state_column[vInd]
output, state = m2dlstm_cell(inputs[:,vInd,hInd,:],
prev_output_v,prev_output_h,prev_state_v,prev_state_h)
prev_output_v=output
prev_state_v=state
if(hInd==0): # In the first column, create the list
Software
38
38
output_column.append(output)
state_column.append(state)
else: # In the rest of columns the elements are replaced
output_column[vInd]=output
state_column[vInd]=state
if(hInd==0): # In the first column, the outputs matrix is created
outputs=tf.concat([output_column],0)
else: # In the rest of the columns, the actual column is
concatenated with the previous ones.
outputs=tf.concat([outputs,output_column],0)
# Reshaping the outputs in order to have the same batchSize, width
and height that inputs.
outputs=tf.reshape(outputs,shape=[int(inputs.shape[2]),
int(inputs.shape[1]),-1,nCells])
# The matrix is transposed in order to have the same shape of the
input.
outputs=tf.transpose(outputs,perm=[2,1,0,3])
# Finally the images are reversed in the way they have been read
if(direction=='upward-forward'):
outputs=tf.reverse(outputs,[1])
elif(direction=='downward-backward'):
outputs=tf.reverse(outputs,[2])
elif(direction=='upward-backward'):
outputs=tf.reverse(outputs,[1,2])
return outputs
39
39 Reconocimiento de Texto Manuscrito con Deep Learning
6 CONFIGURACIÓN DE SERVIDOR CON
GPUS PARA DEEP LEARNING
n esta sección se expone detalladamente cómo preparar las herramientas hardware necesarias para poder
trabajar con algoritmos deep learning pudiendo ejecutar entrenamientos y evaluación en tiempos
razonables. Si se intenta ejecutar estos algoritmos en máquinas en las que los cálculos se realizan en la
CPU, la ejecución es muy lenta debido al tiempo necesario para los entrenamientos en dichas máquinas y por lo
tanto el número de pruebas que se pueden hacer está limitado por este factor.
Para ejecutar estos algoritmos hay varios proveedores como Amazon, Google y Microsoft que ofrecen entornos
de computación como servicios de pago. Los cálculos en estos servicios se realizan mediante computación en
paralelo siempre y cuando los cálculos de los algoritmos lo permitan, o mediante la computación en GPUs, que
es la tendencia actual que se está siguiendo.
Proveedores de GPUs para PCs como Nvidia están especializados en productos dedicados a la computación para
los algoritmos de inteligencia artificial, donde se incluyen los algoritmos deep learning analizados en este
trabajo. Existe una amplia gama de GPUs y actualmente continúan desarrollando nuevas configuraciones que
sean capaz de realizar más cálculos por segundo. El rendimiento de las GPUs se suele medir en TeraFLOPS
(Tera Floating-point Operations Per Second). En la siguiente figura se muestra una gráfica comparativa del
rendimiento de una GPU comparada con una CPU de 8 núcleos.
Figura 6-1. Comparación rendimiento GPU frente CPU. Fuente:
http://la.nvidia.com/object/quadro-3ds-max-la.html
Uno de los objetivos de la realización de este trabajo ha sido la adquisición y configuración de una máquina para
deep learning, que ha sido utilizada para la ejecución de algunos de los algoritmos presentados en capítulos
posteriores. Se ha configurado para que sirva como herramienta de trabajo multiusuario y con conexión remota.
A continuación se muestran los pasos que se han seguido para configurar la máquina que se ha adquirido. En
primer lugar, se exponen las características hardware de la misma y a continuación se muestra la configuración
software realizada.
E
Configuración de servidor con GPUs para deep learning
40
40
6.1 Características Hardware de la máquina
En la siguiente lista, se muestran las características más importantes de la máquina en lo relativo a la
computación:
Servidor ASUS ESC4000 G3
o 2 CPU Intel Xeon E5-2630 10 núcleos a 2.2 GHz.
o 2 GPU Nvidia Tesla P100 16 GB CoWoS.
o 128GB de memoria RAM DDR4
o 1 disco SSD 2TB para el sistema operativo y aplicaciones.
o 5 discos SATA de 2TB para almacenamiento de bases de datos.
o Controladora RAID SATA.
o Puerto Ethernet para conexión remota.
6.2 Configuración Software
Los pasos que se indican a continuación para la configuración software de la máquina se han extraído de diversas
fuentes y tutoriales que tratan de resolver múltiples problemas que aparecen durante la instalación de los
diferentes drivers, librerías y aplicaciones. En esta sección se encuentran todos los pasos organizados y
adaptados a la máquina en cuestión una vez han sido probados y verificados, ya que la mayoría de los manuales
consultados para esta tarea son genéricos y en muchos casos hay errores cuya solución no es trivial.
6.2.1 Instalación del sistema operativo Ubuntu 16.04.2 LTS
Se ha instalado la última versión estable a fecha 25/07/2017, descargada desde:
https://www.ubuntu.com/download/desktop
Se eligió en primera instancia el sistema operativo CentOS 7 debido a que se suponía un sistema más fiable y
seguro para un servidor de estas características. Sin embargo, se descartó finalmente por el escaso soporte que
se encontraba para la solución de los diferentes problemas que iban apareciendo durante la instalación. Por el
contrario, Ubuntu recibe un mayor soporte y múltiples soluciones a los problemas surgidos. En particular con
las tarjetas gráficas.
La máquina tiene varios puertos USB, por lo que la instalación del sistema operativo se ha realizado mediante
un dispositivo de memoria USB, siguiendo los siguientes pasos:
6.2.1.1 Crear USB bootable para la instalación desde la BIOS
En Windows descargar la aplicación Rufus para crear USB Booteable
https://rufus.akeo.ie/?locale
Insertar un USB drive y ejecutar Rufus.
41
41 Reconocimiento de Texto Manuscrito con Deep Learning
Figura 6-2. Configuración de Rufus para la creación de un USB drive instalador
del sistema operativo Ubuntu 16.04.w LTS
o En Dispositivo, elegir el USB drive insertado.
o En tipo de partición, elegir Tipo de partición MBR para BIOS o UEFI
o Sistema de archivos FAT32
o Seleccionar Formateo Rápido, Crear disco de arranque con, elegir imagen ISO y
buscar la imagen ISO de Ubuntu 16.04.2 LTS descargada.
o Clicar en Empezar.
Tras ello se crea el USB drive para la instalación.
6.2.1.2 Instalación del sistema operativo en el servidor
Insertar el USB drive en un puerto de la máquina objetivo y encenderla.
Acceder a la BIOS, pulsando <Supr> o <Remv> dependiendo del tipo de BIOS, consultar fabricante.
En la sección BOOT indicar que arranque desde la unidad USB, guardar cambios y salir.
Al reiniciar la máquina comienza el proceso de instalación de Ubuntu, seguir los pasos y configurar
particiones como se desee.
Configuración de servidor con GPUs para deep learning
42
42
6.2.2 Instalación de los Drivers Nvidia y librerías CUDA.
Ejecutar el siguiente comando para comprobar si el sistema reconoce las tarjetas GPU Nvidia instaladas
en el equipo:
La salida del comando anterior debe mostrar una línea por cada tarjeta nvidia instalada en la máquina.
En la máquina adquirida se tienen dos tarjetas Tesla P100 como se indicó en la sección de hardware.
Figura 6-3. Detección correcta de las tarjetas Nvidia por parte del sistema operativo.
Una vez comprobado que el sistema operativo reconoce las GPUs Nvidia intaladas en el equipo, se procede a
instalar los drivers. Este es uno de los pasos más complicados pues si se instalan los drivers directamente, se
deshabilita el modo gráfico del servidor y sólo se puede utilizar el modo por línea de comandos. Esto se debe a
incompatibilidades con la tarjeta gráfica primaria utilizada con dicho fin. Se pretende que las tarjetas GPUs
Nvidia se dediquen exclusivamente al cálculo. Para ello hay que seguir los siguientes pasos:
Acceder a http://www.nvidia.es/Download/index.aspx?lang=es .
Buscar los drivers para la tarjeta gráfica del equipo para el sistema operativo Linux 64-bit. (Hay una
versión para el sistema operativo Ubuntu 16.04.2 que es el instalado en la máquina, sin embargo dicho
instalador no permite el modo manual y por lo tanto surge el problema comentado anteriormente)
Figura 6-4. Búsqueda de controladores NVIDIA para Tesla P100 y SO Linux en la página del fabricante
$ lspci | grep -i nvidia
43
Se descarga un archivo llamado NVIDIA-Linux-x86_64-375.66.run donde “375.66” se corresponde
con la última versión estable en la fecha de la instalación.
A continuación se descargan las librerías CUDA que proporcionan una interfaz de alto nivel para poder
controlar las tarjetas Nvidia desde Python por ejemplo, para ello acceder a la página del fabricante
https://developer.nvidia.com/cuda-downloads. Y seleccionar el instalador tipo runfile(local) para
Ubuntu, como se muestra a continuación.
Figura 6-5. Búsqueda de librerías CUDA, instalador tipo runfile(local)
Se descarga un fichero llamado cuda_8.0.61_375.26_linux.run. Es importante que se descarguen tanto
los drivers como la librería CUDA en formato runfile, que permite la instalación manual de dichos
paquetes. Los paquetes en formato deb realizan la instalación de forma automática instalando los
paquetes necesarios para el adaptador de pantalla, provocando el problema del entorno gráfico.
Ejecutar los siguientes comandos para actualizar el sistema y necesarios para evitar los problemas del
entorno gráfico, (es necesaria la conexión a internet):
A continuación hay que salir del modo gráfico tecleando <Ctr>l + <Alt> + <F1>. Aparece el modo
terminal donde se pide un login. Hay que entrar con una cuenta de administrador.
Desactivar el entorno gráfico, hay varias opciones dependiendo de la versión del SO y el entorno gráfico
instalado. La que funciona en este caso es la siguiente:
$ sudo /etc/init.d/lightdm stop
$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install build-essential
$ echo blacklist nouveau option nouveau modeset=0 |sudo tee -a /etc/modprobe.d/blacklist-nouveau.conf
$ sudo update-initramfs -u
Configuración de servidor con GPUs para deep learning
44
44
Asegurarse que no hay ningún proceso gráfico corriendo, ya que la instalación aborta con un error en
dicho caso. Para ello teclear:
En el caso que aparezcan procesos X ejecutándose anotar el PID y cerrarlos con:
Una vez hecho esto se pueden instalar los drivers y las librerías CUDA sin problema. En primer lugar
los drivers ejecutando la siguiente orden en el directorio donde se encuentren los archivos runfile
descargados en pasos anteriores:
Es importante el parámetro --no-opengl-files que evita el error del entorno gráfico, si se instala de forma
automática no se puede deshabilitar la instalación de estos paquetes. Seguir los pasos indicados para la
aceptación de licencias y demás.
A continuación instalar las librerías CUDA de la misma forma que se hicieron los drivers:
Durante la instalación, aceptar las condiciones EULA, y decir NO a la pregunta sobre la instalación de
los drivers y sobre una pregunta sobre “Rebuild Xserver configurations with Nvidia”. El resto de
opciones aceptarlas.
Tras la instalación hay que añadir la ruta de las librerías CUDA a las variablesde entorno PATH y
LD_LIBRARY_PATH para que puedan ser encontradas por el resto de las aplicaciones:
Ya que se han instalado tanto los drivers como las librerías CUDA, se puede volver al entorno gráfico,
habilitándolo previamente y reiniciando la máquina.
(Opcional) Una vez se ha reiniciado el sistema, se pueden realizar las siguientes comprobaciones para
asegurarse que los drivers y las librerías se han instalado correctamente.
o Comprobar la versión instalada:
Se obtiene la siguiente salida, donde se comprueba que se ha instalado la versión 8.0 de las
librerias CUDA.
$ sudo ps –ax | grep X
$ kill -9 <PID>
$ sudo bash NVIDIA-Linux-x86_64-375.66.run –no-opengl-files
$ sudo bash cuda_8.0.61_375.26_linux.run –no-opengl-files
$ echo 'export PATH=/usr/local/cuda/bin:$PATH' >> ~/.bashrc $ echo 'export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH' >> ~/.bashrc $ source ~/.bashrc
$ sudo /etc/init.d/lightdm start
$ sudo reboot
$ nvcc -V
45
45 Reconocimiento de Texto Manuscrito con Deep Learning
Figura 6-6. Comprobación de versión de driver nvidia y librerías cuda instaladas
o Compilar y ejecutar algunos de los test de ejemplo que vienen por defecto al instalar las
librerías, (en el caso que se haya aceptado su instalación durante la instalación de las librerías
CUDA)
o Ejecutar el siguiente test que debe dar como resultado PASS, como se muestra en la ilustración:
Figura 6-7. Comprobación de que las GPUs y las librerías pasan el test “deviceQuery”
Una utilidad importante es la monitorización del rendimiento y uso de las GPUs mediante el comando
nvidia-smi. Al ejecutar el mismo debe dar una salida como la siguiente, donde aparece una tabla con
las dos GPUs del sistema, indicando parámetros como la temperatura en cada una de ellas, la energía
que están consumiendo, la memoria interna utilizada y disponible en cada una de ellas y el porcentaje
usado de la capacidad de cálculo que se dispone en cada una de ellas. También aparece una segunda
tabla donde se desglosan los procesos que se están ejecutando en cada una de ellas, indicando el PID,
en qué GPU se está ejecutando, el nombre de la aplicación que lo lanzó y la memoria interna ocupada
por cada una de ellas.
$ /usr/local/cuda/bin/cuda-install-samples-8.0.sh ~/cuda-samples $ cd ~/cuda-samples/NVIDIA_CUDA-8.0_Samples $ make -j $(($(nproc) + 1))
$ bin/x86_64/linux/release/deviceQuery
Configuración de servidor con GPUs para deep learning
46
46
Figura 6-8. Monitorización de las GPUs Nvidia.
Una opción importante es ejecutar el comando nvida-smi con el parámetro -lms seguido de un número
que indica el periodo en milisegundos en el que se muestra la la monitorización, para comprobar
continuamente si las GPUs están funcionando correctamente. Ejemplo:
6.2.3 Instalación de las librerías cuDNN
Las librerías cuDNN son unas librerías auxiliares a CUDA que proporcionan algunas herramientas para el
desarrollo de redes neuronales. Estas librerías son necesarias para algunos frameworks de Python como pueden
ser tensorflow y theano. En el caso de tensorflow, cuando se pretende instalar la versión tensorflow-gpu, si no
se tienen instaladas estas librerías aparece un error y se aborta la instalación. Para instalar dichas librerías seguir
los siguientes pasos:
Descargar las librerías de https://developer.nvidia.com/cudnn para ello hay que registrarse. Es
necesaria la versión 5.1 actualmente para theano y tensorflow. La más reciente es la versión 6.0, pero
no es compatible con la última versión de theano y tensorflow.
Descargar en formato tar.gz.
Durante la realización de este se descargó como cudnn-8.0-linux-x64-v5.1.solitairetheme. Hubo que
cambiar la extensión a tar.gz manualmente con el comando.
Importante: si se descarga en formato tar.gz no hace falta el paso anterior.
Descomprimir el tar.gz
A continuación se hace la instalación manual, copiando las librerías cuDNN en los directorios donde se
instalaron las librerías CUDA.
$ nvidia-smi –lms 200
$ mv ./cudnn-8.0-linux-x64-v5.1.solitairetheme \ ./cudnn-8.0-linux-x64-v5.1.tar.gz
$ tar xvf ./cudnn-8.0-linux-x64-v5.1.tar.gz
47
47 Reconocimiento de Texto Manuscrito con Deep Learning
Resaltar de nuevo que se ha instalado la versión cuDNN 5.1 haber comprobado que es única compatible con las
versiones actuales de theano y tensorflow. Si al instalar posteriormente theano y tensorflow aparece un error
indicando que no se encuentran estas librerías indicando un número concreto de versión, es necesario instalar
dicha versión.
6.2.4 Instalación de paquetes python necesarios para machine learining y deep learning
Ejecutar como root:
Instalar pip, que es el gestor de instalaciones de python
Instalar tensorflow en su versión para GPU:
Comprobar que funciona:
Instalar theano:
Establecer la variable THEANO_FLAGS como float32, ya que actualmente CUDA no soporta float64:
Comprobar que funciona:
Una vez llegados a este punto se tiene configurada la máquina para trabajar con algoritmos de machine learning
y deep learning con python sobre GPUs, así como las herramientas para el control de las mismas. Se han
instalado los paquetes python fundamentales necesarios, si se necesita alguno nuevo sólo hay que instalarlo con
el comando pip install seguido del nombre del paquete. A partir de ahora cualquier desarrollador que quiera
$ cd cuda $ sudo cp */*.h /usr/local/cuda/include/ $ sudo cp */libcudnn* /usr/local/cuda/lib64/ $ sudo chmod a+r /usr/local/cuda/lib64/libcudnn*
# apt-get update && apt-get install -y python-numpy python-scipy python-nose \ python-h5py python-skimage python-matplotlib \ python-pandas python-sklearn python-sympy # apt-get clean && sudo apt-get autoremove # rm -rf /var/lib/apt/lists/*
$ sudo apt-get install python-setuptools $ sudo apt install python-pip
$ sudo pip install tensorflow-gpu
$ python >> import theano >> exit()
$ python >> import tensorflow as tf >> exit()
$ sudo apt-get install g++ python-pygments python-sphinx $ sudo pip install theano
$ export THEANO_FLAGS=’floatX=float32’
Configuración de servidor con GPUs para deep learning
48
48
utilizar dicha máquina sólo tiene que preocuparse de los algoritmos y el código de alto nivel. Es decir, se evita
que el desarrollador/investigador tenga que enfrentarse a problemas hardware y de configuración software del
equipo.
Las siguientes configuraciones que se han hecho al equipo están dedicadas a la seguridad de los datos, el acceso
remoto y la seguridad en los mecanismos de conexión al equipo.
6.2.5 Gestión de los discos
Como se indicó en la Sección 6.1 la máquina se compone de 1 disco SSD de 2 TB para el sistema operativo y
aplicaciones y 5 discos HDD de 2 TB cada uno. Además, la máquina dispone de una controladora RAID SATA
que permite la configuración de los discos en espejo, conocido como RAID 1. El objetivo es tener la información
duplicada. Se han utilizado 4 de los discos HDD y se han emparejado 2 a 2, por lo que finalmente se tienen un
total de 3 discos HDD virtuales de 2 TB cada uno de ellos, estando los dos primeros duplicados físicamente. El
tercer disco se utiliza para copias de seguridad del sistema.
Figura 6-9. Configuración RAID 1. (Fuente: Wikipedia)
En el manual del servidor [20], se explica detalladamente como realizar la configuración paso a paso. Se han
seguido dichas instrucciones y la configuración ha tenido éxito. Esta configuración se realiza desde la BIOS.
Una vez configurados, los discos se han montado en el sistema ejecutando los siguientes comandos:
Por lo tanto se tienen dos discos de 2 TB para almacenamiento en /media/HDD1 y /media/HDD2, y un disco de
2 TB en /backup para realizar copias de seguridad.
$ mkdir /media/HDD1 /media/HDD2 /backup $ sudo mount \ /dev/mapper/ddf1_4c53492020202020808627c3000000004711471100001e78 \ /media/HDD1 $ sudo mount \ /dev/mapper/ddf1_4c53492020202020808627c30000000047114711000028a0 \ /media/HDD2 $ sudo mount /dev/sdf /backup
49
49 Reconocimiento de Texto Manuscrito con Deep Learning
6.3 Conexión remota
Para la conexión remota al equipo se han instalado Teamviewer para conexión a escritorio remoto, un servidor
SSH para la conexión al terminal y un servidor x2go para la conexión al escritorio remoto vía SSH. Se han
considerado otras alternativas, como puede ser un servidor VNC. Se ha preferido Teamviewer y x2go debido a
consideraciones de seguridad.
6.3.1 Instalación del servidor SSH:
El servidor SSH no viene instalado por defecto con el sistema operativo, hay que instalarlo ejecutando:
6.3.2 Instalación de teamviewer
Para instalar teamviewer primero hay que descargarlo desde https://www.teamviewer.com/es/ . Desde
Ubuntu se descarga un paquete con formato “deb”.
Instalarlo siguiendo las siguientes instrucciones desde el directorio donde se haya descargado el
paquete:
Iniciarlo:
Una vez iniciado ya se puede conectar remotamente desde cualquier equipo que tenga instalado
Teamviewer. Por motivos de seguridad no se indican el ID ni la contraseña en este documento.
6.3.3 Instalación de x2go
Instalar el servidor x2go en la máquina mediante la ejecución de los siguientes comandos:
Para la conexión remota desde cualquier dispositivo es necesario instalar y configurar x2goclient en el
mismo, siguiendo los siguientes pasos:
o Descargar cliente X2GO para el Sistema Operativo local: http://wiki.x2go.org/doku.php
o Una vez instalado clicar en <Nueva Sesión> y en la ventana de configuración introducir los
siguientes valores.
$ sudo apt-get install ssh
$ sudo dpkg -i <paquete.deb> $ sudo apt-get install –f $ sudo systemctl restart teamviewerd.service
$ teamviewer
$ apt-get update $ apt-get install python-software-properties $ add-apt-repository ppa:x2go/stable $ sudo apt-get install x2goserver x2goserver-xsession $ apt-get install xfce4 $ reboot
Configuración de servidor con GPUs para deep learning
50
50
Figura 6-10. Ventana de configuración de sesión en x2goclient
En “Nombre de sesión:” establecer un nombre para la sesión.
En “Host:” Introducir la IP del servidor.
En “Usuario:” Introducir el nombre de usuario que debe existir en la máquina. Solicitar al
administrador.
En “Puerto SSH:” Introducir el puerto del servidor SSH (Por motivos de seguridad no se
indica en este documento).
En “Tipo de sesión:” Establecer XFCE, que es la que se ha instalado en el servidor
Es posible que se solicite la instalación de un servidor gráfico en la máquina.
o En MAC OS X, se suele solicitar la instalación de XQuartz, instalarlo siguiendo los pasos
indicados. Aparece esta ventana cuando se solicite la conexión:
51
51 Reconocimiento de Texto Manuscrito con Deep Learning
Figura 6-11. Solicitud de instalación XQuartz
o Clicar en el enlace que nos lleva a la página de descarga de Xquartz.
Figura 6-12. Descarga XQuartz para Mac OS X
o Instalar el paquete descargado y ejecutar XQuartz.
o Añadir /Applications/Utilities/XQuartz.app en la sección Aplicación X11 de la ventana de
configuración de la sesión, en el caso de que no se añada automáticamente.
o Reiniciar el equipo.
Configuración de servidor con GPUs para deep learning
52
52
6.3.4 Configuraciones de seguridad
Debido a la habilitación de conexión remota mediante SSH y teamviewer, aparece la vulnerabilidad de la
conexión al servidor por parte de atacantes informáticos, en el caso de que obtengan un par usuario/clave. Para
evitar esta situación se ha configurado el servidor mediante firewall IPTABLES de Ubuntu para que sólo se
permitan las conexiones desde las IPs dentro de una Red Privada Virtual (VPN), que permite la conexión desde
cualquier punto geográfico al servidor.
Además, se ha configurado el puerto SSH del servidor para que no utilice el puerto por defecto 22. El puerto
configurado no se indica en este documento por motivos de seguridad. También se ha configurado para que el
usuario root no pueda conectarse por SSH.
Antes de realizar la fortificación de seguridad del servidor tomando las medidas mencionadas, se llevaron a cabo
comprobaciones de seguridad, donde se detectó que debido a que el servidor está configurado con una IP pública
y situado en la Universidad, estaba recibiendo continuamente intentos de conexión remota por personal o
máquinas no autorizados.
6.3.5 Resolución de la pantalla para escritorio remoto
Por defecto, el SO Ubuntu instalado ofrece una resolución de pantalla máxima de 800 x 600 a la hora de elegir
la misma en la configuración del sistema. En el caso de que se conecte una pantalla al puerto VGA, sí que se
adapta a la resolución de la pantalla conectada, pero no es el caso ya que el servidor en producción está instalado
en una sala de servidores y la única opción es la conexión remota.
Para solucionar esto hay que editar el archivo de configuración de la resolución de pantalla, siguiendo las
siguientes indicaciones:
Ejecutar el comando xrandr para comprobar el rango de resoluciones que admite la tarjeta de video
primaria del sistema.
Ejecutar el comando: gtf <x> <y> <r> para generar el modeline de la resolución deseada, donde <x>
es la resolución horizontal, <y> la vertical y <r> la tasa de refresco en hertzios. En la siguiente figura
se muestra la generación del modeline para una resolución de 1720x1173 píxeles a una frecuencia de
refresco de 60 Hz.
A continuación, editar o crear el fichero /usr/share/X11/xorg.conf.d/10-monitor.conf escribiendo las
siguientes líneas. Sólo hay que modificar las recuadradas: en la primera copiar la línea que se obtuvo
con el comando gtf; en la segunda seleccionar la etiqueta que precede a connected en la salida del
comando xrandr; y en la tercera sustituir por la resolución deseada.
Figura 6-13. Generación de modeline para una resolución de 1720 x 1173 @ 60 Hz.
53
53 Reconocimiento de Texto Manuscrito con Deep Learning
Finalmente reiniciar el equipo y automáticamente se aplicará la resolución configurada al inicio de la sesión en
el entorno gráfico. Si no funciona el entorno gráfico es porque hay algo mal configurado, basta con eliminar el
fichero anterior desde el terminal.
Figura 6-14. Fichero /usr/share/X11/xorg.conf.d/10-monitor.conf para una resolución 1920x1173.
55
7 APLICACIÓN A RECONOCIMIENTO DE
NÚMEROS
Una vez revisados los diferentes algoritmos de deep learning y las herramientas software disponibles para su
implementación se procede a la realización de experimentos sobre bases de datos ampliamente conocidas para
la transcripción de manuscritos.
En este capítulo se trabaja con la base de datos MNIST, que contiene dígitos manuscritos (0 – 9) extraídos de
una base de datos de mayor dimensión llamada NIST. Está compuesta por dos conjuntos, uno de entrenamiento
con un total de 55000 imágenes y otro de test con un total de 10000.
Es una base de datos preparada para probar algoritmos de aprendizaje máquina de reconocimiento de patrones,
resolviendo problemas de clasificación multiclase.
Cada muestra de la base de datos se compone de un vector de características a la entrada de 784 valores
correspondientes con el nivel de gris de los distintos píxeles de la imagen. Se trata de imágenes de 28x28 píxeles,
pero de la base de datos se extrae directamente como un vector de 784 valores. Si se desea trabajar con imágenes
hay que redimensionar el vector y transformarlo en una matriz de 28x28. Como salida se proporciona un vector
de diez posiciones, que toma el valor 1 en la posición correspondiente al dígito que aparece en la imagen y 0 en
el resto de posiciones. Por lo tanto, se trata de un problema de clasificación multiclase con un total de 10 clases.
Figura 7-1. Ejemplos base de datos MNIST. (Fuente [21])
7.1 Modelo con perceptrón multicapa
En la Sección 3.2 se explicó la estructura de las redes neuronales artificiales o perceptrón multicapa. A partir de
Aplicación a Reconocimiento de Números
56
56
los datos extraídos de la base de datos del MNIST se puede aplicar este tipo de estructuras directamente. La
primera red neuronal que se propone consiste en tomar como capa de entrada el vector formado los 784 valores
de los píxeles y tomar como salida 10 neuronas, donde el valor proporcionado por cada una de ellas se interpreta
como la probabilidad de que la imagen de entrada se corresponda con cada una de las 10 clases posibles.
v
Figura 7-2. Red neuronal propuesta en este ejemplo.
La expresión matemática que toma la estructura es la siguiente:
�̂� = 𝜎(𝑾𝒙 + 𝒃) (7–1)
Donde,
𝜎(): función de activación sigmoidal
𝑥: vector que contiene el valor de los píxeles de la imagen, tamaño [784,1]
𝑊: matriz de pesos, tamaño [784,10]
𝑏: vector de bias aplicado a cada neurona de salida, tamaño [10,1]
�̂�: vector que contiene las probabilidades de cada dígito calculadas por la red neuronal, tamaño [10,1]
[�̂�1
⋮�̂�10
] = 𝜎 ([
𝑊1,1 ⋯ 𝑊1,784
⋮ ⋱ ⋮𝑊784,1 ⋯ 𝑊784,784
] [
𝑥1
⋮𝑥784
] + [𝑏1
⋮𝑏10
])
(7–2)
Finalmente se aplica una función de coste a minimizar conocida como entropía cruzada,
57
57 Reconocimiento de Texto Manuscrito con Deep Learning
𝐿(𝑤) = −1
𝑁∑[𝒚(𝑛) log(�̂�(𝑛)) + (1 − 𝒚(𝑛))log (1 − �̂�(𝑛))]
𝑁
𝑛=1
(7–3)
donde 𝒚(𝑛) y �̂�(𝑛) son el vector de etiquetas reales extraídas de la base de datos y el vector de probabilidades
de etiquetas estimado respectivamente, para la muestra 𝑛.
Se utiliza un optimizador de descenso de gradiente conocido como Optimizador de Adam, que toma como
argumento la función de coste indicada y trata de minimizarla.
Del mismo modo se evalúa la precisión del aprendizaje promediando el número de aciertos entre el conjunto de
evaluación.
Como se indicó en la sección 5.1, en Tensorflow primero se configura un grafo con la red neuronal deseada
donde se muestran las dependencias entre parámetros para posterior realización del entrenamiento. El grafo que
se ha creado en este caso se puede ver en la Figura 7-3, obtenido de la utilidad TensorBoard.
Figura 7-3. Grafo creado para el entrenamiento MNIST con ANN.
Una vez se ha creado el grafo se realiza un entrenamiento con el conjunto de entrenamiento proporcionado por
la base de datos MNIST. Se puede ver la curva de la evolución de la función de coste evaluada sobre el conjunto
de entrenamiento y el conjunto de test en la Figura 7-4.
Aplicación a Reconocimiento de Números
58
58
Figura 7-4. Evaluación de la función de coste a lo largo del entrenamiento de una red ANN sobre el problema
MNIST. (Conjunto de entrenamiento azul, conjunto de test naranja)
Del mismo modo, se puede observar la evaluación de la precisión del aprendizaje tanto en el conjunto de test
como en el conjunto de entrenamiento en la Figura 7-5. La precisión de aprendizaje (accuracy) se mide como:
𝐶𝑃(𝑦(𝑛), �̂�(𝑛)) = {1, 𝑦(𝑛) = �̂�(𝑛)
0, 𝑦(𝑛) ≠ �̂�(𝑛)
(7–4)
𝐴𝐶𝐶 =1
𝑁∑ 𝐶𝑃(𝑦(𝑛), �̂�(𝑛))
𝑁
𝑛=1
(7–5)
Figura 7-5. Evaluación de la precisión del aprendizaje de una red ANN sobre el problema
MNIST (Conjunto de entrenamiento azul, conjunto de test naranja)
Con esta estructura, se consigue una precisión de aprendizaje del 92.5% cuando se evalúa sobre el conjunto de
test.
59
59 Reconocimiento de Texto Manuscrito con Deep Learning
7.2 Modelo con redes neuronales convolucionales
Como ya se comentó en la Sección 3.3, cuando se trata de problemas de aprendizaje automático aplicados a
imágenes, las redes neuronales convolucionales proporcionan información contextual 2D que en las redes
neuronales artificiales MLP no se tienen en cuenta. Se comprueba en esta sección como con una red neuronal
convolucional sencilla se consiguen mejorar los resultados obtenidos en el aprendizaje sobre la base de datos
MNIST.
La red convolucional que se propone se puede observar en la Figura 7-6. La primera parte consiste en
redimensionar el vector de píxeles de entrada en una matriz (imagen) de 28x28. Esta imagen se pasa por una
capa convolucional compuesta por 32 filtros en 2D de 5x5. Tras ello se aplica un filtrado de pooling de 2x2,
resultando en 32 matrices de características de 14x14. Después se aplica una segunda capa convolucional de 64
filtros de 5x5 de nuevo, y una nueva fase de pooling, resultando finalmente en un conjunto de 64 matrices de
7x7. Los 64x7x7 valores a la salida de esta capa se transforman en un vector que se conectan completamente a
las 10 neuronas de salida de la red, proporcionando las probabilidades de las 10 posibles etiquetas al igual que
en el caso anterior.
Figura 7-6. Red neuronal convolucional propuesta en la Sección 7.2.
La formulación de cada capa es como sigue:
1. La primera capa convolucional compuesta por 32 filtros 5x5 obtiene su salida mediante la expresión:
ℎ𝑐𝑜𝑛𝑣1(𝑙) (𝑖, 𝑗) = 𝑅𝑒𝐿𝑈 ( ∑ ∑ 𝑤𝑐𝑜𝑛𝑣1𝑚,𝑛
(𝑙) 𝑥(𝑖 + 𝑚, 𝑗 + 𝑛) + 𝑏𝑐𝑜𝑛𝑣1(𝑙)
𝑛=2
𝑛=−2
𝑚=2
𝑚=−2
)
(7–6)
Donde el índice 𝑙 = 1, . . ,32 representa la capa de salida, y los índices 𝑖 = 0, … ,27 y 𝑗 = 0, … ,27
representan la posición dentro de cada una de las capas. "𝑤" representa el conjunto de 32x5x5
parámetros entrenables de los filtros. "𝑏" representa los 32 sesgos entrenables, uno por cada neurona
convolucional. Finalmente, se le aplica la función de activación ReLu.
2. La salida de la primera capa de pooling se define con la ecuación:
Aplicación a Reconocimiento de Números
60
60
ℎ𝑝𝑜𝑜𝑙1(𝑙)
(𝑖, 𝑗) = max (ℎ𝑐𝑜𝑛𝑣1(𝑙)
(2𝑖, 2𝑗), ℎ𝑐𝑜𝑛𝑣1(𝑙)
(2𝑖 + 1,2𝑗), ℎ𝑐𝑜𝑛𝑣1(𝑙)
(2𝑖, 2𝑗 + 1), ℎ𝑐𝑜𝑛𝑣1(𝑙)
(2𝑖 + 1,2𝑗
+ 1))
(7–7)
Donde de nuevo el índice 𝑙 = 1, … ,32 indica la matriz de salida de salida y en este caso 𝑖 = 0, … ,13 y
𝑗 = 0, … ,13 representa la posición dentro de cada una de las capas de salida.
3. La salida de la segunda capa convolucional se define con la ecuación:
ℎ𝑐𝑜𝑛𝑣2(𝑙)
(𝑖, 𝑗) = 𝑅𝑒𝐿𝑢 ( ∑ ∑ ∑ 𝑤𝑐𝑜𝑛𝑣2𝑚,𝑛(𝑙) ℎ𝑝𝑜𝑜𝑙1
(𝑘,𝑙)(𝑖 + 𝑚, 𝑗 + 𝑛) + 𝑏𝑐𝑜𝑛𝑣2
(𝑙)
32
𝑘=1
𝑛=2
𝑛=−2
𝑚=2
𝑚=−2
)
(7–8)
Donde el índice 𝑙 = 1, . . ,64 representa la capa de salida, 𝑘 representa el índice de cada una de las capas
de entrada a esta capa y los índices 𝑖 = 0, … ,13 y 𝑗 = 0, … ,13 representan la posición dentro de cada
una de las capas. "𝑤" representa el conjunto de 64x5x5x32 parámetros entrenables de los filtros. "𝑏"
representa los 64 bias entrenables, uno por cada neurona convolucional. Finalmente, se le aplica la
función de activación ReLu.
4. Se vuelve a aplicar una capa de pooling a la salida de la segunda capa convolucional:
ℎ𝑝𝑜𝑜𝑙2(𝑙) (𝑖, 𝑗) = max (ℎ𝑐𝑜𝑛𝑣2
(𝑙) (2𝑖, 2𝑗), ℎ𝑐𝑜𝑛𝑣2(𝑙) (2𝑖 + 1,2𝑗), ℎ𝑐𝑜𝑛𝑣2
(𝑙) (2𝑖, 2𝑗 + 1), ℎ𝑐𝑜𝑛𝑣2(𝑙) (2𝑖
+ 1,2𝑗 + 1))
(7–9)
5. Finalmente se aplica la capa de salida que devuelve las probabilidades de cada una de las 10 etiquetas
posibles:
�̂� = 𝜎(𝑾𝒉𝒑𝒐𝒐𝒍𝟐 + 𝒃) (7–10)
Donde, 𝒉𝒑𝒐𝒐𝒍𝟐 es la matriz tridimensional de 64x7x7 que se ha transformado en un vector de 3136x1, 𝑾
es la matriz de pesos entrenables de la capa ANN de salida de dimensión 10x3136, y 𝒃 es el vector de
bias de la capa ANN de salida, de dimensión 10x1. A esta última capa se le aplica la función de activación
sigmoidal 𝜎.
Cuando se crea el grafo en TensorFlow, se puede visualizar con TensorBoard como se muestra en la Figura 7-7
61
61 Reconocimiento de Texto Manuscrito con Deep Learning
Figura 7-7. Grafo creado para MNIST con CNN.
Una vez creado el grafo, se realiza el entrenamiento y evaluación de la misma forma que se realizó en la sección
anterior para la red ANN, obteniendo los siguientes resultados:
La curva de la función de coste a lo largo del entrenamiento, se puede ver en la Figura 7-8.
Aplicación a Reconocimiento de Números
62
62
v
Figura 7-8. Evaluación de la función de coste a lo largo del entrenamiento de una red CNN sobre el
problema MNIST. (Conjunto de entrenamiento azul, conjunto de test naranja)
Se puede observar, comparando con la Figura 7-4, que la función de coste tiende a 0 en un número de iteraciones
menor que la red ANN, tanto como para el conjunto de entrenamiento como para el conjunto de evaluación. Si
se evalúa ahora la precisión del aprendizaje, en la Figura 7-9 se puede observar como en el conjunto de
entrenamiento tiende rápidamente al 100% de precisión, mientras que en el conjunto de test se llega a un 99.3%
de precisión, que mejora notablemente el 92.5% conseguido con la estructura de la sección anterior.
v
Figura 7-9. Evaluación de la precisión del aprendizaje de una red CNN sobre el problema MNIST
(Conjunto de entrenamiento azul, conjunto de test naranja)
63
63 Reconocimiento de Texto Manuscrito con Deep Learning
7.3 Modelo con MDLSTM
Para finalizar con la base de datos de MNIST se ha aplicado una estructura que contiene capas MDLSTM. La
estructura que se implementa es propuesta por Alex Graves en [8] y estudiada por Vu-Pham et al. en [4],
modificando el número de neuronas y tamaño de los filtros de las redes convolucionales así como la inclusión
de técnicas de dropout en algunas capas. Esta estructura está pensada y estudiada para clasificación temporal,
sin embargo, se puede aplicar a problemas de clasificación como MNIST interpretando cada grupo de píxeles
como un símbolo/etiqueta de la secuencia.
También se indica en [8] que la base de datos MNIST puede ser el punto de partida para probar nuevos
algoritmos, ya que debido a la dimensión de las imágenes, no ofrece muchas complicaciones en lo que se refiere
a la carga computacional.
La estructura con capas MDLSTM que se prueba en este ejemplo se puede ver en la Figura 7-10.
Figura 7-10. Red neuronal convolucional propuesta en la Sección 7.3.
En esta Figura, al igual que en el modelo con CNN en el que se trabaja en 2D, en primer lugar hay que
transformar el vector de entrada en una imagen de 28x28 píxeles. En segundo lugar, se puede tomar un píxel
por elemento de la secuencia, (a la entrada se tendría una secuencia de 784 elementos de una característica que
es el valor del píxel) o agruparlos para que cada elemento tenga más características, en [4] se propone dividir la
imagen en bloques de 2x2 píxeles, por lo que en cada instante temporal se tendría un elemento con 4
características a la entrada. En esta sección se prueban ambos casos. A continuación, se aplica una capa
MDLSTM de 2 neuronas, que recorren la imagen en las 4 direcciones que ofrece el caso 2D. Por lo tanto, se
tienen 4 capas independientes cada una de ellas con 2 neuronas. Tras ello, se aplica una capa convolucional de
profundidad 6, sumando las 4 proporcionadas y aplicando una función de activación de tangente hiperbólica. Se
repite esta estructura de capa MDLSTM seguida de una capa convolucional una vez más, pero en este caso con
20 neuronas en el caso de la MDLSTM y 20 neuronas en el caso de la convolucional. Finalmente se aplica una
tercera capa MDLSTM de 100 neuronas cuya salida se transforma en un vector de dimensión 4900x1, al que se
le aplica una última capa ANN, resultando a la salida las probabilidades de las 10 etiquetas posibles, como se
hizo en los casos anteriores.
Entre las capas MDLSTM y CNN se aplica Dropout, con una probabilidad que depende del experimento
Aplicación a Reconocimiento de Números
64
64
realizado.
A continuación, se exponen los resultados obtenidos para los distintos experimentos realizados con esta
estructura.
7.3.1 Estructura sin dividir los datos a la entrada en bloques de 2x2 píxeles y sin Dropout
Con esta estructura se consigue una precisión de aprendizaje, evaluada sobre el conjunto de test de 97.96 %.
7.3.2 Estructura dividiendo los datos a la entrada en bloques de 2x2 píxeles y sin Dropout
Con esta estructura se consigue una precisión de aprendizaje, evaluada sobre el conjunto de test de 98.8%.
7.3.3 Estructura dividiendo los datos a la entrada en bloques de 2x2 píxeles y con probabilidad de Dropout de 0.5
Con esta estructura se consigue una precisión de aprendizaje, evaluada sobre el conjunto de test de 99.23 %.
7.3.4 Estructura dividiendo los datos a la entrada en bloques de 2x2 píxeles y con probabilidad de Dropout de 0.2
Con esta estructura se consigue una precisión de aprendizaje, evaluada sobre el conjunto de test de 99.12 %.
7.4 Comparativa
Tabla 7-1 Resultados sobre la base de datos MNIST
Tipo de estructura ANN
CNN MDLSTM
(Mejor caso,
Sección 7.3.3)
Nº
iter
acio
nes
40.000 92.5% 99.3% 97.64%
80.000 92.5% 99.3% 97.89%
120.000 92.5% 99.3% 99.2%
160.000 92.5% 99.3% 99.23%
Se comprueba en este caso que la estructura propuesta en [8] no mejora la precisión del aprendizaje con respecto
a la estructura de CNN presentada en la sección anterior, y además necesita de un 400% más de iteraciones para
aprender, debido a la complejidad de la estructura.
Debido a que en este problema se alcanzan precisiones de aprendizaje muy altas, es difícil proponer estructuras
que mejoren esta situación, los errores cometidos en la evaluación pueden deberse a circunstancias varias que
pueden depender de este problema específico. La potencia de las redes neuronales MDLSTM se prueba en
problemas más complicados como la clasificación temporal que se estudia en las siguientes secciones
65
8 APLICACIÓN A RECONOCIMIENTO DE
PALABRAS
En este Capítulo se aplican las herramientas estudiadas para la clasificación temporal, utilizando la base de datos
IAM, que es una base de datos de textos manuscritos en inglés. Como se trata de un problema de etiquetado de
secuencias, herramientas como las redes neuronales con memoria y la capa CTC empiezan a jugar un papel
importante.
8.1 Base de datos del IAM
La base de datos de textos manuscritos IAM [1] está basada en páginas de texto manuscrito en inglés y se puede
utilizar para el entrenamiento y evaluación de algoritmos para el reconocimiento de textos manuscritos.
La base de datos contiene páginas de texto manuscrito sin restricciones en inglés, escaneadas a una resolución
de 300 dpi y almacenadas en formato PNG con 256 niveles de gris. En la Figura 8-1 se puede observar un
ejemplo de una página escaneada de las incluidas en la base de datos IAM.
Figura 8-1. Ejemplo de página completa base de datos IAM. (Fuente [1])
Además, la propia base de datos proporciona líneas, frases y palabras extraídas de las páginas escaneadas, todas
en formato PNG, lo que permite trabajar a nivel de línea y de palabra directamente. En la Figura 8-2 se puede
observar un ejemplo de línea extraída mientras que en la Figura 8-3 se pueden observar varios ejemplos de
palabras.
Aplicación a Reconocimiento de Palabras
66
66
Figura 8-2. Ejemplo de línea extraída de una página de la base de datos del IAM mediante
segmentación. (Fuente [1])
Figura 8-3. Ejemplo palabras extraídas base de datos IAM mediante segmentación. (Fuente
[1])
Las transcripciones se proporcionan en la base de datos en de dos formas, o bien en formato ASCII o bien en
formato XML. En formato ASCII se tienen cuatro ficheros forms.txt, lines.txt, sentences.txt y words.txt,
correspondientes con meta-información de las páginas completas, la segmentación a nivel de líneas, de frase y
de palabras respectivamente. En esta Sección se ha trabajado a nivel de palabras, por lo que se va a explicar este
caso. En la Sección 9 se ha trabajado a nivel de línea y el fichero correspondiente sigue una estructura similar.
67
67 Reconocimiento de Texto Manuscrito con Deep Learning
Figura 8-4. Extracto del archivo words.txt base de datos IAM. (Fuente [1])
En la Figura 8-4 se puede observar un extracto del fichero words.txt. El mismo está compuesto por una cabecera
que explica la información que contiene y a continuación una serie de líneas. Cada línea se corresponde con la
imagen de una palabra y comienza con un nombre compuesto por 4 códigos separados por guiones, ese nombre
se corresponde con la secuencia de directorios que hay que seguir dentro de la base de datos para localizar la
imagen a la que se refiere la etiqueta, luego una serie de información donde se destaca un parámetro que puede
tomar los valores “ok” o “err” indicando si la palabra se ha segmentado bien o mal y la transcripción de la palara.
Con respecto a los archivos en formato XML se incluye un archivo por cada página escaneada, cuyo nombre
está compuesto por dos secuencias alfanuméricas separadas por guiones, que se corresponden con los dos
primeros directorios dentro de la base de datos de palabras.
Cada fichero XML está compuesto por un elemento raíz <form> que contiene meta información en forma de
atributos. Este elemento está compuesto por dos elementos hijos llamados <machine-printed-part> y
<handwritten-part>. El elemento <handwritten-part> está compuesto por un elemento hijo <line> por cada línea
y estos a su vez por elementos hijos <word> por cada palabra dentro de la línea. En la Figura 8-5 se puede ver
un ejemplo.
Aplicación a Reconocimiento de Palabras
68
68
Figura 8-5. Extracto de un archivo XML de la base de datos IAM. (Fuente [1])
Finalmente se obtiene la transcripción de cada palabra en un atributo llamado “text” del elemento <word>
comentado anteriormente.
Para poder trabajar con esta base de datos en TensorFlow es necesario extraer el par imagen-etiqueta de la misma
y transformarlo al formato Numpy para poder trabajar con ella en formato matricial. Con respecto a las etiquetas,
también es necesario definir un diccionario para mapear cada carácter posible con un número de neurona de la
capa de salida de la red neuronal. En el caso de la base de datos MNIST, hay un total de 10 neuronas de salida,
una por cada dígito decimal. En este caso se tiene un total de 26 etiquetas posibles, correspondientes con las
letras en minúscula. Se eliminan de la detección los signos de puntuación, que sí se incluyen en la Sección 9.
Se han encontrado varias dificultades a la hora de adaptar los datos de esta base de datos para poder trabajar con
ellos en TensorFlow:
Hay imágenes cuyos archivos tienen un formato desconocido o corrupto y no se pueden leer.
Solución aportada: en el archivo words.txt no se indican las dimensiones de la imagen como “-1 -1 -1
-1” se han descartado las imágenes tengan esta forma.
Hay imágenes que se corresponden con un único píxel, y no se puede aplicar CTC a dichas imágenes,
ya que la secuencia de entrada al CTC debe tener longitud mínima L=2.
Solución aportada: se han descartado todas las imágenes tras leerla y comprobar que su tamaño es un
píxel.
Hay imágenes de la base de datos correspondientes con palabras mal segmentadas o etiquetadas.
Solución aportada: se indica en el fichero “words.txt” las palabras que se han segmentado
incorrectamente con el parámetro err. Se han desechado dichas imágenes, aunque se siguen detectando
imágenes con algún carácter mal etiquetado.
Se han implementado funciones para manejar la base de datos del IAM. El siguiente código pertenece a un script
llamado load_IAM_data.py donde el autor del trabajo ha implementado tres módulos, uno para extraer las
transcripciones a nivel de línea, otra que extrae las transcripciones a nivel de palabra y un módulo que realiza el
rellenado con ceros para que todas las imágenes tengan un mismo tamaño a la hora de ser procesados por una
red neuronal.
69
69 Reconocimiento de Texto Manuscrito con Deep Learning
from lxml import etree
import os
import numpy as np
import math
# Indicate path were you saved the IAM database lines and xml folder
INPUT_PATH = './lines/'
LABEL_PATH = './xml/'
def load_labeled_lines(path):
"Este módulo extrae líneas completas de la base de datos del
IAM, extrae en un vector el contenido de cada línea”
line_array=np.empty([])
print("Loading data")
for xml_file in os.listdir(path):
print("Loading file %s" % xml_file)
doc=etree.parse(os.path.join(path,xml_file))
root=doc.getroot()
for index in range(len(root[1])):
new_line=np.array(root[1][index].get('text'))
line_array=np.vstack((line_array,new_line))
line_array=np.delete(line_array,0,axis=0)
return line_array
def data_to_numpy(list_set_path,input_path,label_path):
"Este modulo transforma la base de datos IAM compuesta por
imagenes (palabras segmentadas) y documentos xml con las
etiquetas en arrays numpy. Recibe tres parametros,
list_set_path: la ruta del fichero donde se listan los
nombres de las imagenes del set en cuestion. input_path: la
ruta del directorio donde se encuentran las imagenes en
formato png. label_path: la ruta del directorio donde se
encuentran los ficheros xml con las etiquetas"
inputs=[]
targets=[]
seqLengths=[]
# Se abre el fichero donde se listan las imagenes a cargar
contest_list_file=open(list_set_path,'r')
# Se almacenan los nombres de las imagenes
xml_lines=contest_list_file.readlines()
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
import string
alphabet={} # Se crea un alfabeto para los diferentes caracteres
# Conjunto de caracteres que se van a transcribir
Aplicación a Reconocimiento de Palabras
70
70
chars=string.ascii_lowercase
for ind in range(len(chars)): # Se mapean los caracteres a indices
alphabet[chars[ind]]=ind
for ind in range(len(xml_lines)): # Para cada linea del fichero
donde se listan las lineas
current_line=xml_lines[ind] # Se obtiene el nombre de la linea
# Con esta estructura se obtiene el nombre del fichero xml
path_xml=current_line[:(len(current_line)-4)]+'.xml'
print(path_xml)
# se crea un objeto con los datos xml para trabajar con ellos
xml_file=etree.parse(os.path.join(label_path,path_xml))
# Se obtiene el elemento raiz para poder acceder a todos
los demás
root=xml_file.getroot()
# Dentro del documento xml se accede a cada una de las lineas
que tiene
for index in
range(len(root[1][int(current_line[(len(current_line)-
3):(len(current_line)-1)])])):
# Cuando la informacion de la linea contenga una
palabra...
if(root[1][int(current_line[(len(current_line)-
3):(len(current_line)-1)])][index].tag=='word'):
# Se obtiene el identificador que coincide con el
nombre del fichero que contiene la imagen
id=root[1][int(current_line[(len(current_line)-
3):(len(current_line)-1)])][index].get('id')
# Se construye el nombre del fichero que contiene
la imagen png
path_img=id[:3]+'/'+id[:(len(current_line)-
4)]+'/'+id+'.png'
# Se obtiene la etiqueta
new_word=root[1][int(current_line[(len(
current_line)-3):(len(current_line)-
1)])][index].get('text')
# Se eliminan los símbolos que no sean letras
for char in
string.punctuation+string.
digits+string.whitespace:
new_word=new_word.replace(char,'')
new_word=str.lower(new_word)
if(new_word!=''): #Solo se añaden las imágenes que
contienen caracteres (algunas son
vacías o signos de puntuación)
# Se obtiene la imagen
71
71 Reconocimiento de Texto Manuscrito con Deep Learning
image=mpimg.imread(os.path.join(input_path,
path_img))
# Se eliminan las imagenes grandes (esto se
puede eliminar en el futuro)
if np.array(image).shape[0]<100 and
np.array(image).shape[1]<400 and
np.array(image).shape[1]>65:
inputs.append(np.array(image))
# Se crea la etiqueta vacia para sustituir los
caracteres por indices
target=np.zeros([len(new_word)])
# Con el bucle se mapean las etiquetas a
secuencias de digitos
for l in range(len(new_word)):
target[l]=alphabet[new_word[l]]
seqLength=np.array(image).shape[1]
targets.append(target)
seqLengths.append(seqLength)
contest_list_file.close() # Finalmente se cierra el fichero
return (inputs,targets,seqLengths)
def padding_data(train_set,validation_set,test_set):
"Este módulo realiza un rellenado de ceros en las imágenes para
que todas tengan el mismo tamaño a la hora de ser procesadas
por redes neuronales, en primer lugar detecta el tamaño
máximo de las imágenes y finalmente realiza el padding”
maxDim1=0;
maxDim2=0;
# Detección del tamaño máximo en las imágenes
for image in train_set:
maxDim1 = max(maxDim1,image.shape[0])
maxDim2 = max(maxDim2,image.shape[1])
print('After train shape')
print(maxDim1,maxDim2)
for image in validation_set:
maxDim1 = max(maxDim1,image.shape[0])
maxDim2 = max(maxDim2,image.shape[1])
print('After validation shape')
print(maxDim1,maxDim2)
for image in test_set:
maxDim1 = max(maxDim1,image.shape[0])
maxDim2 = max(maxDim2,image.shape[1])
print('After test shape')
print(maxDim1,maxDim2)
# Tamaño con dimension par para poder dividir en bloques 2x2
maxDim1=math.ceil(maxDim1/8)*8
Aplicación a Reconocimiento de Palabras
72
72
maxDim2=math.ceil(maxDim2/32)*32
# Relleno de las imagenes para que tengan todas el mismo tamaño
for index in range(len(train_set)):
padDim1=maxDim1-train_set[index].shape[0]
padDim2=maxDim2-train_set[index].shape[1]
train_set[index]=np.pad(train_set[index],
((0,padDim1),(0,padDim2)),'constant', constant_values=1)
print('Train padded')
for index in range(len(validation_set)):
padDim1=maxDim1-validation_set[index].shape[0]
padDim2=maxDim2-validation_set[index].shape[1]
validation_set[index]=np.pad(validation_set[index],
((0,padDim1),(0,padDim2)),'constant', constant_values=1)
print('Validation padded')
for index in range(len(test_set)):
padDim1=maxDim1-test_set[index].shape[0]
padDim2=maxDim2-test_set[index].shape[1]
test_set[index]=np.pad(test_set[index],
((0,padDim1),(0,padDim2)),'constant', constant_values=1)
return maxDim1,maxDim2
Con los módulos programados en el script anterior, se obtienen los datos en TensorFlow para poder aplicar
directamente estructuras formadas por redes neuronales incluidas en la API de TensorFlow, además de la capa
MDLSTM también programada por el autor del trabajo.
8.2 Modelo con redes neuronales convolucionales
En primer lugar y previo a la implementación de la capa MDLSTM, se ha propuesto resolver este problema de
clasificación temporal mediante redes neuronales convolucionales como extractor de características y etiquetado
mediante CTC. Para ello se ha propuesto una red neuronal que se puede visualizar en la Figura 8-6. Esta
estructura está compuesta por una primera capa convolucional de 20 neuronas compuesta por filtros 2x4, a su
salida se conecta otra capa convolucional de 50 neuronas y filtros 2x4 al igual que la primera. Con esto se extraen
las características que tras colapsar en un vector de 1250x1 para cada instante temporal, se transforman en
probabilidades mediante una capa MLP que tiene 1250 neuronas de entrada y 27 neuronas de salida, una por
cada carácter del abecedario inglés más uno para el blank necesario para el CTC. A la entrada se tienen imágenes
correspondientes con palabras que se han obtenido de la base de datos del IAM. Para el ejemplo realizado las
imágenes tienen una dimensión igual a la mayor de las seleccionadas para realizar dicho entrenamiento, 100
píxeles de alto por 400 de ancho. Los 400 píxeles de ancho se mantienen hasta la capa CTC, ya que se interpreta
como el eje temporal. La capa CTC es la encargada de mapear cada píxel a lo ancho de la imagen en un carácter
del abecedario o el carácter especial blank, detectando así la palabra manuscrita en la imagen.
73
73 Reconocimiento de Texto Manuscrito con Deep Learning
Figura 8-6. Red neuronal convolucional propuesta en la Sección 8.2.
Como se explicó en la Sección 2.2, para el problema de etiquetado de secuencias la evaluación del aprendizaje
se realiza mediante una función de error denominada distancia editada normalizada de Levenshtein que mide el
número mínimo de inserciones, sustituciones y eliminaciones que hay que hacer en una secuencia a para que
sea igual que una secuencia b.
Tras evaluar el sistema propuesto mediante dicha función de error, se comprueba que no ha podido aprender
pues en el entrenamiento la función evaluada se ha quedado lastrada en un valor de 𝐸𝑅 = 5.3. Este dato puede
llamar la atención, pues normalmente la función de error se encuentra entre 0 y 1, siendo 1 un 100% de error.
Sin embargo, en el problema de clasificación temporal mediante la capa de CTC, se mapea una secuencia de
entrada de longitud T en una secuencia de etiquetas de longitud L<T, y para promediar el error utilizando la
distancia normalizada de Levenshtein se divide entre L. En el caso de que haya más caracteres detectados que
caracteres tenga la palabra y la mayoría de caracteres sea erróneo, la distancia normalizada de Levenshtein ya
es mayor que uno. El resultado obtenido del error ER = 5.3 está indicando por tanto que en una secuencia se
están detectando más de 5 veces el número de caracteres reales que tiene la transcripción. Por lo tanto, el sistema
no está aprendiendo bien.
Se comprueba por lo tanto que la resolución de un problema con capas convolucionales y CTC no funciona bien
cuando se aplica a imágenes de entrada con distorsión.
8.3 Modelo con BI-LSTM
En esta sección se propone un esquema que incluye capas con memoria como las explicadas en la Sección 3.5
y 3.6. El esquema propuesto en esta sección tiene a la entrada imágenes de palabras de la base de datos IAM, a
la que se le aplica una capa LSTM bidireccional de 128 neuronas sobre el eje temporal, que se corresponde con
el ancho de la imagen. En cada instante de tiempo, las características con las que se alimenta esta capa LSTM
bidireccional es un vector formado por el valor de los píxeles a lo largo de la dimensión vertical de la imagen.
A la salida de esta capa se tiene por lo tanto un conjunto de 128 características por cada instante temporal, que
se conectan a una capa MLP de 27 neuronas al igual que en el caso de la Sección anterior, una neurona por cada
carácter del abecedario inglés más una neurona para el carácter especial blank. La salida de cada una de estas
neuronas indica en cada instante temporal la probabilidad de ocurrencia de cada carácter, que es la entrada de la
capa CTC la cual se encarga del etiquetado de la secuencia.
Aplicación a Reconocimiento de Palabras
74
74
Figura 8-7. Esquema propuesto en la Sección 8.3.
En la Figura 8-7 se puede ver gráficamente el esquema propuesto. Evaluando el conjunto de test, con este
esquema se consigue una tasa de error ER=0.4447 evaluando la distancia editada normalizada de Levenshtein.
Se puede observar que en este caso el sistema consigue aprender, y se consigue una tasa de error mayor que la
obtenida por sistemas estudiados por varios autores en la actualidad cuyos resultados se pueden ver en la Figura
8-8, donde Vu-Phan et al. [4] comparan su esquema basado en capas MDLSTM con varios autores (las
referencias que aparecen en dicha tabla se deben consultar en [4]). El parámetro que hay que comparar en este
caso es el CER (Character Error Rate) en el conjunto de evaluación. En el esquema implementado en esta
Sección es CER=44.47%.
Figura 8-8. Tabla de resultados obtenidos por diversos autores. (Fuente [4]. Ver referencias de
la tabla en [4].)
En la figura anterior se puede comprobar que en el esquema propuesto en [4] basado en capas MDLSTM
75
75 Reconocimiento de Texto Manuscrito con Deep Learning
multidireccionales y aplicando dropout para evitar sobreajuste en el entrenamiento se consigue una de las
mejores tasas de error hasta la actualidad. Esto se puede observar en la parte superior de la tabla representada en
la figura, donde CER=5.1. Motivados por estos resultados en la siguiente sección se propone emular la estructura
propuesta en dicho artículo [4].
8.4 Modelo con MDLSTM
En esta sección se propone replicar la estructura propuesta en [4] para la base de datos IAM. Es una estructura
similar a la que se sigue en la sección 7.3 para la base de datos MNIST. Se compone de 3 pares de capas
MDLSTM + convolucionales, una capa MLP para calcular las probabilidades y finalmente la capa CTC para la
detección de la secuencia. Se aplica dropout entre las capas MDLSTM y las convolucionales. La Figura 8-9
extraída de [4] muestra gráficamente la estructura que se pretende implementar.
Figura 8-9. Estructura propuesta en [4]. (Fuente [4]).
Esta estructura se ha programado en TensorFlow al igual que el resto, utilizando las capas de redes neuronales
que vienen en la API de TensorFlow excepto la capa MDLSTM que fue programada por el autor de este trabajo
en la sección 5.2.
No se ha podido ejecutar esta estructura debido a que requiere de recursos de memoria que exceden de los
disponibles en el laboratorio. Estos recursos se deben a la capa MDLSTM, la cual requiere el cálculo del
gradiente en cada uno de los píxeles de la imagen de entrada mediante el algoritmo BPTT [8]. El problema que
surge se debe a la memoria necesaria para almacenar todos los parámetros necesarios, donde el mayor peso lo
tienen los gradientes calculados. En el caso de la base de datos MNIST con imágenes de 28x28 se necesitan
unos 20 GB de memoria RAM cuando se crea el grafo en TensorFlow, de los cuales 3 GB aproximadamente
son ocupados por los parámetros de la red y los 17 GB restantes almacenan los gradientes, por lo tanto, se pudo
realizar el entrenamiento. Sin embargo, en el caso de las imágenes IAM de una dimensión 100x400 se necesitan
inicialmente 40 GB para el almacenamiento de los parámetros, mientras que la reserva de memoria para los
gradientes llegó a saturar los 128 GB de memoria RAM disponible. Por lo tanto, no ha sido viable.
Tras ello se han hecho esfuerzos para investigar una implementación más eficiente de la capa MDLSTM. Ya se
ha explicado en el párrafo anterior que los problemas de memoria se deben al cálculo de gradientes. En
TensorFlow, el cálculo del gradiente se separa de la definición de la estructura y se encuentra embebido dentro
del optimizador. Una posible solución pasa por una modificación de dicho optimizador para tratar el cálculo de
gradientes de los parámetros de la capa MDLSTM de forma distinta que los del resto de capas.
En [6] y [19] se mencionan los problemas de memoria que surgen en la programación de las capas MDLSTM
con APIs de alto nivel como pueden ser TensorFlow o Theano. Estos autores proponen la implementación a
bajo nivel de dichas capas directamente con librerías CUDA, con las que se puede controlar directamente el
hardware.
Dichos autores han programado un framework para facilitar la implementación de estructuras con redes
Aplicación a Reconocimiento de Palabras
76
76
neuronales donde incluyen la capa MDLSTM programada con librerías CUDA. Este framework está disponible
públicamente en [22]. En la siguiente Sección se realiza la aplicación al reconocimiento de líneas sobre la base
de datos del IAM utilizando y adaptando dicho framework.
Indicar que las pruebas de las Secciones 7 y 8 se han realizado previamente a la adquisición del hardware con
GPUs explicado en la Sección 6 y del hallazgo del framework publicado en [22]. Por lo tanto, los entrenamientos
se han realizado sobre equipos que disponen de una capacidad computacional inferior y el número de pruebas
que se pueden hacer ha estado limitado. En la Sección 9 se utiliza la máquina que se configuró en la Sección 6.,
que tiene disponibles 2 tarjetas GPU.
77
9 APLICACIÓN A RECONOCIMIENTO DE
LÍNEAS
Este Capítulo es una evolución del anterior donde se aplicaron los algoritmos estudiados al reconocimiento de
palabras sobre la base de datos IAM. En este caso se aplica al reconocimiento de líneas sin necesidad de
segmentarlas en palabras. Para ello se utiliza una implementación más eficiente de las capas MDLSTM, ya que
la usada en el Capítulo anterior satura en memoria e impide el aprendizaje. En este capítulo se utiliza el
framework propuesto en [22] donde implementan las capas MDLSTM directamente sobre librerías CUDA y,
por lo tanto, se tiene un control sobre los recursos utilizados de las GPUs. Ya se ha comentado que durante una
gran parte de la realización de este trabajo no se hallaba la capa MDLSTM programada públicamente, y en las
secciones anteriores se utilizó la implementada por el autor de este trabajo. Otros autores han realizado intentos
en su implementación, pero actualmente la más eficiente y estable es la de estos autores [22].
El framework propuesto en [22] está programado en Python, utilizando tanto Tensorflow como Theano. Tiene
implementadas algunas partes directamente sobre CUDA, entre las que se encuentra la capa MDLSTM.
Para configurar y ejecutar un entrenamiento con dicho framework, sólo hay que editar un fichero de
configuración y pasarlo como parámetro al fichero principal rnn.py. Dicho fichero se encarga de llamar al resto
de módulos que se encargan de configurar la red neuronal sobre las GPUs o CPUs según se indique en el fichero
de configuración, establecer el formato de los registros del avance en la ejecución, ubicar los directorios de
entrada y salida, entre otras cosas. Todo ello se puede controlar desde el fichero de configuración.
Sin embargo, la documentación existente sobre las diferentes opciones de configuración no es muy amplia y
salvo los aspectos básicos, los autores indican que para conocer el resto de opciones hay que analizar el código.
Entre los parámetros a configurar, se puede elegir si la ejecución va a ser un entrenamiento o una evaluación, el
tamaño de los batches, el número de epochs, el número de secuencias que se pueden evaluar a la vez, la ruta de
los ficheros donde se encuentran las imágenes y las etiquetas y la red a configurar.
Figura 9-1. Ejemplo de fichero de configuración para rnn.py.
En la Figura 9-1 se muestra un archivo de configuración de ejemplo para el framework. Entre otros parámetros
Aplicación a Reconocimiento de Líneas
78
78
se indica que la tarea a realizar va a ser un entrenamiento, se indican los datos para el conjunto de entrenamiento
y el conjunto de validación. El número de entradas y salidas. También se indica que se entrena con batches
aleatorios, y la red que se implementa, compuesta por una capa LSTM de 500 neuronas llamada fw0 y una capa
de salida llamada output a la que se le aplica la función de pérdidas cross-entropy ya mencionada anteriormente.
Utilizando este framewok se han entrenado y comparado dos estructuras: la primera de ellas se corresponde con
la de la Sección 8.4 y la segunda es una estructura más compleja propuesta en [19].
9.1 Modelo compuesto por 3 capas MDLSTM - convolucional
En esta sección se aplica la misma red neuronal que en la Seccón 8.4 se aplicó a la detección de palabras sobre
la base de datos del IAM. Se implementa sobre el framework programado en [22], donde se edita un fichero de
configuración del entrenamiento para que se implemente esta red. El conjunto de entrenamiento se compone
5545 imágenes correspondientes con segmentaciones a nivel de línea extraídas de la base de datos del IAM,
como la que se muestra en la Figura 8-2. Como conjunto de validación se toman 616 imágenes de la misma base
de datos, pero es un conjunto disjunto del anterior tanto en el contenido como en el autor. Finalmente se toma
un conjunto de test compuesto por 2772 imágenes disjunto de los dos conjuntos anteriores.
Figura 9-2. Esquema propuesto en la Sección 9.1.
Se entrena la red aplicando un dropout de 0.25 % de probabilidad en las neuronas MDLSTM. A la salida se
tienen 79 caracteres posibles, en lugar de los 27 que se tenían en la Sección anterior donde solamente se tenían
en cuenta las letras del alfabeto inglés sin diferenciar mayúsculas y minúsculas. En esta sección se diferencian
mayúsculas, minúsculas, números, algunos signos de puntuación y los espacios en blanco. A los 79 caracteres
posibles se le añade uno más para tener en cuenta el símbolo especial blank necesario para la decodificación
mediante la capa CTC.
El entrenamiento se realiza a partir de las 5545 imágenes del conjunto de entrenamiento, en cada iteración se
expone a la red neuronal a un minibatch de 10 imágenes y se actualizan los pesos mediante el optimizador de
Adam. Cada vez que se hace una pasada a las 5545 imágenes se dice que ha transcurrido un epoch y se evalúa
el conjunto de validación. En la Figura 9-3 se muestra la evaluación del error en los 50 epochs que dura el
entrenamiento, evaluados sobre el test de validación. Cada epoch se ejecuta en 1h 55min, por lo que el
entrenamiento ha tardado en total unas 100 h. aproximadamente.
79
79 Reconocimiento de Texto Manuscrito con Deep Learning
Figura 9-3. Evolución del Character Error Rate (CER) durante el entrenamiento en el modelo
propuesto en la Sección 9.1.
Se observa en la Figura 9-3 que el error evaluado en el conjunto de validación al final del entrenamiento es
CER=16.13%. Se ha evaluado el error sobre un conjunto de test obteniéndose un error de CER=17.87%. El error
medido es el Character Error Rate cuyo cálculo se indica en la Sección 2.2, y utiliza la distancia editada de
Levenshtein. Si se compara con los resultados obtenidos por otros autores expuestos en la Figura 8-8, se
comprueba que se acerca a los resultados obtenidos por los mismos. Se ha tratado de implementar la estructura
denominada MDLSTM-RNN + Dropout en la tabla que aparece en dicha figura, donde los autores [4] alcanzan
un CER=7.4% para el conjunto de validación y un CER =10.8% en el conjunto de test. Hay que de analizar la
causa de que no se alcance la misma tasa de error que en [4], aunque se haya tratado de entrenar la misma
estructura. Se puede deber a la complejidad de la red, y de ciertos parámetros internos que no se han indicado
por los autores y por lo tanto no se han tenido en cuenta.
En la Sección 9.2 se utiliza una estructura más compleja propuesta en [19], mejorando estos resultados.
9.2 Modelo compuesto por 5 capas convolucional-LSTM
En esta sección se entrena una de las redes neuronales propuestas en [19], que sigue la misma estructura de los
ejemplos anteriores. Aunque en este caso el bloque elemental se compone de una capa convolucional seguido
de una capa MDLSTM en las 4 direcciones, cuando hasta ahora se han estudiado estructuras en las que el orden
era el contrario. Además, debido a la eficiencia en ejecución de la implementación software utilizada, se pueden
entrenar redes neuronales con mayor profundidad, como se explica en [22]. Dichos autores proponen varios
modelos y el que mejores resultados consigue es el compuesto por 5 capas convolucionales y 5 capas MDLSTM
intercaladas, realizando la decodificación mediante la capa CTC. Se realiza el entrenamiento de esta estructura
utilizando los mismos conjuntos de entrenamiento, validación y test que se utilizaron en la sección anterior.
Aplicación a Reconocimiento de Líneas
80
80
Figura 9-4. Esquema propuesto en la Sección 9.2.
El entrenamiento de esta red se realiza en las mismas condiciones que las indicadas en la Sección anterior.
Aunque el modelo tiene más capas y parámetros que entrenar que el modelo anterior, el tiempo de ejecución de
cada epoch es también de 2h aproximadamente.
Figura 9-5. Evolución del Character Error Rate (CER) durante el entrenamiento en el modelo
propuesto en la Sección 9.2. Comparativa frente al error del modelo de la sección anterior.
81
81 Reconocimiento de Texto Manuscrito con Deep Learning
Se observa en la Figura 9-4 que el error evaluado en el conjunto de validación al final del entrenamiento es
CER=5.7% que mejora el CER=16.13% conseguido con la estructura de la Sección anterior. Se ha evaluado el
error sobre conjunto de test obteniéndose un error de CER=8.8%.
9.2.1 Análisis de la salida de la capa CTC
Se puede observar el efecto de la capa de salida CTC antes de realizar la decodificación. Para ello se toma un
ejemplo de transcripción del conjunto de test utilizado en este experimento. En la parte superior de la Figura 9-6
se muestra la evaluación log-posterior que indica el logaritmo de la probabilidad de los 80 caracteres evaluado
en cada uno de los 40 píxeles de salida de la red neuronal antes de la capa CTC. Se muestran en color las curvas
de los caracteres que tienen mayor probabilidad. Si se compara con el texto manuscrito que se pretende
transcribir en la parte inferior de la Figura 9-6, se observa cómo la probabilidad de cada carácter que aparece en
la imagen es mayor cuando se encuentra en la posición del carácter al que se corresponde en el texto manuscrito.
También se puede comprobar la diferencia entre lo que es un espacio en blanco, que aparece una vez en esta
línea, y el carácter especial blank, que aparece en varios instantes a lo largo de la línea para indicar la separación
entre las letras.
Figura 9-6. Salida de la capa CTC tras la transcripción de una línea del conjunto de test.
9.2.2 Análisis de la transcripción de un párrafo
Del mismo modo, se puede analizar el funcionamiento de la red neuronal una vez entrenada mediante la
transcripción de un párrafo (línea a línea) a partir de la misma. Se pretende transcribir la página escaneada
mostrada en la Figura 9-7, que ha sido extraída de la base de datos IAM.
Aplicación a Reconocimiento de Líneas
82
82
Figura 9-7. Imagen escaneada extraída de la base de datos IAM.
En la Tabla 9-1 se muestra la transcripción generada por la red neuronal entrenada en esta Sección junto con de
la transcripción “correcta” proporcionada por la base de datos, segmentada línea a línea y marcando en rojo los
errores de sustitución de caracteres y en naranja los errores de inserción. En este ejemplo no ha habido ningún
error de eliminación. El número de errores totales por línea se muestra en la columna de la derecha. Si se analizan
los errores se puede comprobar que en este ejemplo la mayoría se corresponden al carácter “a” que la red
neuronal decide que es una “o”. Además, si se observa el error de la tercera línea donde la transcripción
“correcta” facilitada indica que la cuarta palabra es “mutual”, y la red neuronal la ha transcrito como “mutuel”,
por lo que habría un error. Sin embargo, si se observa la imagen de partida, se ve claramente que la letra que
aparece es una “e”. Lo mismo ocurre con la cuarta línea, donde la transcripción facilitada indica que la segunda
palabra es “whether”, mientras que la red la ha transcrito como “wether”. De nuevo, si se observa la imagen, la
palabra que aparece es “wether”, por lo que la red neuronal la ha transcrito bien, la errónea es la transcripción
facilitada por la base de datos. Sería conveniente para el futuro analizar este tipo de errores a la hora de medir la
tasa de error de la red neuronal, ya que se deberían tener en cuenta y comprobar si la red neuronal es sensible a
ellos. También se puede analizar el uso de un corrector léxico del lenguaje en cuestión para comprobar si se
reduce el error.
En la Tabla 9-2 se calculan el número total de errores en la transcripción de dicho párrafo, el número total de
caracteres y el cociente que marca el Character Error Rate.
83
83 Reconocimiento de Texto Manuscrito con Deep Learning
Tabla 9-1. Transcripción de la imagen de la Figura 9-7 mediante la red neuronal de la Sección 9.2
Transcripción Errores por línea
Sociol service os o function of government
Social service as a function of government
3
was quite alien to medioeral thought - its
was quite alien to mediaeval thought - its
2
substitute was the mutuel self-help of
substitute was the mutual self-help of
1
communities , whether those communities were
communities , whether those communities were
1
monosteries , monors , townstips , or words ond
monasteries , manors , townships , or wards and
5
guilds of o city . A medioeral tox was
guilds of a city . A mediaeval tax was
4
therefore in essence a forced poyment whose
therefore in essence a forced payment whose
1
return was the uncertoin bounty of booty
return was the uncertain bounty of booty
1
and the rague advantages of military glory ;
and the vague advantages of military glory ;
1
it was therefore alwoys gronted grudgingly
it was therefore always granted grudgingly
2
and coupled with the rain hope that , in the
and coupled with the vain hope that , in the
1
Tabla 9-2. Resultados de la evaluación de la transcripción de la Figura 9-7.
Errores totales: (sustituciones, inserciones o eliminaciones) 22
Caracteres: 496
Character Error Rate (CER) 4.4 %
Aplicación a Reconocimiento de Líneas
84
84
9.3 Comparativa
Una vez entrenados ambos modelos, se evalúa la transcripción que realizan ambas redes neuronales sobre el
conjunto de test para comprobar el error. El resultado de la evaluación del error se muestra en la Tabla 9-3. Se
indica el error en ambas redes neuronales para los conjuntos de evaluación y de validación.
Tabla 9-3. Comparativa error redes neuronales aplicadas a reconocimiento de líneas.
CER
Estrucutura Valid Eval
3 capas 16.13% 17.87 %
5 capas 5.7 % 8.8 %
El error obtenido por la estructura de la Sección 9.2 se aproxima a las tasas de error alcanzadas por los autores
de [4], representados en la tabla de la Figura 8-8. Se mejora el CER=10.8% obtenido con la estructura que
proponen previo a utilizar un corrector léxico. Cuando utilizan el corrector léxico, mejoran el error a una tasa
CER=5.1%. Se puede investigar en este aspecto en el futuro para comprobar qué tasa de error se consigue
aplicando un corrector léxico a esta estructura.
85
10 CONCLUSIONES Y TRABAJO FUTURO
En este trabajo, se ha abordado el problema de reconocimiento de texto manuscrito mediante deep learning.
Para ello se ha analizado el tipo de problema correspondiente dentro del aprendizaje máquina. Tras ello, se ha
realizado una exposición teórica de los distintos algoritmos que se utilizan para resolver este tipo de tareas, se
ha analizado el software disponible para su implementación y finalmente se han aplicado los conocimientos
adquiridos a dos bases de datos de referencia: MNIST para el reconocimiento de dígitos manuscritos como
problema de clasificación multiclase; y la base de datos IAM para el reconocimiento de palabras y líneas en
inglés, siendo este un problema de clasificación temporal.
Con respecto al tipo de tarea, el reconocimiento de textos manuscritos se encuentra dentro de los problemas de
clasificación temporal, que es un subtipo dentro de los de etiquetado de secuencias. Es una tarea que deriva del
clásico problema de clasificación o reconocimiento de patrones, pero en lugar de asignar una etiqueta a cada
dato de entrada, en este caso hay que asignar a cada dato de entrada una secuencia de etiquetas de longitud
desconocida, lo que dificulta la tarea en gran medida.
Se han expuesto varias técnicas para la resolución de este tipo de problemas con redes neuronales. Estas técnicas
permiten tener en cuenta la dependencia temporal entre los elementos de una secuencia a la entrada y aprovechan
esta información para realizar el etiquetado. Una de las técnicas propuestas ha sido la utilización de capas
MDLSTM que tienen en cuenta la dependencia contextual de varias dimensiones, que en el caso de las imágenes
se trata de dos. La implementación de este tipo de capas ha sido una de las tareas más importantes de este
proyecto, pues actualmente no se encuentra implementada públicamente para su utilización dentro de los marcos
de trabajo más extendidos en Python. Se ha comprobado que la implementación realizada no escala con el
tamaño de los datos de entrada, ya que, para su entrenamiento se utilizan algoritmos más complejos que los
utilizados para las redes neuronales del tipo MLP o convolucionales. Esto se debe a la dependencia temporal
que necesita ser almacenada en memoria. Por lo tanto, es necesario investigar en una programación más eficiente
a bajo nivel, que considere la gestión de la memoria.
Otro punto importante tratado en este trabajo ha sido la capa CTC para el etiquetado de secuencias en el problema
de clasificación temporal. Esta capa proporciona una solución para el caso de que se tengan secuencias de salida
de longitud desconocida. Además, este tipo de capas ya se encuentran implementadas en TensorFlow y la única
complicación encontrada se ha debido a su integración con las redes neuronales, que finalmente se ha podido
resolver.
Una de las conclusiones obtenidas tras la realización de este trabajo ha sido la apreciación de que los algoritmos
de deep learning basados en redes neuronales dependen de muchos parámetros, y una ligera modificación en
alguno de ellos provoca unos resultados distintos cuando se intenta medir la precisión del aprendizaje. Existe
cierta dificultad a la hora de tratar de emular estructuras estudiadas por otros autores, pues normalmente no se
indica el valor de todos los parámetros en la documentación aportada y por lo tanto se dificulta la obtención de
los mismos resultados.
Una vez se ha realizado el análisis de las técnicas actuales para resolver problemas de reconocimiento de textos
manuscritos con redes neuronales, y se han configurado las herramientas hardware y software para poder realizar
pruebas, se ha procedido a evaluar distintas estructuras.
La línea a seguir en el futuro, toma como punto de partida el software propuesto en [22] debido a que,
actualmente, realizan una implementación muy eficiente de la capa MDLSTM, conseguida tras un profundo
análisis a bajo nivel. Se intenta adoptar dicho framework a las necesidades del proyecto, y se tratará de resolver
el problema aplicando directamente la red neuronal a párrafos completos sin necesidad de segmentar.
Finalmente, una vez se dominen todas las técnicas de deep learning de forma teórica y práctica, se procederá a
su aplicación para la conservación del patrimonio histórico. Se tratará de aplicar las estructuras estudiadas al
problema concreto de la transcripción de textos manuscritos antiguos del Archivo General de Indias.
87
REFERENCIAS
[1] U.-V. Marti y H. Bunke, «The IAM Database: an english sentence database for offline handwritting
recognitio,» Int Journal on Document Anal. and Recognition, vol. 5, nº 1, pp. 39-46, 2002.
[2] A. Graves y J. Schmidhuber, «Offline handwritting recognition with multidimensional recurrent nerual
networks,» Advances in Neural Information Proccesing Systems, pp. 545-552, 2008.
[3] E. ElAbed y G. H, «ICDAR 2009 Handwriting recognition competition,» International Conference on
Document Analysis and Recognition, 2009.
[4] V. Pham, T. Bluche, C. Kermorvant y J. Louradour, «Dropout improves Recurrent Neural Networks for
Handwriting Recognition,» de Int. Conf. on Frontiers in Handwiting Recognition, 2014.
[5] D. Ciresan, U. Meier y J. Schmidhuber, «Multi-column Deep Neural Networks for Image
Classification,» Idsia/USI-SUPSI, 2012.
[6] P. Voigtlaender, P. Doetsch, S. Wiesler, R. Schluter y H. Ney, «Sequence-Discriminative Training of
Recurrent Neural Networks,» de In Acustics Speech and Signal Procesing (ICASSP) IEEE International
Conference, 2015.
[7] C. Bishop, Pattern Recognition and Machine Learning, 2006.
[8] A. Graves, Supervised Sequence Labelling with Recurrent Nerual Networks, Munich: Technical
University Munich, 2008.
[9] A. Graves, S. Fernandez, F. J. Gomez y J. Schmidhuber, «Connectionist temporal classification:
labelling unsegmented sequence data wih recurrent neural networks,» de Proc. of the Int. Conf. on Mach.
Learning (ICML),, 2006.
[10] D. Boeree y C. George, «General Psycology,» [En línea]. Available:
http://webspace.ship.edu/cgboer/genesp/neuronas.html.
[11] K. Horkink, M. Stinchcombe y H. White, Multilayer feedforward networks are universal approximators.,
1989.
[12] C. Bishop, Neural Networks for Pattern Recognition, Chapter 6, Oxford University Press, Inc, 1995.
[13] Wikipedia, «Deep learning,» [En línea]. Available: https://en.wikipedia.org/wiki/Deep_learning.
[14] Y. LeCun, L. Bottou, Y. Bengio y P. Haffner, «Gradient-based learning applied to dcument
recognition.,» Proceedings of the IEEE, vol. 86, nº 11, pp. 2278-2324, November 1998.
[15] A. Graves, M. Liwicki, S. Fernandez, R. Bertolami, H. Bunke y J. Schmidhuber, «A novel connectionist
system for unconstrained handwriting recognition,» IEEE transactions on Pattern Annalysis and
Referencias
88
88
Machine Intelligence, vol. 31, nº 5, pp. 855-868, 2009.
[16] Y. Bengio, «Markovian models for sequential data.,» Neural Computing Surveys, vol. 2, pp. 129-162,
1999.
[17] V. Kovalev, «Deep Learning with Theano, Torch, Caffe, TensorFlow, and Deeplearning4J: Which One
Is the Best in Speed and Accuracy?,» de XIII International Conference on Pattern Recognition and
Information Processing (Oct 2016), Minsk, 2016.
[18] GitHub, «Python TensorFlow API,» [En línea]. Available:
https://www.tensorflow.org/api_docs/python/.
[19] V. Paul, D. Patrick y N. Hermann, «Handwritting Recognition with Large Multidimensional Long Short-
Term Memory Recurrent Neural Networks,» International Conference on Frontiers in Handwritting
Recognition, pp. 228-233, 2016.
[20] ASUS, «Manual ESC4000 G3 G3S,» [En línea]. Available:
https://dlsvr04.asus.com/pub/ASUS/server/ESC4000_G3/Manual/E12285_ESC4000_G3_G3S_UM_
V3_WEB.pdf.
[21] Y. LeCun y C. Cortes, «The MNIST database,» [En línea]. Available:
http://yann.lecun.com/exdb/mnist/. [Último acceso: 2017].
[22] P. Doetsch, A. Zeyer, P. Voigtlaender, I. Kulikov, R. Schlüter y H. Ney, «RETURNN,» 2017. [En línea].
Available: https://github.com/rwth-i6/returnn.
[23] N. Markou, «The Black Magic of Deep Learning - Tips and Tricks for the practitioner,» 2017. [En línea].
Available: http://nmarkou.blogspot.com.es/2017/02/the-black-magic-of-deep-learning-tips.html.
[24] L. R. Rabiner, «A tutoral on hidden markov models an selected applications in speech recognition,»
Proc. IEEE, pp. 257-286, 1989.
[25] J. Bridle, «Probabilistic interpretation of feed-forward classification network outputs, with relationships
to statistical pattern recognition.,» Neurocomputing, Algortithms, architectures and applications, pp.
227-236, 1990.
[26] C. Zeller, «Cuda C/C++ Basics,» 2011. [En línea]. Available:
http://www.nvidia.com/docs/IO/116711/sc11-cuda-c-basics.pdf.
[27] R. J. Williams y D. Zipser, «Gradient Based learning algorithms for recurrent networks and their
computational complexity,» Back propagation Theory Architectures and apllications, pp. 433-486,
1995.
[28] P. Doetshc, M. Kozielski y H. Ney, «Fast and robust training of recurrent neural networks for offline
handwriting recognition,» International Conference on Frontiers in Handwriting Recognition, 2014.
[29] M. Kozielski, P. Doetsch y H. Ney, «Improvements in rwth's system for off-line handwriting
recognition,» Proc. of the Int Conf on Document Anal and Recognition (ICDAR), pp. 935-939, 2013.
[30] N. Lalchbremmer, I. Danielhka y A. Graves, «Grid Long-Short Term Memory,» Google Deep Mind,
2016.
89
89 Reconocimiento de Texto Manuscrito con Deep Learning
90
ANEXOS
Anexo I: Consejos para deep learning
En este anexo se resumen una serie de consideraciones que hay que tener en cuenta a la hora de implementar
algoritmos basados en redes neuronales [23]:
Barajar siempre los datos durante el entrenamiento intentando no entrenar siempre con el mismo orden
de los datos. (En los entrenamientos realizados en este trabajo siempre se han barajado los datos en cada
iteración)
Antes de entrenar con el conjunto de datos completo, entrenar con un conjunto reducido intentando
sobre ajustar la estructura a dicho conjunto para comprobar que la misma puede converger. (Esto es lo
que se hizo en la sección 8.2, y se comprobó que la red no convergía a un conjunto de 50 imágenes)
Evitar pooling con normalización, intentar usar siempre max-pooling. (Se ha utilizado siempre max-
pooling)
Utilizar la función de activación ReLU en lugar de la tangente hiperbólica o la sigmoidal ya que estas
últimas tienden a saturar el gradiente. Sin embargo, no se debe utilizar la función ReLU antes de un
max-pooling, si hay una capa de max-pooling realizar la activación tras ella.
Utilizar dropout para evitar el overfitting.
Intentar utilizar estructuras sencillas antes que complicarse con estructuras más complejas.
Cada vez que se programe una plantilla para la ejecución de algún algoritmo intentar parametrizar todo
con vistas a no realizar demasiadas modificaciones en el código en el futuro. (Es una consideración que
se ha llevado a cabo durante la realización de este proyecto, ya que uno de los objetivos ha sido la
implementación de un framework que permita la ejecución de varias estructuras modificando
parámetros de la misma, y se ha buscado facilitar esta tarea)
Intentar entender siempre lo que se está haciendo, las con deep learning se pueden obtener buenos
resultados sin conocer lo que se está haciendo, entender las diferentes técnicas es necesario para poder
mejorar. (Este ha sido uno de los objetivos generales de este proyecto)
En [23] se enumeran más consejos a parte de los aquí mencionados, éstos son los que se han tenido en cuenta
durante la realización de este trabajo y en algunos casos han resuelto problemas que se daban antes de tenerlos
en cuenta.
91
91 Reconocimiento de Texto Manuscrito con Deep Learning
GLOSARIO
ANN Artificial Neural Network
CNN Convolutional Neural Network
FNN Feedforward Neural Network
RNN Recurrent Neural Network
LSTM Long Short Term Memory
MLP Multilayer Perceptron
MDRNN Multi-Dimensional Recurrent Neural Network
MDLSTM Multi-Dimensional Long Short Term Memory
CTC Connectionist Temporal Classification
HMM Hybrids of hidden Markov Models
OHR Offline Handwriting Recognition
BPTT Back Propagation Through Time
GPU Graphics Processor Unit
CPU Central Processing Unit
IP Internet Protocol
CUDA Compute Unified Device Architecture
FLOPS Floating-point Operations Per Second
SSH Secure SHell
SSD Solid State Drive
HDD Hard Disk Drive