scieee AI-readable full text Open interactive document viewer

Desarrollo de una librería Haskell sobre redes neuronales

Ramírez de Arellano Marrero, Antonio

Abstract

Artificial Neural Networks are a computational model whose objective is to simulate the learning system of the human brain, this is achieved by designing and optimizing a network through pre-established examples. In this Final Degree Project we present an introductory theoretical vision on this, in addition to an implementation of a Haskell library, based on the Neurolab Python library, easy to understand for any beginning user in this field. We also add some practical examples as an user’s manual for it. We conclude this work by proposing future improvements for this type of library and commenting on some that already exist.

Full text

FACULTAD DE MATEM´ ATICAS Trabajo fin de Grado Grado en Matem´aticas Desarrollo de una librer´ıa Haskell sobre redes neuronales Realizado por Antonio Ram´ırez de Arellano Marrero Dirigido por Francisco Jes´us Mart´ın Mateos Departamento Ciencias de la Computaci´on e Inteligencia Artificial Sevilla, Junio de 2020 Abstract Artificial Neural Networks are a computational model whose objective is to simulate the learning system of the human brain, this is achieved by designing and optimizing a network through pre-established examples. In this Final Degree Project we present an introductory theoretical vision on this, in addition to an implementation of a Haskell library, based on the Neurolab Python library, easy to understand for any beginning user in this field. We also add some practical examples as an user’s manual for it. We conclude this work by proposing future improvements for this type of library and commenting on some that already exist. I ´ Indice general ´ Indice general III ´ Indice de figuras V ´ Indice de c´odigo VII 1 Redes neuronales artificiales 1 1.1 Inspiraci´on biol´ogica y Motivaci´on de las redes neuronales . . . . . . . . . . . . 1 1.2 Perceptrones ..................................... 2 1.2.1 El Poder Representativo de los perceptrones . . . . . . . . . . . . . . . . . 3 1.2.2 La regla de entrenamiento del “Perceptr´on” . . . . . . . . . . . . . . . . . 4 1.2.3 Descenso del Gradiente y la Regla Delta . . . . . . . . . . . . . . . . . . . 5 1.2.4 Visualizaci´on del espacio de hip´otesis . . . . . . . . . . . . . . . . . . . . . 6 1.2.5 Derivaci´on de la regla del descenso del gradiente . . . . . . . . . . . . . . 7 1.2.6 Aproximaci´on Estoc´astica del Descenso del Gradiente . . . . . . . . . . . 9 1.2.7 Observaciones.................................. 10 1.3 Redes multicapa y el algoritmo de retropropagaci´on . . . . . . . . . . . . . . . 10 1.3.1 Unidad Diferenciable Acotada . . . . . . . . . . . . . . . . . . . . . . . . . 11 1.3.2 El algoritmo de retropropagaci´on . . . . . . . . . . . . . . . . . . . . . . . 12 1.3.3 Derivaci´on del algoritmo de Retropropagaci´on . . . . . . . . . . . . . . . . 15 1.4 Observaciones en el Algoritmo de Retropropagaci´on . . . . . . . . . . . . . . . 18 1.4.1 Convergencia y M´ınimo local . . . . . . . . . . . . . . . . . . . . . . . . . 18 1.4.2 Poder de representaci´on de las redes neuronales . . . . . . . . . . . . . . . 19 1.4.3 B´usqueda en el espacio de hip´otesis y sesgo inductivo . . . . . . . . . . . 19 1.4.4 Representaciones de las Capas Ocultas . . . . . . . . . . . . . . . . . . . . 20 1.4.5 CriteriosdeParada .............................. 21 2 Dise˜no de la aplicaci´on 23 2.1 Librer´ıas ....................................... 23 2.2 NuevotipodeDato ................................. 23 2.3 Funciones Constructoras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 2.3.1 Iniciaci´on por Pesos Fijos . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 2.3.2 Iniciaci´on por Pesos Aleatorios . . . . . . . . . . . . . . . . . . . . . . . . 25 2.4 Funciones de Activaci´on . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 2.5 FuncionesdeError.................................. 28 2.6 M´etodos de Entrenamiento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 III IV ´ Indice general 2.6.1 Entrenamiento del Perceptr´on Simple . . . . . . . . . . . . . . . . . . . . 31 2.6.2 Entrenamiento de Redes Nueronales Multicapa . . . . . . . . . . . . . . . 32 2.7 Criteriosdeparada ................................. 33 3 Manual de uso 35 3.1 Perceptr´onSimple.................................. 35 3.2 Perceptr´onMulticapa ................................ 37 3.2.1 Funci´onXOR.................................. 37 3.2.2 Funci´onContinua ............................... 39 4 Conclusiones 43 4.1 Ampliacionesfuturas ................................ 43 Bibliograf´ıa 45 ´ Indice de figuras 1.1 Comparaci´on de una neurona biol´ogica con una red neuronal . . . . . . . . 2 1.2 Ejemplosvisuales................................. 4 1.3 Error de diferentes hip´otesis. Para una unidad lineal de dos pesos. . . . . . 7 1.4 Launidadsigmoide................................ 11 1.5 Funci´on σ(x) ................................... 11 1.6 Representaci´on de puntos de dato con entrada x∈ {0,5,1,3}. Gracias al sesgo inductivo que tenemos, el algoritmo tender´a a etiquetar los valores intermedios como positivos. . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 1.7 Representaci´on de una capa oculta que ya ha aprendido. Hemos entrenado esta red de 8 x 3 x 8 para aprender la funci´on identidad, hemos usado los 8 ejemplos de entrenamiento. Despu´es de 5000 entrenamientos, las unidades ocultas han codificado las ocho unidades de entrada con la codificaci´on de la derecha. Ejemplo sacado de Tom Mitchell [13] . . . . . . . . . . . . . . . 20 3.1 Gr´afica de la funci´on booleana AND . . . . . . . . . . . . . . . . . . . . . . 35 3.2 Perceptr´on Unicapa para la funci´on AND . . . . . . . . . . . . . . . . . . . 36 3.3 Gr´afica de la funci´on XOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 3.4 Red Neuronal Multicapa para la funci´on XOR . . . . . . . . . . . . . . . . . 38 3.5 Representaci´on Gr´afica de f........................... 39 3.6 Red Neuronal Multicapa para la funci´on f................... 40 V ´ Indice de c´odigo 2.1 Librer´ıasImportadas............................... 23 2.2 Tipo de dato para las funciones de activaci´on . . . . . . . . . . . . . . . . . 24 2.3 Tipo de dato para las FNN . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 2.4 Tipo de dato para las funciones Error . . . . . . . . . . . . . . . . . . . . . 24 2.5 Funci´on constructora del Perceptr´on simple con pesos nulos . . . . . . . . . 24 2.6 Funci´on constructora de la red neurnal multicapa con un valor fijo v. . . . 25 2.7 Funciones constructoras con pesos nulos . . . . . . . . . . . . . . . . . . . . 25 2.8 Matriz con entradas aleatorias . . . . . . . . . . . . . . . . . . . . . . . . . . 25 2.9 Funci´on constructora del Perceptr´on simple con entradas aleatorias . . . . . 25 2.10 Funci´on auxiliar para la lista de matrices peso . . . . . . . . . . . . . . . . . 25 2.11 Funci´on constructora de la red neuronal multicapa con entradas aleatorias . 26 2.12 Funci´on de activaci´on y su derivada . . . . . . . . . . . . . . . . . . . . . . 26 2.13 Funci´on de Activaci´on Lineal . . . . . . . . . . . . . . . . . . . . . . . . . . 26 2.14 Funci´on de Activaci´on Lineal Saturada . . . . . . . . . . . . . . . . . . . . . 26 2.15 Funci´on de Activaci´on sigmoide . . . . . . . . . . . . . . . . . . . . . . . . . 27 2.16 Funci´on de Activaci´on Tangente Hiperb´olica . . . . . . . . . . . . . . . . . . 27 2.17 Funci´on de Activaci´on ReLU . . . . . . . . . . . . . . . . . . . . . . . . . . 27 2.18 Funci´on de Activaci´on leaky ReLU . . . . . . . . . . . . . . . . . . . . . . . 28 2.19 Funci´on de Activaci´on Umbral . . . . . . . . . . . . . . . . . . . . . . . . . 28 2.20 Funci´on de error basada en entrop´ıa con su derivada . . . . . . . . . . . . . 28 2.21 Funci´on de error absoluto medio con su derivada . . . . . . . . . . . . . . . 29 2.22 Funci´on de error cuadr´atico medio con su derivada . . . . . . . . . . . . . . 29 2.23 Funci´on de suma de errores absolutos con su derivada . . . . . . . . . . . . 29 2.24 Funci´on de suma de errores cuadr´aticos con su derivada . . . . . . . . . . . 30 2.25 Funci´on salida de una red . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 2.26 Funci´on Auxiliar para los valores de las unidades . . . . . . . . . . . . . . . 30 2.27 Entrenamiento del Perceptr´on simple con regla de aprendizaje Delta . . . . 31 2.28 Entrenamiento del Perceptr´on simple con la regla de aprendizaje Batch . . 31 2.29 Funci´on eliminatoria de los pesos w0...................... 32 2.30 Funci´on producto componente a componente . . . . . . . . . . . . . . . . . 32 2.31 Funci´on matrices de error por capa . . . . . . . . . . . . . . . . . . . . . . . 32 2.32 Entrenamiento de tipo gradiente Delta multicapa . . . . . . . . . . . . . . . 33 2.33 Entrenamiento de tipo gradiente Batch multicapa . . . . . . . . . . . . . . . 33 2.34 Entrenamiento unicapa iterando n veces . . . . . . . . . . . . . . . . . . . . 33 2.35 Entrenamiento iterando n veces . . . . . . . . . . . . . . . . . . . . . . . . . 33 2.36 Error de la red sobre los ejemplos de entrenamiento . . . . . . . . . . . . . . 34 2.37 Entrenamiento unicapa con error acotado . . . . . . . . . . . . . . . . . . . 34 VII 61. Redes neuronales artificiales objetivo tdy el valor de salida de la unidad lineal od, sumando esto sobre todos los ejemplos de entrenamiento. B´asicamente estamos hablando de la Suma de Errores Cuadr´aticos. Aqu´ı caracterizamos Ecomo una funci´on de ~w porque la unidad lineal que devuelve o depende exclusivamente del vector peso. Obviamente Etambi´en depende en particular del conjunto de ejemplos de entrenamiento, pero asumimos que estos ya est´an fijados durante el entrenamiento. Para estudiar la convergencia, seguiremos usando la suma de errores cuadr´aticos, pero actualmente se usan otras muchas medidas de error, algunas de estas medidas son los siguientes: •Error basado en entrop´ıa: −X d∈D tdlog(od) + (1 −td) log(1 −od) •Error absoluto medio: 1 |D|X d∈D |td−od| •Suma de errores absolutos: X d∈D |td−od| •Error cuadr´atico medio: 1 |D|X d∈D (td−od)2 1.2.4. Visualizaci´on del espacio de hip´otesis Para comprender el algoritmo de descenso por el gradiente, puede ser de gran ayuda visualizar todo el espacio de hip´otesis de los posibles vectores peso y su relaci´on con los valores de E, como podemos observar en la figura 1.3, la funci´on error debe ser siempre un paraboloide con un m´ınimo global (gracias a nuestra elecci´on de la funci´on error). Cada paraboloide va a depender de los ejemplos de entrenamiento. Fij´andonos m´as detenidamente en la figura 1.3 el espacio de hip´otesis Hes el plano XY asociado a w0yw1respectivamente, el eje vertical representa el error del vector peso correspondiente. La flecha indica la direcci´on opuesta a la del gradiente, que se˜nala el mayor descenso de la funci´on de error. Luego una manera de disminuir el error en cada paso puede ser gui´andonos por el vector opuesto al gradiente de la funci´on error, la longitud de paso en cada iteraci´on la podremos ajustar para asegurar que no nos “pasamos” del m´ınimo. El descenso del gradiente determina el vector peso que minimiza Eempezando por un vector peso arbitrario y modific´andolo en peque˜nos pasos. En cada paso, el vector peso lo alteramos en la direcci´on que produzca el mayor descenso sobre la superficie de error. Este proceso es reiterado hasta que alcancemos el m´ınimo global. 1.2. Perceptrones 7 Figura 1.3: Error de diferentes hip´otesis. Para una unidad lineal de dos pesos. 1.2.5. Derivaci´on de la regla del descenso del gradiente Ahora nos preguntamos: ¿C´omo podemos calcular la direcci´on que d´e el salto con mayor descenso posible sobre la superficie de error? Esta direcci´on la podemos encontrar derivando la funci´on Erespecto a cada componente del vector ~w. Este vector derivada se denomina Gradiente de Erespecto de ~w, denotado ∇E(~w). ∇E(~w) = ∂E ∂w0 ,∂E ∂w1 , ..., ∂E ∂wn(1.3) Observemos que ∇E(~w) es un vector en s´ı, cuyas componentes son las derivadas parciales de Erespecto cada wi. Interpret´andolo como vector del espacio de los pesos, el gradiente nos da la direcci´on que produce el mayor aumento en E. Por lo tanto −∇Enos da la direcci´on del mayor decrecimiento. Puesto que el gradiente produce esta informaci´on, definimos la regla de entrenamiento para el descenso por el gradiente como ~w ←~w + ∆~w donde ∆~w =−η∇E(~w) (1.4) Aqu´ı ηes una constante positiva que volveremos a llamar “tasa de aprendizaje”, que determina el tama˜no del paso en el descenso del gradiente. Obviamente el signo negativo est´a para que nos movamos hacia el mayor descenso. Est´a regla tambi´en la podemos expresar componente a componente wi←wi+ ∆wi donde ∆wi=−η∂E ∂wi (1.5) Para construir un algoritmo pr´actico para ir actualizando iterativamente los pesos de acuerdo a (1.5), necesitamos una manera eficiente de calcular el gradiente en cada paso, afortunadamente, no es complicado conseguirlo. Derivando Ecomponente a componente seg´un su definici´on tenemos que 81. Redes neuronales artificiales ∂E ∂wi =∂ ∂wi (1 2X d∈D (td−od)2) =1 2X d∈D ∂ ∂wi (td−od)2 =1 2X d∈D 2(td−od)∂ ∂wi (td−od) =X d∈D (td−od)∂ ∂wi (td−~w ·~xd) ∂E ∂wi =X d∈D (td−od)(−xid)(1.6) donde xid denota la entrada de la componente xipara el ejemplo de entrenamiento d. Acabamos de conseguir una ecuaci´on que nos da ∂E ∂wien t´erminos de xid,od, y el valor objetivo tdasociado con los ejemplos de entrenamiento. Sustituyendo la ecuaci´on 1.6 en la ecuaci´on (1.5) nos queda ∆wi=ηX d∈D (td−od)xid (1.7) En resumidas cuentas, el algoritmo nos queda de la siguiente forma: DESCENSO-GRADIENTE(ejemplo entrenamiento, η) Para cada ejemplo de entrenamiento de la forma h~x, ti, donde ~x es el vector de los valores de entrada, tes el valor objetivo de salida y ηes la tasa de aprendizaje. •Asignamos a cada wiun valor inicial aleatorio •Hasta que se llegue a la condici´on terminal, hacer ◦Dar a cada ∆wiel valor 0. ◦Para cada h~x, tien ejemplo entrenamiento, hacer ∗Dar el valor ~x a la unidad y calcular el valor de salida o ∗Para cada peso wi, hacer ∆wi←∆wi+η(t−o)xi(1.8) ◦Para cada peso wi, hacer wi←wi+ ∆wi(1.9) Cabe destacar que el algoritmo converge porque la superficie de error contiene un s´olo m´ınimo global, adem´as ´este converger´a al m´ınimo error independientemente de que los ejemplos de entrenamiento sean o no separables, siempre que el ηsea suficientemente peque˜no, puesto que el descenso del gradiente cuenta con el riesgo de que el salto sea demasiado grande y nos saltemos el m´ınimo en la superficie de error en vez de alcanzarlo. Por ´esta raz´on, una modificaci´on que suele hacerse en el algoritmo es reducir el valor de η conforme vayamos aumentando las iteraciones. 1.2. Perceptrones 9 1.2.6. Aproximaci´on Estoc´astica del Descenso del Gradiente El m´etodo del descenso del gradiente es una estrategia para la b´usqueda en grandes, o incluso espacios infinitos de hip´otesis. En general se puede aplicar cuando el espacio en el que trabajamos est´a parametrizado de forma continua y podemos derivar la funci´on error respecto de estos par´ametros continuos. Las dificultades pr´acticas m´as importantes que nos podemos encontrar al aplicarlo son: 1. La convergencia puede llegar a ser muy lenta, es decir, puede llegar a necesitar varios miles de pasos. 2. Si existen varios m´ınimos locales en la superficie de error, no hay garant´ıas de que alcancemos el m´ınimo global. Una variaci´on com´un para aliviar estas dificultades es el descenso del gradiente estoc´astico. Mientras que el m´etodo del descenso del gradiente (usando la ecuaci´on (1.7)) realiza la actualizaci´on de los pesos despu´es de sumar los incrementos sobre todos los ejemplos de entrenamiento D, la idea detr´as del m´etodo de descenso por el gradiente estoc´astico es actualizar los pesos con m´as frecuencia, ajust´andolos individualmente para cada ejemplo. Esta modificaci´on del m´etodo de entrenamiento es igual a la ecuaci´on (1.7) exceptuando que ahora cada vez que iteremos en cada ejemplo de entrenamiento actualizamos los pesos de acuerdo a la siguiente regla: ∆wi=η(t−o)xi(1.10) donde t,oy los xison los valores objetivo, la unidad de salida y la i-´esima entrada para el ejemplo de entrenamiento en cuesti´on, respectivamente. Para modificar el anterior algoritmo basta reemplazar la ecuaci´on (1.8) por wi←η(t−o)xi Una manera de visualizar el descenso del gradiente estoc´astico es considerando una funci´on de error distinta Ed(~w) definida para cada uno de los ejemplo de entrenamiento d de la siguiente forma Ed(~w) = 1 2(td−od) (1.11) donde tdyodson el valor objetivo y el valor de la unidad de salida para el ejemplo de entrenamiento d, respectivamente. El descenso por el gradiente estoc´astico itera sobre cada ejemplo de entrenamiento den D, en cada iteraci´on actualizamos los pesos de acuerdo con el gradiente del Ed(~w) correspondiente. Esta secuencia de iteraciones proporciona una aproximaci´on razonable para descender por el gradiente de nuestra funci´on de error original E(~w). Haciendo ηsuficientemente peque˜no, podemos conseguir que el descenso del gradiente estoc´astico funcione incluso mejor que el est´andar. Las diferencias clave entre el m´etodo est´andar y el estoc´astico son: •En la versi´on est´andar, sumamos el error sobre todos los ejemplos antes de actualizar los pesos, mientras que el estoc´astico los vamos actualizando en cada ejemplo de entrenamiento. 10 1. Redes neuronales artificiales •Sumar sobre varios ejemplos distintos en la versi´on est´andar requiere de mucha m´as computaci´on por cada actualizaci´on de los pesos. Por el otro lado, como este s´ı usa el verdadero gradiente, la versi´on est´andar normalmente usa una longitud de paso m´as grande que el estoc´astico. •En casos donde haya varios m´ınimos locales respecto de E(~w), algunas veces el m´etodo estoc´astico puede evitar caer en estos m´ınimos locales porque usa varios ∇Ed(~w) en vez de s´olo un ∇E(~w) para guiarnos en la b´usqueda. En la pr´actica se usan ambos m´etodos con bastante frecuencia. La regla de entrenamiento en la ecuaci´on (1.10) la llamamos regla delta (cuya nomenclatura usaremos en la librer´ıa) o tambi´en regla LMS (least-mean-square). Tambi´en aclarar que a la regla est´andar la llamaremos regla Batch en la implementaci´on. Observemos que la regla delta en la ecuaci´on (1.10) es similar a la regla perceptr´on, pero aunque ambas expresiones aparentan ser id´enticas, estas son diferentes puesto que en la regla delta ose refiere a la unidad lineal o(~x) = ~w ·~x, mientras que la regla perceptr´on se refiere a la funci´on umbral o(~x) = sg(~w ·~x). 1.2.7. Observaciones Hemos considerado dos algoritmos similares para el aprendizaje iterativo del perceptr´on. La diferencia clave se refleja en sus diferentes propiedades de convergencia. La regla perceptr´on converge despu´es de un n´umero finito de pasos hacia una hip´otesis que clasifica perfectamente los datos de entrenamiento, siempre y cuando los ejemplos de entrenamientos sean linealmente separables. La regla delta converge s´olo asint´oticamente hacia el m´ınimo error, posiblemente esto requiera un tiempo no acotado, pero converge sin importar si los datos de los ejemplos de entrenamiento son linealmente separables o no [17]. Un tercer algoritmo para el aprendizaje del vector de pesos es la programaci´on lineal. La programaci´on lineal es un m´etodo gen´erico y eficiente que se usa para resolver conjuntos definidos por inecuaciones lineales. Esto es aplicable en este contexto si planteamos que cada ejemplo de entrenamiento corresponde a una desigualdad de la forma ~w ·~x > 0 o~w ·~x ≤0, y su soluci´on es el vector deseado. Desafortunadamente este acercamiento s´olo nos da una soluci´on si los ejemplos de entrenamiento son linealmente separables, sin embargo; [3] sugiere una formulaci´on mas sutil que funciona en los casos no separables. En cualquier caso, el acercamiento por programaci´on lineal no escala al entrenamiento de redes multicapa, el cual es nuestro objetivo principal. En cambio, el acercamiento por el descenso del gradiente, base de la regla delta; podemos extenderlo a redes multicapa, como vamos a ver en la siguiente secci´on. 1.3– Redes multicapa y el algoritmo de retropropagaci´on Como hemos visto en el apartado anterior, los perceptrones unicapa s´olo pueden expresar superficies de decisi´on lineales. En cambio, el tipo de redes multicapa que aprenden por el algoritmo de retropropagaci´on son capaces de expresar una rica variedad de superficies de decisi´on no lineales. En esta secci´on discutiremos como ajustar las redes multicapa usando algoritmos de tipo gradiente de forma similar al planteado en la secci´on anterior. 1.3. Redes multicapa y el algoritmo de retropropagaci´on 11 1.3.1. Unidad Diferenciable Acotada ¿Qu´e tipo de unidad deber´ıamos usar como base para la construcci´on de redes multicapa? Lo primero que podr´ıamos intentar es elegir las unidades lineales discutidas en la anterior secci´on, para la cual ya hemos derivado una relga del descenso del gradiente. De cualquier forma, m´ultiples capas de unidades lineales tambi´en producen funciones lineales, y preferimos redes capaces de representar funciones no lineales m´as complejas. La unidad perceptr´on es otra posibilidad, pero su valores de salida son discretos, luego no son diferenciables, y por lo tanto no se portan bien en el descenso por el gradiente. Lo que necesitamos es una unidad cuya salida sea una funci´on no lineal pero que sea tambi´en diferenciable respecto a los valores de entrada. Una soluci´on es la unidad sigmoide, una unidad muy parecida al perceptr´on, pero basada en una funci´on diferenciable y suavizada. Figura 1.4: La unidad sigmoide Esta unidad sigmoide es una funci´on continua respecto a sus entradas, su salida ose calcula como o=σ(~w ·~x) donde σ(y) = 1 1 + e−y(1.12) Figura 1.5: Funci´on σ(x) Aσla llamaremos funci´on sigmoide o funci´on log´ıstica. Observando la gr´afica 1.5, vemos que su rango queda comprendido entre 0 y 1, adem´as es mon´otona creciente respecto a su variable. Como puede partir de grandes dominios y va al (0,1), la funci´on tambi´en se suele 12 1. Redes neuronales artificiales llamar funci´on aplastamiento a la unidad. La funci´on sigmoide tiene la ´util propiedad de que podemos expresar f´acilmente su derivada respecto a su valor de salida (dσ(y) dy = σ(y)·(1 −σ(y))). Como podemos observar el m´etodo del descenso del gradiente hace uso de esta derivada. Algunas veces se usan otras funciones diferenciables con derivadas faciles de calcular. Por ejemplo, el t´ermino e−ylo podemos reemplazar algunas veces por por e−ky donde kes una constante positiva que nos determina la longitud de paso del l´ımite. En el ´ambito te´orico y a lo largo de este cap´ıtulo seguiremos con esta unidad de activaci´on, pero existen diversas opciones en la pr´actica, algunas a destacar son: •Activaci´on Lineal (o identidad): σ(y) = y •Activaci´on Lineal Saturada: σ(y) = (0 si y < 0 yen caso contrario •Tangente Hiperb´olica: σ(y) = ex−e−x ex+e−x •Unidad Lineal Rectificada: σ(y) = m´ax{0, y} •Unidad Lineal Rectificada “Leaky”: σ(y) = (0,01ysi y < 0 yen caso contrario 1.3.2. El algoritmo de retropropagaci´on El algoritmo de retropropagaci´on aprende los pesos de una red multicapa con un conjunto fijo de unidades e interconexiones. Utiliza el m´etodo de descenso por el gradiente para intentar minimizar el error entre los valores de la red de salida y los valores objetivo de estas salidas. Aqu´ı presentaremos este algoritmo adem´as de algunas posibles mejoras. Como estamos considerando ahora redes con m´ultiples salidas en vez de unidades simples como antes, empezaremos por redefinir la funci´on de error Ecomo la suma de los errores sobre todas las unidades de salida de la red E(~w) = 1 2X d∈DX k∈salidas (tkd −okd)2(1.13) donde salidas es el conjunto de unidades de salida de la red, y tkd yokd son los valores objetivos y de salida asociados a la k-´esima unidad de salida en el ejemplo de entrenamiento d. El problema de aprendizaje al que se enfrenta la retropropagaci´on es la b´usqueda de un gran espacio de hip´otesis definida por todos los posibles valores peso de todas las unidades de la red. Esta situaci´on la podemos visualizar en t´erminos de la superficie de error de manera similar a la de la imagen 1.3. Reemplazamos el error en ese diagrama por nuestra nueva definici´on de E, y las otras dimensiones del espacio corresponden ahora a todos los 1.3. Redes multicapa y el algoritmo de retropropagaci´on 13 pesos asociados a todas las unidades de la red. Como en el caso del entrenamiento de una unidad simple, el descenso del gradiente pretende encontrar una hip´otesis para minimizar la funci´on de error E. RETROPROPAGACION(ejemplos entrenamietno,η,nin,nout,nhidden) Cada ejemplo de entrenamiento es un par de la forma h~x,~ ti, donde ~x es el vector de los valores de entrada de la red, y ~ tes el vector de salida con los valores objetivo de la red. ηes la tasa de aprendizaje, nin es el n´umero de redes de entrada, nhidden el n´umero de unidades en las capas ocultas, y nout es el n´umero de unidades de salida. Llamaremos a la entrada que vaya de la unidad ia la unidad jcomo xji y al peso que vaya de la unidad ia la unidad jlo llamaremos wji. •Creamos una red prealimentada con nin entradas, nhidden unidades ocultas, y nout unidades de salida. •Asignamos a todos los pesos de la red n´umero aleatoriamente peque˜nos (p.ej. −0,5 y 0,5). •Hasta llegar a la condici´on final, hacer ◦Para cada h~x,~ tien ejemplos entrenamientos, hacer ∗Propagar la entrada hacia delante a trav´es de la red: ?Evaluamos el valor ~x en la red y calculamos la salida oude cada unidad uen la red. ∗Propagar el error hacia atr´as a trav´es de la red: ?Para cada unidad de salida de la red k, calcular su error δk δk←ok(1 −ok)(tk−ok) (1.14) ?Para cada unidad oculta h, calcular su error δh dh←oh(1 −oh)X k∈salidas wkhδk(1.15) ?Actualizamos cada peso de la red wij wji ←wji + ∆wji (1.16) donde ∆wji =ηδjxji (1.17) Una de las diferencias notables en el caso de las redes multicapa es que la superficie de error puede tener varios m´ınimos locales, no como en las superficies parab´olicas de las redes simples (como podemos observar en la figura 1.3) donde no nos encontramos este problema. Desafortunadamente, esto implica que el descenso del gradiente nos garantiza la convergencia a un m´ınimo local, y no necesariamente al global. A pesar de este obst´aculo, en la pr´actica la retropropagaci´on proporciona excelentes resultados en diversas aplicaciones en el mundo real. El algoritmo que acabamos de describir comienza con una construcci´on de la red con el n´umero deseado de unidades ocultas y de salida, e inicia toda la red con pesos aleatorios 14 1. Redes neuronales artificiales peque˜nos. Dada esta estructura fija de la red, el bucle principal del algoritmo se repite sobre los ejemplos de entrenamiento. Para cada ejemplo de entrenamiento, se aplica la red al ejemplo, se calcula el error de la salida en ese caso, se calcula el gradiente respecto del error en esa iteraci´on (a veces repetimos esto miles de veces con el mismo ejemplo) y se ajustan los pesos hasta que la red act´ue de manera aceptable. La actualizaci´on del peso por el m´etodo del gradiente (1.17) es similar a la regla de aprendizaje delta (1.10). Al igual que la regla delta, se actualiza cada peso en proporci´on a la tasa de aprendizaje η, el valor de entrada xij al cual aplicamos el peso, y el error en la salida de la unidad. La ´unica diferencia es que el error (t−o) de la regla delta se reemplaza por un error m´as complejo, δj. La forma exacta de δjse consigue de la derivaci´on de la regla en la que cambiamos el peso (que veremos m´as adelante). Para entenderla intuitivamente, primero consideremos como estamos computando δken el algoritmo para cada unidad de salida de la red k(1.14). δksimplemente es la forma familiar de la regla delta (tk−ok), multiplicado por un factor ok(1 −ok), el cual es la forma de la derivada de la funci´on sigmoide. El δhpara cada unidad oculta htiene una forma similar (1.15). Sin embargo, como los ejemplos de entrenamiento nos proporcionan valores objetivos tksolo para las salidas de la red, no tenemos valores objetivos para indicar el error de los valores de las unidades ocultas. En lugar de esto, calculamos el error para las unidades ocultas h sumando los errores δkque est´a influenciados por h, pesando cada δkcon wkh, el peso que va desde la unidad oculta hy la unidad de salida k. Este peso nos da la informaci´on de “c´omo y cu´anto de importante es h” en el error de la unidad de salida k. El algoritmo actualiza los pesos de forma incremental, siguiendo la presentaci´on de cada ejemplo de entrenamiento. Esto corresponde a una aproximaci´on estoc´astica al descenso por el gradiente. Para obtener el verdadero gradiente de Edeber´ıamos sumar los valores δjxji sobre todos los ejemplos de entrenamiento antes de alterar los pesos. Podemos llegar a iterar miles de veces el bucle que hacemos para actualizar los pesos en la retropropagaci´on en cualquier aplicaci´on t´ıpica del mismo. Una variante para las condiciones terminales es usando un procedimiento de parada, parar en un n´umero fijado de iteraciones (Epochs) o una vez que el error decaiga por debajo de alguna cota, o bien alcance un criterio previamente marcado. La elecci´on de estos criterios es muy importante, puesto que con pocas iteraciones se pueden fallar a la hora de reducir suficientemente el error, y con demasiadas puede “sobreajustar”los datos de entrenamiento. Discutiremos este problema m´as adelante. A˜nadir momentum Al ser la retropropagaci´on un algoritmo muy usado, se han desarrollado muchas variaciones del mismo. Seguramente la m´as com´un consiste en variar la actualizaci´on de los pesos (1.17) del algoritmo haciendo que la actualizaci´on del peso en la iteraci´on n-´esima dependa parcialmente en la actualizaci´on de la iteraci´on (n-1)-´esima de la siguiente forma ∆wji(n) = ηδjxji +α∆wji(n−1) (1.18) aqu´ı ∆wji(n) es la actualizaci´on del peso en la iteraci´on n-´esima que ocurre en el bucle principal del algoritmo, y 0 ≤α < 1 es una contante llamada momentum. Observamos que el primer t´ermino de la parte derecha de la igualdad es exactamente igual al del algoritmo de retropropagaci´on (1.17). El segundo t´ermino de la parte derecha lo llamaremos t´ermino de momentum. Para ver el efecto de este t´ermino, pensemos que la trayectoria del descenso 1.3. Redes multicapa y el algoritmo de retropropagaci´on 15 del gradiente es como una pelota que baja rodando por la superficie de error. El efecto que tiene αes que esta bola tienda a seguir rodando en la misma direcci´on de una iteraci´on a la siguiente. Esto puede conseguir que la bola siga rodando aunque pase por un m´ınimo local o en regiones planas (gradiente nulo), es decir, en sitios donde se detendr´ıa si us´asemos el algoritmo de retropropagaci´on. Adem´as esto tambi´en hace que vaya aumentando la longitud de paso en regiones donde el gradiente no var´ıa, y por lo tanto su velocidad de convergencia. Aprendizaje en redes ac´ıclicas arbitrarias Si analizamos el algoritmo de retropropagaci´on, observamos que s´olo se puede aplicar a redes de dos capas. Sin embargo, este mismo algoritmo se puede generalizar a redes de profundidad arbitraria. Mantenemos la regla de actualizaci´on del peso (1.17), y lo ´unico que cambiamos es el procedimiento al calcular los valores δ. En general, calculamos el valor δrpara una unidad ren la capa mdesde los valores de δde la siguiente capa m+ 1 de acuerdo a la siguiente regla: δr=or(1 −or)X s∈capa m+1 wsrδs(1.19) Hay que destacar que esto es id´entico al paso 3 del algoritmo original. Realmente lo que estamos diciendo aqu´ı es que este paso lo vamos a repetir para cada capa oculta de la red. De la misma forma podemos generalizarlo a cualquier grafo ac´ıclico dirigido, sin importar si las unidades de la red est´an uniformemente organizadas en capas, como hemos supuesto hasta ahora. En el caso en el que no lo est´en, la regla para calcular δpara cualquier unidad interna (es decir, cualquier unidad que no sea de salida) es δr=or(1 −or)X s∈Siguientes(r) wsrδs(1.20) donde Siguientes(r) es el conjunto de unidades a las que se va inmediatamente desde la unidad ren la red, esto es; todas las unidades cuyas entradas incluyen la salida de la unidad r. Esta es la forma general de la regla de actualizaci´on del peso que vamos a derivar en la siguiente secci´on. 1.3.3. Derivaci´on del algoritmo de Retropropagaci´on En esta secci´on vamos a presentar la derivaci´on de la regla en la que actualizamos el peso en el algoritmo de retropropagaci´on. En concreto, la regla del descenso por el gradiente estoc´astico del algoritmo de retropropagaci´on (secci´on 1.3.2). Si volvemos a observar la ecuaci´on (1.11) estamos iterando sobre los ejemplos de entrenamiento de uno en uno, para cada ejemplo de entrenamiento dcalculamos el gradiente del error Edrespecto de ese ejemplo. En otras palabras, para cada ejemplo de entrenamiento dactualizamos cada peso wji a˜nadi´endole ∆wji ∆wji =−η∂Ed ∂wji (1.21) CAP´ ITULO 2 Dise˜no de la aplicaci´on En este cap´ıtulo hablaremos de la implementaci´on de nuestra librer´ıa sobre redes neuronales en Haskell, para la que nos hemos inspirado en la librer´ıa Neurolab de Python [14]. Esta librer´ıa desarrolla algoritmos b´asicos para redes neuronales, con configuraciones flexibles tanto para los algoritmos de aprendizaje, como para las redes en s´ı. 2.1– Librer´ıas Comencemos por hablar de las librer´ıas necesarias para este proyecto. Necesitaremos: 1. Una librer´ıa para trabajar con las matrices peso como es Data.Matrix. 2. Una librer´ıa para generar los pesos aleatorios bajo cierto umbral como puede ser System.Random. 3. Una librer´ıa para pasar del tipo de dato IO (Float) a Float para poder manejar los datos aleatorios generados, como puede ser la librer´ıa System.IO.Unsafe. 4. Una librer´ıa para usar principalmente genericLength la cual daremos uso en las funciones de error, Data.list. 1import qualified Data.Matrix as M 2import qualified System.Random as S 3import System.IO.Unsafe 4import Data.List C´odigo 2.1: Librer´ıas Importadas 2.2– Nuevo tipo de Dato Vamos a implementar un nuevo tipo de dato para las FNN en haskell. La manera de implementarlas va a ser muy parecida a como lo hace la librer´ıa Neurolab en Python, pero antes vamos a hacer un tipo de dato para las funciones de activaci´on. Como en haskell no tenemos forma de derivar de manera simb´olica, nuestras funciones de activaci´on deber´an venir acompa˜nadas de su correspondiente derivada 23 24 2. Dise˜no de la aplicaci´on 1data ACT =Act (Float -> Float) (Float -> Float) C´odigo 2.2: Tipo de dato para las funciones de activaci´on Ahora ya estamos listos para implementar nuestro tipo de dato para las redes neuronales 1data FNN =Net [Int] [M.Matrix Float] [ACT] C´odigo 2.3: Tipo de dato para las FNN donde •La primera lista describe la estructura de la red, m´as concretamente indica el n´umero de unidades que tiene cada una de las capas que forman la red. •La segunda lista almacena las matrices peso para ir de de la capa i-´esima a la capa i+ 1-´esima. •La tercera lista contiene la funci´on de activaci´on con su derivada para cada capa. Por ´ultimo tambi´en implementaremos un tipo de dato para el Error de la red en los ejemplos de entrenamiento. Al igual que en las funciones de activaci´on, tambi´en haremos uso de la correspondiente derivada, as´ı que lo implementaremos de la siguiente forma: 1data ERROR =Error ([Float] -> [Float]->Float) ([Float] -> [Float] -> [Float]) C´odigo 2.4: Tipo de dato para las funciones Error Como la funci´on Error es de tipo Rn−→ Ral hablar de su derivada, hablaremos de gradiente y por lo tanto ∇E:Rn−→ Rn, adem´as (aunque lo demos por fijado) el error tambi´en depende de los ejemplos de entrenamiento. 2.3– Funciones Constructoras Otros elementos base para la aplicaci´on son las funciones constructoras para las redes neuronales. Aqu´ı podemos diferenciar las dos principales maneras de implementar los pesos iniciales: pesos aleatorios peque˜nos (bajo cierto umbral) y pesos nulos. 2.3.1. Iniciaci´on por Pesos Fijos Comencemos por la m´as simple, el perceptr´on simple, 1newpValue :: Int -> ACT -> Float -> FNN 2newpValue n (Act f df)v= 3Net [n,1] [M.transpose (M.fromLists [replicate (n+1) v])] [Act f df] C´odigo 2.5: Funci´on constructora del Perceptr´on simple con pesos nulos Como podemos observar, hemos generado un perceptr´on simple con nunidades de entrada y funci´on de activaci´on f. Para movernos en casos m´as generales vamos a implementar una funci´on para definir redes multicapa: 2.3. Funciones Constructoras 25 1newffValue :: [Int] -> [ACT]->Float -> FNN 2newffValue ns fs v = 3Net ns (foldl (\ z(x1,x2)->z++[M.matrix (x1+1) x2 (\ (i,j)->v)]) [] 4(zip ns (tail ns))) fs C´odigo 2.6: Funci´on constructora de la red neurnal multicapa con un valor fijo v Cada capa i-´esima tendr´a un n´umero de entradas definida por el i-´esimo entero de la lista ns, y con la i-´esima funci´on de activaci´on de la lista fs. Un caso particular de ´este es el inicio con pesos nulos el cual lo vamos a tener como construcci´on aparte, tanto como el perceptr´on unicapa como para la red multicapa: 1newpZero :: Int -> ACT -> FNN 2newpZero n (Act f df) = 3newpValue n (Act f df) 0 4 5newffZero :: [Int] -> [ACT]->FNN 6newffZero ns fs = 7newffValue ns fs 0 C´odigo 2.7: Funciones constructoras con pesos nulos 2.3.2. Iniciaci´on por Pesos Aleatorios Aqu´ı vamos a necesitar algunas funciones auxiliares, comencemos por generar las matrices con entradas aleatorias (acotadas). 1randomMatrix :: Float -> Float -> Int -> Int -> IO (M.Matrix Float) 2randomMatrix min max nm= 3do vs <- sequence [S.randomRIO (min,max)::IO Float |i<- [1..n*m]] 4let a=M.fromList n m vs 5return a C´odigo 2.8: Matriz con entradas aleatorias Aqu´ı estamos generando una matriz n×mcon entradas aleatorias acotadas por min y max por abajo y arriba respectivamente. Ahora ya podemos implementar el perceptr´on simple 1newpRand :: (Float,Float)->Int -> [ACT]->FNN 2newpRand (min,max)nfs= 3Net [n,1] [unsafePerformIO (randomMatrix min max (n+1) 1)] fs C´odigo 2.9: Funci´on constructora del Perceptr´on simple con entradas aleatorias Para la versi´on de la red neuronal multicapa, daremos uso de una funci´on auxiliar para generar la lista de matrices peso, 1randWs :: Float -> Float -> [Int] -> [M.Matrix Float] 2randWs min max xs = 3foldl (\ ws (x1,x2)->ws ++ [unsafePerformIO(randomMatrix min max (x1+1) x2)]) [] (zip xs (tail xs)) C´odigo 2.10: Funci´on auxiliar para la lista de matrices peso 26 2. Dise˜no de la aplicaci´on Finalmente, la versi´on de la red neuronal multicapa queda: 1newffRand :: (Float,Float) -> [Int] -> [ACT]->FNN 2newffRand (min,max)ns fs = 3Net ns (randWs min max ns)fs C´odigo 2.11: Funci´on constructora de la red neuronal multicapa con entradas aleatorias 2.4– Funciones de Activaci´on En esta secci´on implementaremos distintos tipos de funciones de activaci´on para nuestras redes (con sus correspondientes derivadas). Antes de ello construyamos dos funciones para extraer la funci´on y su derivada del tipo de dato de activaci´on. 1activ :: ACT -> (Float -> Float) 2activ (Act f df)=f 3 4derAct :: ACT -> (Float -> Float) 5derAct (Act f df)=df C´odigo 2.12: Funci´on de activaci´on y su derivada Una vez teniendo en cuenta esto, las funciones de activaci´on con las que vamos a trabajar son las siguientes: 1. Activaci´on lineal Esta es la funci´on identidad 1actLin :: Float -> Float 2actLin x =x 3 4dActLin :: Float -> Float 5dActLin x = 1 6 7pureLin :: ACT 8pureLin =Act actLin dActLin C´odigo 2.13: Funci´on de Activaci´on Lineal 2. Activaci´on lineal saturada Esta se va a diferenciar de la anterior cuando escapemos del intervalo (0,1). 1actLinSat :: Float -> Float 2actLinSat x = 3if x<0 4then 0 5else if x>1 6then 1 7else x 8 9dActLinSat :: Float -> Float 10 dActLinSat x = 2.4. Funciones de Activaci´on 27 11 if x>0 && x<1 12 then 1 13 else 0 14 15 satLin :: ACT 16 satLin =Act actLinSat dActLinSat C´odigo 2.14: Funci´on de Activaci´on Lineal Saturada 3. Sigmoide De esta funci´on que ya hemos hablado de manera extendida en el anterior cap´ıtulo 1sigmoide :: Float -> Float 2sigmoide x = 31/(1+exp(-x)) 4 5dsigmoide :: Float -> Float 6dsigmoide x = 7(sigmoide x) * (1-sigmoide x) 8 9logSig :: ACT 10 logSig =Act sigmoide dsigmoide C´odigo 2.15: Funci´on de Activaci´on sigmoide 4. Tangente Hiperb´olica De esta haskell ya tiene una implementaci´on hecha (tanh), luego basta con implementar la derivada 1dtanh :: Float -> Float 2dtanh x =1-(tanh x)^2 3 4tanSig :: ACT 5tanSig =Act tanh dtanh C´odigo 2.16: Funci´on de Activaci´on Tangente Hiperb´olica 5. Unidad Lineal Rectificada Se anula en valores negativos 1actReLU :: Float -> Float 2actReLU x = 3max 0x 4 5dActReLU :: Float -> Float 6dActReLU x = 7if x>0 then 1else 0 8 9reLU :: ACT 10 reLU =Act actReLU dActReLU C´odigo 2.17: Funci´on de Activaci´on ReLU 28 2. Dise˜no de la aplicaci´on 6. Unidad Lineal Rectificada Suavizada (“leaky” en ingl´es). 1actLeakyReLU :: Float -> Float 2actLeakyReLU x = 3if x<0 4then 0.01*x 5else x 6 7dActLeakyReLU :: Float -> Float 8dActLeakyReLU x = 9if x<0 10 then 0.01 11 else 1 12 13 leakyReLU :: ACT 14 leakyReLU =Act actLeakyReLU dActLeakyReLU C´odigo 2.18: Funci´on de Activaci´on leaky ReLU 7. Funci´on Umbral De gran utilidad para ejemplos de entrenamiento Booleanos. 1actHardLim :: Float -> Float 2actHardLim x =if x>0then 1else 0 3 4dActHardLim :: Float -> Float 5dActHardLim x = 0 6 7hardLim :: ACT 8hardLim =Act actHardLim dActHardLim C´odigo 2.19: Funci´on de Activaci´on Umbral 2.5– Funciones de Error En esta secci´on vamos a implementar las funciones error entre los valores objetivos (que llamaremos ys) y los valores de salida de la red (que llamaremos os). Tambi´en a˜nadiremos las correspondientes derivadas para un uso futuro en los m´etodos de entrenamiento. Los errores con los que trabajaremos son: 1. Error Basado en Entrop´ıa Este error s´olo lo podemos usar cuando los valores objetivos son booleanos {0,1} 1cee :: [Float] -> [Float]->Float 2cee ys os = 3-sum (map (\ (y,o) -> (y*log(o)+(1-y)*log(1-o))) (zip ys os)) 4 5dcee :: [Float] -> [Float] -> [Float] 6dcee ys os = 7zipWith (\ yo-> -y/o+ (1-y)/(1-o)) ys os 8 2.5. Funciones de Error 29 9eCEE :: ERROR 10 eCEE =Error cee dcee C´odigo 2.20: Funci´on de error basada en entrop´ıa con su derivada 2. Error Absoluto Medio 1mae :: [Float] -> [Float]->Float 2mae ys os = 3(sum (zipWith (\ yo-> abs (y-o)) ys os))/(genericLength ys) 4 5dmae :: [Float] -> [Float] -> [Float] 6dmae ys os = 7zipWith (\ yo-> if y<othen 1else -1) ys os 8 9eMAE :: ERROR 10 eMAE =Error mae dmae C´odigo 2.21: Funci´on de error absoluto medio con su derivada 3. Error cuadr´atico Medio 1mse :: [Float] -> [Float]->Float 2mse ys os = 3let n= 1/ (genericLength ys) 4in n*(sum (zipWith (\ yo-> (y-o)^2) ys os)) 5 6dmse :: [Float] -> [Float] -> [Float] 7dmse ys os = 8let n= 1/(genericLength ys) 9in zipWith (\ yo-> 2*n*(o-y)) ys os 10 11 eMSE :: ERROR 12 eMSE =Error mse dmse C´odigo 2.22: Funci´on de error cuadr´atico medio con su derivada 4. Suma de Errores Absolutos 1sae :: [Float] -> [Float]->Float 2sae ys os = 3sum (zipWith (\ yo-> abs (y-o)) ys os) 4 5dsae :: [Float] -> [Float] -> [Float] 6dsae ys os = 7zipWith (\ yo-> (if y<o 8then 1 9else -1)) ys os 10 11 eSAE :: ERROR 12 eSAE =Error sae dsae C´odigo 2.23: Funci´on de suma de errores absolutos con su derivada 30 2. Dise˜no de la aplicaci´on 5. Suma de Errores cuadr´aticos 1sse :: [Float] -> [Float]->Float 2sse ys os = 3(sum (zipWith (\ yo-> (y-o)^2) ys os))/2 4 5dsse :: [Float] -> [Float] -> [Float] 6dsse ys os = 7zipWith (\ yo-> o-y)ys os 8 9eSSE :: ERROR 10 eSSE =Error sse dsse C´odigo 2.24: Funci´on de suma de errores cuadr´aticos con su derivada En la actualidad existen muchas otras funciones error o versiones distintas de las antes mencionadas, pero est´as son las m´as comunes con diferencia. 2.6– M´etodos de Entrenamiento En esta secci´on atacaremos dos m´etodos de entrenamiento para nuestras redes neuronales, la regla Delta y el modelo de entrenamiento con todos los ejemplos, tambi´en conocido como Batch. Antes de esto cabe destacar la utilidad de dos funciones que van a servir de gran ayuda. La primera es una funci´on que devuelve los valores de salida de una red a la que le damos unos valores de entrada xs. 1salidaRed :: [Float]->FNN -> [Float] 2salidaRed xs (Net _ ws fs) = 3let ass=M.toList (foldl (\ x(w,Act f df)->fmap f ((M.fromLists [[-1]] M.<|> x)*w)) 4(M.fromLists [xs]) (zip ws fs)) 5in ass C´odigo 2.25: Funci´on salida de una red A la hora de los entrenamientos como el del tipo gradiente vamos a necesitar los valores de entrada de cada unidad, su valor al aplicar la funci´on de activaci´on y la derivada correspondiente. 1valorEntradaSalidaDerivada :: [Float]->FNN -> [([Float],([Float],[Float]))] 2valorEntradaSalidaDerivada xs (Net _ ws fs) = 3map (\(x,y,z) -> (M.toList x,(M.toList y,M.toList z))) 4(scanl (\ (x,y,z) (w,Act f df)->let ins = (M.fromLists [[-1]] M.<|> y)*w 5in (ins,fmap f ins ,fmap df ins)) 6((M.fromLists [xs]),(M.fromLists [xs]),(fmap (derAct (head fs)) (M.fromLists [ xs]))) (zip ws fs)) C´odigo 2.26: Funci´on Auxiliar para los valores de las unidades Esta funci´on a partir de unos valores de entrada y una red nos da una lista de ternas de vectores (a,b,c) donde •aes el vector de valores de entrada de la capa i-´esima. 2.6. M´etodos de Entrenamiento 31 •bes el vector de valores al evaluar la funci´on de activaci´on i.e. g(a). •ces el vector de valores al evaluar la derivada de la funci´on de activaci´on i.e. g0(a). Realmente no es una terna, la salida de la funci´on es de la forma (a,(b,c)) la cual es un par dentro de otro para extraerlos m´as f´acilmente a posteriori con combinaciones de las funciones predefinidas fst ysnd. Debemos aclarar que nuestros ejemplos de entrenamiento ser´an listas de pares ordenados formados por un vector de entrada y su vector objetivo correspondiente (xs, ts). Ya estamos a disposici´on de comenzar con los m´etodos de entrenamiento en s´ı. Lo dividiremos en dos secciones, unicapa y multicapa. 2.6.1. Entrenamiento del Perceptr´on Simple Dentro de que estamos aplicando el m´etodo del gradiente, utilizaremos dos reglas de aprendizaje: Delta y Batch. La diferencia principal entre estas dos es que la regla Batch calcula el error entre todos los ejemplos de entrenamiento y los valores de salida de nuestra red y ya despu´es actualiza los pesos de la red, mientras que la regla Delta va calculando el error y actualizando los pesos para cada ejemplo del conjunto de entrenamiento. 1. Regla de Aprendizaje Delta 1entrenoPerceptronDelta :: FNN -> [([Float],[Float])] -> Float -> ERROR -> FNN 2entrenoPerceptronDelta (Net ns [w] [f]) zs eta (Error error derror) = 3Net ns [foldl (\ rz-> 4let ins =M.toList ((M.fromLists [(-1):(fst z)])*r) 5fin =map (activ f)ins 6[errorin]=zipWith (-) fin (snd z) 7nw =r- (M.transpose (fmap (*(eta*errorin)) 8(M.fromLists [(-1):(fst z)]))) 9in nw)w zs] [f] C´odigo 2.27: Entrenamiento del Perceptr´on simple con regla de aprendizaje Delta donde zs es la lista de ejemplos de entrenamiento y eta es el factor de aprendizaje del cual ya hemos hablado en el cap´ıtulo 1. 2. Regla de entrenamiento Batch. 1entrenoPerceptronBatch :: FNN -> [([Float],[Float])] -> Float -> ERROR -> FNN 2entrenoPerceptronBatch (Net ns [w] [f]) zs eta (Error error derror) = 3let erroresB =scanl (\ rz-> let ins =M.toList ((M.fromLists [ (-1):( fst z)])*w) 4fin =map (activ f)ins 5dfin =map (derAct f)ins 6[errorin]=zipWith (-) fin (snd z) 7in M.transpose (fmap (*(eta*errorin)) (M. fromLists [(-1):(fst z)]))) w zs 8in Net ns [foldl (\ re-> r-e)w erroresB ] [f] C´odigo 2.28: Entrenamiento del Perceptr´on simple con la regla de aprendizaje Batch 38 3. Manual de uso perceptrones multicapa, empecemos con un ejemplo booleano como en la secci´on anterior, la funci´on XOR. Figura 3.3: Gr´afica de la funci´on XOR Como podemos observar en la gr´afica, no es una funci´on linealmente separable, luego no tendr´ıamos convergencia con el perceptr´on unicapa, con una sola capa oculta de tres unidades podremos conseguir una alta precisi´on, luego nuestro perceptr´on ser´a de la forma: Figura 3.4: Red Neuronal Multicapa para la funci´on XOR Esta vez usemos el m´etodo de iniciaci´on con valores aleatorios acotados (entre ±0,5) para visualizar un uso pr´actico del mismo. El dominio es el mismo que en la funci´on AND pero con imagen diferente: 1fXOR :: Float -> Float -> Float 2fXOR x y =if x/= ythen 1else 0 3 4ejemplosXOR =map (\ [x,y] -> ([x,y],[fXOR x y])) entrada 5 6redXOR =newffRand (0,1) [2,3,1] [hardLim,hardLim] C´odigo 3.9: Red y ejemplos de entrenamiento para la funci´on XOR 3.2. Perceptr´on Multicapa 39 Ahora pues entrenemos con la rutinas de aprendizaje Batch, comencemos por el m´etodo de parada Epsilon 1entrenaRedfXORBatchEpsilon = 2gradienteDeltaEpsilon 0.5 redXOR ejemplosXOR 0.1 eSSE C´odigo 3.10: Rutina de entrenamiento para la funci´on XOR con el criterio de parada Epsilon Ahora estamos entrenando con un factor de aprendizaje η= 0,1 y bajo el error de la Suma de Errores Cuadr´aticos y con cota de error = 0,5. Observemos que realmente termina la rutina 1>map (\x-> salidaRed x entrenaRedfXORBatchEpsilon)entrada 2[[0.0],[1.0],[0.0],[1.0]] C´odigo 3.11: Salida de la red para la funci´on XOR con el criterio de parada Epsilon Y para 2 iteraciones veamos que ya tenemos una red que nos devuelve exactamente todos los valores iguales 1entrenaRedfXORBatchEpochs = 2gradienteBatchEpochs 2redXOR ejemplosXOR 0.1 eSSE C´odigo 3.12: Red para la funci´on XOR con el criterio de parada Epochs Luego aqu´ı vemos que es mejor hacer las iteraciones puesto que nos devuelve bien todos los valores de entrada 1>map (\x-> salidaRed x entrenaRedfXORBatchEpochs)entrada 2[[0.0],[1.0],[0.0],[1.0]] C´odigo 3.13: Salida de la red para la funci´on XOR con el criterio de parada Epochs 3.2.2. Funci´on Continua Cojamos como ejemplo ahora algo m´as complejo, una funci´on continua, particularmente la funci´on f:R−→ R x7−→ f(x) = sin x 2 Figura 3.5: Representaci´on Gr´afica de f 40 3. Manual de uso Ahora, al ser el dominio finito obviamente no vamos a dar todos los puntos, usaremos la siguiente lista de puntos equidistantes entre −7 y 7 con sus respectivas im´agenes: 1lsx = [-7.0 , -6.26315789, -5.52631579, -4.78947368, -4.05263158, 2-3.31578947, -2.57894737, -1.84210526, -1.10526316, -0.36842105, 30.36842105, 1.10526316, 1.84210526, 2.57894737, 3.31578947, 44.05263158, 4.78947368, 5.52631579, 6.26315789, 7.0 ] 5 6lsy =map ((/2).sin)lsx :: [Float] 7 8ejemplos =zipWith (\ xy-> ([x],[y])) lsx lsy C´odigo 3.14: Ejemplos para la funci´on f Para este caso vamos a usar m´as unidades en la capa oculta que en el ejemplo anterior, le vamos a dar la siguiente estructura Figura 3.6: Red Neuronal Multicapa para la funci´on f Los pesos iniciales ser´an generados aleatoriamente de nuevo, esta vez en un rango entre 0 y 1, quedando de la siguiente forma 1redSin =newffRand (0,1) [1,5,1] [logSig,logSig] C´odigo 3.15: Red neuronal para la funci´on f Ahora veamos las diferencias que podemos llegar a conseguir con las dos rutinas de entrenamiento con el m´etodo de parada Epochs, fijando 500 iteraciones, veamos primero la versi´on Batch 1redSinSolBatch = 2gradienteBatchEpochs 500 redSin ejemplos 0.1 eSSE C´odigo 3.16: Entrenamiento Batach para la funci´on fbajo 500 iteraciones 3.2. Perceptr´on Multicapa 41 la cual nos da un error 1>errorRed redSinSolBatch ejemplos eSSE 25.7890754e-2 C´odigo 3.17: Error de entrenamiento Ahora bien, veamos la versi´on delta 1redSinSolDelta = 2gradienteDeltaEpochs 500 redSin ejemplos 0.1 eSSE C´odigo 3.18: Entrenamiento Delta para la funci´on fbajo 500 iteraciones que genera el siguiente error 1>errorRed redSinSolDelta ejemplos eSSE 20.124147944 C´odigo 3.19: Error de entrenamiento Como podemos observar, la diferencia entre las dos rutinas es bastante notoria para llevar 500 iteraciones, (diferencia del error entorno al 0,05) el error de la rutina Delta est´a doblando al error de la rutina Batch. Observando con el error de la versi´on Batch, tenemos asegurada la convergencia bajo una cota de error de 0,0579, es decir, que podemos entrenar la red con el m´etodo de parada Epsilon con = 0,1 por ejemplo, sin temor a que no termine: 1redSinSolBatchEpsilon = 2gradienteBatchEpsilon 0.1 redSin ejemplos 0.1 eSSE C´odigo 3.20: Entrenamiento Batch con el m´etodo de parada Epsilon Y efectivamente, podemos comprobar que el error es menor que la cota 1>errorRed redSinSolBatchEpsilon ejemplos eSSE 29.135607e-2 C´odigo 3.21: Error de entrenamiento CAP´ ITULO 4 Conclusiones En est´a implementaci´on intentamos acercarnos, de manera introductoria, a este complejo mundo que se sigue desarrollando hoy en d´ıa, si bien aqu´ı hemos usado ejemplos algo b´asicos, la profundidad de aprendizaje de las redes puede llegar a ser realmente compleja (como ya hablamos en el cap´ıtulo 1). Lejos de estar completamente optimizada, creemos que con esta librer´ıa se podr´ıan resolver problemas m´as complejos haciendo uso de ordenadores m´as potentes. Aunque sobre redes neuronales la librer´ıa Neurolab resulta muy atractiva por su sencilla comprensi´on, a la hora de la verdad esta se queda muy corta en cuanto a la complejidad de las redes que puede modelar, para estos casos algunas de las m´as utilizadas son Keras [9] y TensorFlow [16]. Tambi´en existen librer´ıas en Haskell que proporcionan funcionalidades para definir y entrenar redes neuronales, tales como Neural [7]. La librer´ıa Neural de Haskell, adem´as de poseer una gran flexibilidad a la hora de generar las redes neuronales y entrenarlas, tiene la gran ventaja de usar la derivaci´on autom´atica con la librer´ıa ad [4] para automatizar el algoritmo de descenso por el gradiente en el proceso de retropropagaci´on. 4.1– Ampliaciones futuras 1. Ser´ıa muy recomendable el uso de la librer´ıa ad [4], no s´olo por las ventajas que ofrecen en Neural, sino que adem´as podr´ıamos ahorrarnos el hecho de tener que implementar cada funci´on de activaci´on con su respectiva derivada (tambi´en seria m´as f´acil para el usuario generar nuevas funciones de activaci´on). 2. Una gran desventaja a la hora de usar funciones con el tipo de dato Data.Matrix es que al actualizar una matriz, por muy peque˜no que sea el cambio, se crea una copia entera de la misma. Esto genera una gran ineficiencia puesto que estamos gastando una gran cantidad de memoria en el algoritmo. ¿C´omo podemos resolver este problema? Una de las opciones es usar la interfaz de MArray para arrays mutables [5]. Con estos arrays mutables podemos modificar la matriz de pesos entrada a entrada sin tener que genera una copia entera en cada paso. 3. El mayor inconveniente es el tiempo de convergencia. Las aplicaciones reales pueden llegar a tener miles de ejemplos en el conjunto de entrenamiento y ello requiere 43 44 4. Conclusiones d´ıas de tiempo de c´alculo. Adem´as la retropropagaci´on es susceptible de fallar en el entrenamiento, es decir, la red puede que nunca llegue a converger. ¿C´omo podemos solucionar esto? A˜nadiendo a la librer´ıa algunas de las variaciones del algoritmo que ya hemos comentado en el cap´ıtulo 1, tales como a˜nadir momentum o modificar el factor de aprendizaje ηen cada iteraci´on, a uno cada vez m´as peque˜no. Bibliograf´ıa [1] G. Cybenko, G. Approximation by superpositions of a sigmoidal function. Math control Signal Systems 2 , pp.303 - 314, 1989. [2] G. Cybenko, Continuous Valued Neural Networks with Two Hidden Layers are Sufficient. Department of Computer Science, Tufts University, 1988. [3] R. O. Duda y P. E. Hart, Pattern classification and scene analysis. Wiley, 1973. [4] Haskell, ad: Automatic Differentiation. Consultado en https://hackage.haskell.org/package/ad [5] Haskell, Data.Array.MArray . Consultado en http://hackage.haskell.org/package/array-0.5.4.0/docs/Data-Array-MArray.html . [6] Haskell, Data.Matrix . Consultado en https://hackage.haskell.org/package/matrix-0.3.6.1/docs/Data-Matrix.html . [7] Haskell, Neural Cosultado en https://hackage.haskell.org/package/neural [8] K. Hornik, Approximation capabilities of multilayer feedforward networks. Neural Networks, Volume 4, Issue 2, pp. 251-257, 1991. [9] Keras, Consultado en https://keras.io/ [10] F. J. Mart´ın Mateos y J. L. Ruiz Reina, Introducci´on a las redes neuronales Apuntes de la asignatura de Inteligencia Artifical, Tema 2, 2018. [11] W. S. McCulloch and W. H. Pitts, A Logical Calculus of the Ideas Immanent in Nervous Activity. The bulletin of mathematical biophysics volume 5, pp. 115–133,1943. [12] M. Minsky and S. Papert, Perceptrons. M.I.T. Press, 1969. [13] Tom M. Mitchell, Machine Learning. McGraw-Hill Science/Engineering/Math, 1997. [14] Python, Neurolab 0.3.5 documentation. Consultado en https://pythonhosted.org/neurolab/ [15] S. Russell and P. Norvig, Artificial Intelligence: A Modern Approach. Prentice Hall, 2010. 45 46 Bibliograf´ıa [16] TensorFlow, Consultado en https://www.tensorflow.org/ [17] B. Widrow y M. E. Hoff, Adaptative Switching Circuits. IRE WESCON Convention Record, 1960.