490 likes | 678 Views
Redes Neuronales y Programación Declarativa. Francisco Jesús Fernández Burgos José Manuel Cortés López. ÍNDICE . 1. Introducción 1.1. Haskell y la Computación Numérica 1.2. Computación Celular 1.3. Redes Neuronales 1.3.1 Redes Neuronales Celulares 1.4. Objetivos
E N D
Redes Neuronales y Programación Declarativa Francisco Jesús Fernández Burgos José Manuel Cortés López
ÍNDICE • 1. Introducción • 1.1. Haskell y la Computación Numérica • 1.2. Computación Celular • 1.3. Redes Neuronales • 1.3.1 Redes Neuronales Celulares • 1.4. Objetivos • 2. Construcción de una librería de Redes Neuronales en Haskell • 2.1. Estructura de Datos • 2.2. Análisis lineal sin Índices • 2.3. Iteración y Recursión.
ÍNDICE • 3. Definición de Capas • 3.1 Definición de una Capa • 3.2 Definición de múltiples Capas • 4. Ventajas de Usar Haskell • 5. El perceptrón Simple • 5.1 Introducción. • 5.2 Ejemplo de entrenamiento • 5.2.1 Entrenamiento 1ªiteración • 5.2.2 Entrenamiento 2ªiteración • 5.3 Otro Ejemplo de entrenamiento sobre la máquina. • 6. Estudio Comparativo: Haskell vs. Matlab
ÍNDICE • 7. NeuroScheme • 7.1 Introducción • 7.2 Seis Razones para elegir la programación funcional • 7.3 Arquitectura de la Herramienta • 7.4 Interfaz con el Sistema • 7.5 Interfaz Gráfica de Usuario • 7.6 Implementación de RNAS • 7.7 Resultados Obtenidos • 8. Conclusiones • 8.1 Conclusiones Haskell • 8.2 Conclusiones NeuroScheme • 8.3 Trabajo Futuro • 9. Referencias
1. Introducción • En la actualidad, la gran mayoría del software de simulación y entrenamiento de redes neuronales es desarrollado mediante lenguajes imperativos como C++, Java... • Usaremos Haskell, como alternativa para la implementación de algoritmos de simulación y entrenamiento de redes neuronales aprovechando las potencialidades que este ofrece. • Se mostrará que es posible evitar el uso de tablas e índices para la implementación de redes neuronales feedforward multicapa, generando un código claro, simple y corto en comparación con los lenguajes imperativos. • Se verá como Haskell puede ser adecuado para la experimentación con nuevos algoritmos de entrenamiento de redes neuronales gracias a su similitud sintáctica con la matemática y las fortalezas del lenguaje.
1.1 Haskell y La computación Numérica • La programación funcional ofrece la oportunidad de crear un código mucho más comprensible y fácil de manejar gracias: • La similitud sintáctica con la matemática. • Los altos niveles de abstracción permiten crear un código más estructurado y reusable. • No se pide obtener una alta eficiencia en tiempo por parte de Haskell, pues su misma naturaleza como lenguaje de alto nivel lo impide. • La relativa juventud de este tipo de programación ofrece un gran campo de investigación en el cual se puede pensar en buscar nuevas alternativas: • Para la construcción de compiladores más eficientes. • Como también en la formación de alianzas con lenguajes de bajo nivel para la optimización de algunasoperaciones • Lo importante a destacar estriba en las posibilidades que tiene Haskell para la creación y experimentación de nuevos algoritmos en el campo de la computación numérica.
1.2 Computación celular • Este nuevo paradigma computacional suministra nuevas formas de hacer la computación más eficiente (en términos de velocidad, coste, disipación, almacenamiento y calidad de la solución) para tratar grandes problemas en dominios de aplicación específicos. • La computación celular se basa en tres principios: • Simplicidad • Paralelismo inmenso • Localidad
1.3 Redes Neuronales • Una red de neuronas artificiales está caracterizada por su: • Arquitectura: Estructura o patrón de conexiones entre las unidades de proceso • Dinámica de la Computaciónque nos expresa el valor que toman las unidades de proceso y que se basa en unas funciones de activación (o de transferencia) que especifican como se transforman las señales de entrada de la unidad de proceso en la señal de salida. • Algoritmo de Entrenamiento o Aprendizaje: Procedimiento para determinar los pesos de las conexiones • Una característica muy importante de estas redes es su naturaleza adaptativa, donde el "aprendizaje con ejemplos" sustituye a la "programación" en la resolución de problemas.
1.3.1 Redes Neuronales Celulares • Las redes neuronales celulares están constituidas por un conjunto de unidades de proceso, llamadas neuronas, cuyos valores posibles pueden ser discretos o continuos y el valor que presenta cada unidad neuronal viene dado por una función que depende de una combinación lineal de los estados de las unidades vecinas. (potencial sináptico) • Es por esta definición funcional que vamos a utilizar un lenguaje funcional para describirlas.
1.4 Objetivos • Mostrar que es posible aprovechar la potencia expresiva de Haskell para la definición eficiente de las redes neuronales. • Mostrar que es posible crear una aplicación, a partir de la semántica de un lenguaje funcional, para trabajar con redes neuronales y estudiarlas.
2. Construcción de una librería de Redes Neuronales en Haskell • Para construir un algoritmo en programación funcional, este debe ser visto como una función explicita, al cual se le ingresa unos valores de entrada para retornar una salida, de manera similar una red neuronal se comporta como una función. La figura nos presenta de manera esquemática la relación.
2.1 Estructura de datos • Al momento de representar una matriz haciendo uso de las programación funcional es necesario construir una estructura de datos que haga uso de listas en vez de tablas e índices por los siguientes motivos: • Las listas son la estructura lineal más importante de Haskell, además cuenta con un gran número de funciones y operaciones para utilizarlas. • A parte de la poca expresividad, la representación de una matriz indexada en Haskell es poco eficiente, ya que los valores al ser atrapados en el constructor de datos Array, son de difícil acceso y esto tiene un costo computacional. • La siguiente figura muestra como se representa una matriz por medio de listas de listas, donde cada una de ellas representa una fila de la matriz.
2.2 Álgebra Lineal sin Índices • El siguiente paso consiste en desarrollar una librería de operaciones básicas de álgebra lineal para construir los algoritmos de entrenamiento. Para ver el proceso de construcción observe en la siguiente figura, la función zipmatrizse usa para definir funciones que respectivamente sumen, resten y multipliquen elemento a elemento dos matrices, esta abstracción hace uso del concepto de función de alto nivel. Nota: Código de Cesar Augusto Acosta Minoli (estas funciones podrían sustituirse por funciones predefinidas en haskell)
2.3 Iteración y Recursión • El entrenamiento de una red neuronal es un proceso iterativo en el cual la red actualiza sus pesos y umbrales hasta que se cumpla un criterio de parada. • El modelo imperativo de programación implementa la iteración y la actualización por medio de ciclos y asignaciones. Sin embargo la iteración y la actualización de variables se puede superar por medio de declaraciones recursivas. • La figura muestra la función fIter la cual realiza un proceso Iterativo mediante la recursión. • fIter se define haciendo uso de sí misma y hace uso de valores enteros para determinar el número de ciclos de la iteración ( init. y final). En la llamada recursiva init aumenta en una unidad y el proceso termina una vez init sea igual a final, de lo contrario sigue modificando el valor g a través de alguna función h.
2.3 Iteración y Recursión • Los elementos mencionados anteriormente son de suma importancia para la construcción de los algoritmos de entrenamiento. A continuación se mostrará algunos de los elementos implementados. • La implementación llevada a cabo se realizó pensando en los algoritmos de entrenamiento de redes feedforward multicapa, la arquitectura de una capa de este tipo de red luce como en la siguiente figura:
2.3 Iteración y Recursión • Por lo tanto es necesario declarar los siguientes tipos: • Los tipos Input y Target no son más que una redeclaración de una matriz de tipo Float. • Por su parte el tipo NeuralNetwork se define como una pareja ordenada donde el primer componente corresponde a la matriz de pesos y la segunda componente corresponde a la matriz de umbrales de la capa, es decir (W,b).
3. Definición de una capa • Para simular una capa se definió la función simlayer: • Podemos observar la gran similitud entre la descripción teórica de la red neuronal y su implementación en haskell. • Una capa de la red multicapa que estamos desarrollando se puede expresar como:
3.1.1. Función de transferencia • Un hecho interesante estriba en que la función de activación f puede ser definida en un modulo anterior y luego ser llamada, bien se puede definir una arquitectura perceptrón o una Adalainerespectivamentecomo : • simLayer p (w,b) hardlim • simLayer p (w,b) pureline
3.2 Definición de múltiples capas • La función anterior nos permite definir una función para el caso en el cual tenemos una arquitectura de cualquier cantidad de capas y neuronas en cada capa. Nota: Código de Cesar Augusto Acosta Minoli
4. Ventajas de usar Haskell • Un hecho interesante estriba en que la cantidad de código para la creación de la librería es realmente pequeño en comparación con otros lenguajes de programación. (No supera los 70K), para apreciar esto en detalle observe el código la función trainperceptron. Nota: Código de Cesar Augusto Acosta Minoli (Hay funciones que deberían estar mas optimizadas a la programación funcional)
5. El perceptrón Simple 5.1 Introducción. • Se usan en problemas de clasificación y predicción, minimizando los errores de clasificación incorrectos. • Arquitectura de la Red : • N sensores de entrada : x1,x2,…,xN pertenecientes a R • 1 unidad de proceso: y perteneciente a {0,1} ó {-1,1} • Regla de aprendizaje: • Memorizamos p pares de patrones : {x1,z1}, {x2,z2},…,{ xp,zp}
5.1 El perceptrón Simple Introducción. • Dinámica de la computación: • y = f ( u ) • θ : umbral o sesgo • h = • wi : pesos sinápticos asociados a xi • función de transferencia paso → y pertenece a {0,1} • f = • función de transferencia signo → y pertenece a {-1,1}
5.1 El perceptrón Simple Introducción. • η(k) : tasa de aprendizaje, que optimiza la convergencia de la red.
5.2 Ejemplo de entrenamiento • Vamos a tener dos clases de patrones de entrada posibles • los de CLASE A • los de CLASE B • Se desea que nuestro perceptron después de un proceso de aprendizaje pueda diferenciar patrones de ambas clases. • Patrones de entrada • clase A={ (-0.5, -0.5), (-0.5, 0.5) } • clase B={ ( 0.3, -0.5), (0.0, 1.0) } • Para ello se desea que cuando le llegue un patrón de la clase A devuelva un 1 y cuando llegue un patrón de la clase B devuelva un 0. • Z(Clase A) = 1 • Z(Clase B) = 0
5.2.1 Entrenamiento 1ªiteración • Inicialmente nuestra matriz de pesos sinápticos va a ser: w1 = -0.3 w2 = 0.5 umbral = 1 • Estos valores son dados aleatoriamente, podrían haberse dado otros cualesquiera. • 1º Selecciono un patrón de entrada aleatorio, por ejemplo el patrón de la clase B = (0.0, 1.0). • 2º Calculo el potencial sináptico que le ha llegado al perceptron. • El potencial sináptico es el resultado de sumar cada una de las entradas del perceptron multiplicadas por el peso sináptico correspondiente para cada entrada. • h (x1, x2) = w1*x1 + w2*x2 • En este caso h=-0.3*0.0 + 0.5*1.0 = 0.5
5.2.1 Entrenamiento 1iteración • Como h es menor que el umbral (u = 1 ) entonces el perceptron pondrá a la salida uno 0 • El perceptrón estará determinado por la función paso, es decir si el potencial sináptico es mayor que el umbral entonces pone a la salida un 1, de lo contrario pondrá un 0. • En este caso el PERCEPTRON HA ACERTADO (ya que le hemos introducido un patrón de la clase B y lo ha clasificado correctamente devolviendo un 0, luego NO SUFRE PROCESO DE ENTRENAMIENTO. • Si se hubiese equivocado, entonces se produciría el proceso de aprendizaje, mediante el cual se producirán cambios oportunos en los pesos sinápticos, con objetivo de aceptar en el próximo patrón.
5.2.2 Entrenamiento 2iteración • Ahora cogemos otro patrón cualquiera de entrada, por ejemplo uno de la clase A : (-0.5, 0.5) • el Potencial sináptico será: • h= (-0.3)*(-0.5) + 0.5 * 0.5 = 0.4 • h < umbral luego entonces se devuelve un 0. • (Esto no coincide con la salida deseada, pues para patrones de la clase A, es un 1.) • Puesto que se ha equivocado nuestro perceptron ha de aprender de sus errores y modificar su matriz de pesos sinápticos W, para asi realizar una mejor clasificación de patrones.
5.2.2 Entrenamiento 2iteración • Según expusimos anteriormente: • n es el patrón de aprendizaje n=0.1 • wi(1): peso sináptico de la entrada i, durante la iteración 1. • xi : valor de la entrada i • zi : Salida deseada para la entrada i • yi : Salida Obtenida para la entrada i • u(i): umbral durante la iteración i • Wi(2) = wi(1) + η[SalidaDeseada - SalidaObtenida]* xi ósea nos quedaría que: • w1(2) = -0.3 + η(1-0)*(-0.5) = -0.35 • w2(2) = 0.5 + η(1-0)*0.5 = 0.55 • u(2) = 1 + η(1-0)* (-1) = 0.9
5.2.2 Entrenamiento 2iteración • Ahora se ha producido un error en la clasificación y por lo tanto el perceptrón aprenderá y modificara los valores de sus pesos sinápticos y su umbral. • De forma que en sucesivas iteraciones introduciendo nuevos valores de x1 y x2 (y -1 en el umbral) el perceptrón irá aprendiendo hasta conseguir unos óptimos valores de w1, w2 y u , que permitan clasificar correctamente cualquier valor introducido en la entrada.
module ParityProblem where import Transfer import NeuralNetwork import Interface p::Input p= [[0.0,1.0,0.0,1.0,0.0,1.0,0.0,1.0], [0.0,0.0,1.0,1.0,0.0,0.0,1.0,1.0], [0.0,0.0,0.0,0.0,1.0,1.0,1.0,1.0]] t:: Target t= [[0.0,1.0,1.0,0.0,1.0,0.0,0.0,1.0]] main = entrenarPerceptron p t (inicializar 75 [3,3,1]) 3 5.3 Otro Ejemplo de entrenamiento sobre la máquina.
5.3 Otro Ejemplo de entrenamiento sobre la máquina El resultado es el siguiente: "TrainPerceptron, Epoca 0" "TrainPerceptron, Epoca 1" "TrainPerceptron, Epoca 2“ Simulacion : [0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0; 0.0 0.0 1.0 1.0 0.0 0.0 1.0 1.0] Supervision : [0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0; 0.0 0.0 1.0 1.0 0.0 0.0 1.0 1.0] Desea guardar La red? y / n
6. Estudio comparativo: Haskell vs. Matlab • El estudio comparativo muestra que el desempeño de la librería es bastante bueno teniendo como referente a Matlab para los problemas propuestos. • El uso de un lenguaje funcional también muestra un código claro, corto en comparación con los lenguajes imperativos y sin la necesidad de usar tablas e índices. • Sin embargo se observa que requiere de mucho más tiempo para realizar las operaciones. Lo anterior permite formular la siguiente pregunta: ¿Cuál puede ser el papel de Haskell frente a la computación numérica en la actualidad?
6. Estudio comparativo: Haskell vs. Matlab Todas las pruebas se realizaron en un PC con procesador AMD-ATHLON de 850 Mhz con 256 Mb de memoria, utilizando Windows 98 como sistema operativo. El compilador para la librería en Haskell fue GHC compiler versión 5.04.3 para Windows y los tiempos fueron capturados mediante la función getClockTime, una función pre-definida de Haskell. Para la comparación se usó Matlab versión 6.1.0.450 release 12.1.
7. NEUROSCHEME 7.1 Introducción • Un lenguaje para el modelado de redes neuronales artificiales. • Para el desarrollo de la herramienta se ha seleccionado como lenguaje base al dialecto Scheme. • Scheme define el ámbito de sus definiciones léxicamente, es estructurado en bloques, soportando funciones y continuaciones como objetos de datos que pueden ser pasados como parámetros a funciones, retornados como el valor de una función, y permanecer indefinidamente en memoria.
7.2 Seis razones para elegir la programación funcional. • La programación funcional es mucho más simple, ya que las expresiones son construidas en forma natural inherentemente recursiva. • La programación funcional es mucho más fácil de entender, ya que cada pieza de código ejecuta una tarea específica, facilitando el seguimiento del código. • Es posible ejecutar pruebas para validar el programa. • Las variables locales se declaran directamente como parámetros de las funciones, inicializándose siempre al ser invocada una función, y representa más el nombre para un valor que una localización en memoria, tal como ocurre en C o Pascal.
7.2 Seis razones para elegir la programación funcional. • Es posible alternar el orden de evaluación de las expresiones en los lenguajes funcionales. • Pueden construirse complejas instrucciones con retornos no locales, lo que facilita complejas estructuras de control.
7.3 Arquitectura de la Herramienta • El núcleo de la herramienta es un interprete de Scheme basado en un montículo de memoria. • La herramienta se divide en cuatro grandes partes: • Un módulo de interfaz con el usuario, encargado de administrar las entradas del usuario y los mensajes del sistema, y utilitarios como la historia de comandos. • Un pre-procesador de código fuente • Un compilador. • Una máquina virtual que ejecuta las instrucciones de bajo nivel
7.6 Implementación de RNAS • Se han implementado tres modelos de propagación hacia delante: • Feedforward. • Cascada correlación. • Cascada hacia delante. • Los algoritmos de entrenamiento implementados incluyen: • Regla delta generalizada. • Regla delta con momento. • Gradiente descendente. • Estrategias de evolución. • Temple simulado. • Así como versiones de algunas de ellas combinadas con mínimos cuadrados.
7.7 Resultados Obtenidos • La red neuronal se modela como un tipo de dato propio del lenguaje, lo que implica que se encuentra codificada en lenguaje Scheme, haciendo que la velocidad de los algoritmos de entrenamiento sea tan alta como en las aplicaciones de usuario final disponibles hoy en día (matlab). • La utilización de diálogos como mecanismo primario de comunicación con el usuario de la aplicación, permite que este con unas pocas horas de entrenamiento, y aún sin tener un conocimiento previo del lenguaje Scheme, pueda estar entrenando modelos de redes neuronales artificiales.
8. Conclusiones En el transcurso del trabajo, podemos destacar las siguientes conclusiones: • Se demuestra que no es necesario usar índices y tablas para el diseño e implementación de algoritmos que simulen y entrenen redes neuronales. • Haskell posee grandes posibilidades para el diseño y evaluación experimental de nuevos algoritmos de forma rápida gracias al parecido que tiene con la especificación del problema a implementar y su similitud sintáctica con la matemática. • Los ejemplos usados para el entrenamiento mostraron que las respuestas son de buena calidad, es confiable y se puede usar como cualquier otro simulador de redes neuronales para resolver problemas de tamaño moderado.
8.1 Conclusiones HASKELL • La implementación en Haskell permite que el código sea transparente y ver la forma en que la librería está implementada. • Haskell permite expresar algoritmos de forma clara y simple, esto es útil en el momento de desarrollar y de derivar versiones más eficientes a bajo nivel. • Comparación Haskell vs. Matlab: • Haskell como lenguaje de programación funcional puro, aún no está preparado para competir por la eficiencia en tiempo, su característica de lenguaje de alto nivel le impide tal rapidez, por tal motivo: • Es necesario la generación de alianzas con lenguajes de bajo nivel que se encarguen de hacer el trabajo pesado y menos significativo (es el caso del producto de matrices.)
8.1 Conclusiones HASKELL • Como ejemplo de estas alianzas, muchos de los algoritmos de Matlab están desarrollados en una eficiente librería de bajo nivel diseñada para el álgebra lineal numérica (conocida como LAPACK) • Adicionalmente Matlab hace un uso cuidadoso de C y ensamblador en muchas de sus rutinas.Estas alianzas han logrado optimizar significativamente las operaciones que se pueden realizar en Matlab (véanse graficas comparativas) • Un detalle a destacar de la librería mostrada es que no aprovecha toda la potencia expresiva de la programación funcional, haciendo caso omiso al sistema de clases y no aprovechando las funciones predefinidas del lenguaje
8.2 Conclusiones NEUROSCHEME • El interprete implementado es altamente versátil, permitiendo construir algoritmos para la manipulación y entrenamiento de RNAs, de tal forma, que es posible automatizar procesos, y construir modelos complejos de RNAs. • Los resultados obtenidos hasta ahora, permiten concluir que debe continuarse con el desarrollo de la herramienta, e incorporarse otros paradigmas como Redes Neurodifusas, y Sistemas Borrosos, para habilitar la herramienta para construir sistemas híbridos para solución de problemas.
8.3 Trabajo Futuro • Se hace necesario un estudio sobre las posibilidades de hacer una alianza entre lenguajes de bajo nivel y Haskell para la construcción de algoritmos precompilados de bajo nivel que puedan ser usados por Haskell. • Es necesario desarrollar una interfaz visual en Haskell que muestre de manera más amigable los resultados de entrenamiento,(así como “plot” en Matlab) donde se puedan apreciar graficas que muestren la evolución. • A nivel teórico es necesario observar las posibilidades que Haskell ofrece para el diseño de nuevos algoritmos de redes neuronales puramente funcionales, explicando la teoría de las redes desde el lambda cálculo.
9. Referencias • 1. Blas C. Ruiz Jiménez...[et al.], “Programación funcional con Haskell” Málaga : Universidad, Secretariado de Publicaciones, D.L. 1995 • 2. Acosta Minoli, C. A. “Artículo sobre implementación de Redes Neuronales.”(2004)Universidad del Quindío, Colombia. • 3. Hudak et al . (2000), “A Gentle Introduction to Haskell , Tutorial”. http://www.haskell.org/tutorial/ • 4. FREEMAN, J.A. Y SKAPURA D.M,(1993) “Redes Neuronales: Algoritmos, aplicaciones y técnicas de programación”. Addison Wesley. 1993
9. Referencias • 5. Martín del Brío B., A. Sanz,(2001) “Redes neuronales y Sistemas Borrosos”. Madrid : Ra-Ma, 2ª ed. • 6. HUGHES, J. (1990) “Why Functional Programming Matters”, Institutionen för Datavetenskap, Chalmers Tekniska Högskola, 41296 Göteborg, SWEDEN. • 7. Mark P Jones, Alastair Reid, the Yale Haskell Group, and the OGI School of Science & Engineering at OHSU, (1994-2002) “The Hugs 98 User Manual”, web: http://cvs.haskell.org/Hugs/pages/hugsman/index.html
9. Referencias • 8. José R. Hilera y Victor J Martinez."REDES NEURONALES ARTIFICIALES". Madrid : Ra-ma, [1995] • 9. VELÁSQUEZ J. D., “NEUROSCHEME: UN LENGUAJE PARA EL MODELAMIENTO DE REDES NEURONALES ARTIFICIALES”, Grupo de Inteligencia Artificial, Facultad de Minas, Universidad Nacional de Colombia, Junio de 2005. • 10. Muñoz J., ”APUNTES DE LA ASIGNATURA MODELOS COMPUTACIONALES”, www.lcc.uma.es/LCCTemario/Asignatura.jsp?idasignatura=22, Escuela Superior de Ingeniería Informática, Universidad de Málaga, Abril 2006.