martes, 16 de octubre de 2012

Redes neuronales MLP en un PIC? se puede?

Lo se, mucho tiempo ha pasado desde la ultima actualizacion ( casi 2 años ) debido a que me decante por otro tipo de investigación. Sin embargo hace un mes casi, en un comentario que acabo de controlar recién se ha planteado la pregunta: es posible implementar una red MLP en un PIC ( programable interrupt controler, también conocido como microcontrolador ).
Dependiendo del tipo de escenario, es factible su realizacion, pero vamos a analizar dos casos:

Programacion del PIC para entrenar una red: para entrenar una red, además del calculo de la salida ( y las respectivas multiplicaciones ) hay que hacer también el calculo del error, el calculo del error cuadrático medio y la actualizacion de los pesos sinapticos de cada coneccion. Y esto por cada ciclo de entrenamiento hasta que el entrenamiento finaliza. Entonces por poner un ejemplo numérico: 3 perceptrones a la entrada, 5 en la capa oculta y 1 en la salida ( sin bias ). Esto nos da 15 conecciones sinapticas. ahora hipotizamos un ciclo de entrenamiento de 20 etapas.

  1. 15 multiplicaciones para el calculo de la salida
  2. 3 multiplicaciones para aplicar los valores de entrada ( el tiempo de proceso depende de la función de transferencia y de la arquitectura del PIC )
  3. calculo de error cuadrático medio ( elevar al cuadrado el valor de la salida obtenida y la esperada, restar y sacar raíz cuadrada, aproximamos a 6 multiplicaciones, pero depende de la arquitectura de la ALU )
  4. actualizacion de los pesos sinapticos ( según el método, si se usa la ley del gradiente se necesitan cálculos de derivadas, para la ley de Kohonen basta una suma vectorial )
  5. actualizar los pesos sinapticos ( 15 para la capa oculta, 5 para la salida. 20 sumas )
Y esto multiplicarlo por las 20 etapas de entrenamiento. Eso es mucho para un chip que va a 20MHz, aun teniendo en cuenta la modesta dimensión de la red. Y obviamente depende mucho de la habilidad del programador en hacer un código eficiente ( en mi programa yo se que desperdicio muchos ciclos, pero eso es para una demostración, nada profesional )

Programacion del PIC para calcular la red ya entrenada: en este caso, usando la misma red de antes solo necesitamos del calculo de la salida: 15 multiplicaciones... si! nada mas que 15 multiplicaciones. Yo he hecho esta prueba entrenando una red neuronal para dividir el ruido de fondo de la colisión de positrones con electrones ( ahora me dedico a la física ) usando el framework de ROOT y aplicando la red ya entrenada en arduino. Con el entrenamiento en ROOT obtengo 197 pesos sinapticos. Y es que solo basta hacer multiplicaciones de las entradas por los respectivos pesos sinapticos, después sumar los resultados para la salida de cada neurona en la capa oculta ( y así sucecivamente si hay mas capas ocultas ) y lo mismo a la salida, se suma todo y lo que mas se tarda es aplicar la función de transferencia a la salida ( por lo general yo uso la de escalón, mas adapta al envió de información digital y la uso exclusivamente en la salida ).

Entonces en realidad, 20MHz van bien sobrados para hacer una buena cantidad de multiplicaciones, en redes de modesta entidad, siempre que se tenga ya una red entrenada.

EDITO: por cierto, visto que algunos comentan y a mi no me llegan avisos de los comentarios, si teneis alguna pregunta enviarla a jhonellway@gmail.com. Solo tener en cuenta que no soy un experto como lo serìa algun especialista en la materìa o algun PhD en inteligencia artificial.

domingo, 5 de diciembre de 2010

Nuevo modelo para la red neuronal: Taller de C++

En los anteriores talleres hemos visto que para simular las neuronas creamos una clase o función, en esta ocasión con una sola clase simularemos toda la red, de modo que podemos facilmente definir cuantos elementos de entrada, salida y en la capa oculta queremos.
La ventaja esta en el tiempo de ejecución del entrenamiento de la red: si fuera una sola clase para neurona, en casos en los que sean necesarias 20 o mas neuronas el tiempo de entrenamiento seria enorme.
Por motivos de espacio no pongo todo el código fuente en este post, pero podéis obtenerlo desde mi repositorio en http://github.com/Sauruxum/Sauruxum/ .
Para los que no son prácticos con este tipo de servicios, he subido los archivos en http://www.mediafire.com/?9q6sa7rxv27exsm ( Actualizado )

El código  fuente de la red es red.cpp y red.h. Como podréis ver, definimos las salidas de la red con una variable y la entrada a cada elemento es la misma que la salida de los elementos de la capa anterior, a la cual se les aplica o no la función de transferencia ( yo en este caso he decidido de usar exclusivamente la función sigmoidal )

En esta situación es útil crear una matriz para contener ordenadamente los datos de ingreso a cada elemento y tener en la misma variable un identificador de donde proviene el mismo dato.
Para crear una matriz, de modo que sea variable ( de cursos básicos de lenguaje C sabemos que cuando declaramos un vector o matriz estos no pueden cambiar la cantidad de elementos que contienen ) la cual es miembro de la clase red. La función es create_array:

//Crear una matriz de valores "double"
double **create_array( int Row, int Col )
{
    double **array = new double*[Row];
    for ( int i = 0; i < Row; i++ )
        array[i] = new double[Col];
    return array;
}

Este es un método con el cual podemos declarar matrices dinamias ( sin intención de "reinventar la rueda" esta función podéis encontrarlo en textos básicos de C ) y estas matrices se deben declarar para cada capa de la red neuronal.  Otra cosa es que el bias lo declaramos junto a todas las entradas, pero como hemos dicho, se le da un peso sinaptico aleatorio y entrada siempre 1.
Con esta función se deben crear algunas variables, como las que contendrán los pesos sinapticos, el valor del delta ( para actualizar los pesos sinapticos ).
Como dijimos necesitamos un generador de números aleatorios, pero como sabemos los números aleatorios de la librería estándar "no son tan aleatorios", en caso que el entrenamiento falle, nos encontraremos con que el entrenamiento siempre fallara, por lo tanto necesitamos cambiar la semilla para generar números aleatorios siempre distintos por cada ejecución del programa.
Cada parte del entrenamiento de la red la he dividido en funciones simples, y en la definición de las funciones miembros las he ordenado en orden cronológico de uso durante la ejecución.
Tambien se hace necesario guardar los datos del entrenamiento en un archivo para posteriormente recuperarlos, sin embargo la parte para recuperar los datos de una red ya entrenada esta en el código fuente muestras.h

Como nota final para este post dejo un par de comentarios personales:
  • Creo que aunque si mis habitos de programacion son malos, el código fuente esta ampliamente comentado, facilitando la comprension
  • El código es libre y podéis redistribuirlo o modificarlo. En el código vienen algunos ejemplos del uso de la red para los que quieren examinarlo.

viernes, 19 de noviembre de 2010

Tipo de salida del MLP y su uso

Como dijimos antes el el perceptron multicapa los elementos de entrada y los de la capa oculta deben tener una función de transferencia que no sea lineal, entonces solo nos queda como opción la sigmoide y la tangente hiperbólica.
Sin embargo la salida puede tener una función lineal o no lineal, segun el uso que se le da a la red.
Como sabemos las funciones sigmoidal y tangentoide son funciones limitadas en su conjunto imagen para valores del dominio en todo el campo real ( sus valores van de 0 a 1 para la sigmoidal y de -1 a 1 para la tangente hiperbólica ), en cambio una recta adquiere todos los valores de salida en el campo real.
Esto puede ser útil en muchos casos, como ejemplos tenemos para las redes con salida no lineal la posibilidad de representar la salida en "porcentajes" ( un ejemplo de uso real seria en mecánica, una viga en ciertas condiciones de presión/tracción, a que punto esta respecto la tensión de ruptura de la viga ) o también en la clasificación de patrones con salidas discretas "si" o "no" ( en medicina son ampliamente usadas las redes neuronales en la clasificación de tejidos, de modo que se puede reconocer si es tejido cancerigeno o no ). Una cosa que vale decir acerca del uso de estas redes para el calculo de porcentajes es que son muy imprecisas a valores cercanos a los limites, ya que las funciones usadas tienen como limites esos valores, pero nunca los alcanzan.
El perceptron multicapa puede ser usado con salidas continuas en el caso del calculo del valor de una función compleja ( no me refiero a números complejos, que sea claro ) la cual puede adoptar valores relativamente grandes. Con frecuencia se usan para las predicciones meteorológicas o en predicciones económicas.
En todo caso el uso que se le puede dar a una red neuronal es muy amplio, en campos como la medicina, meteorología y economía ( con los ejemplos anteriores ), reconocimiento de patrones ( actualmente hay software que reconoce la escritura usando redes neuronales ) y biometria.

En las dos siguientes entregas desarrollaremos en código en C++ para tratar de simular el funcionamiento del MLP, explicando un nuevo método que usaremos, en el cual no simularemos cada neurona sino la red completa.

domingo, 7 de noviembre de 2010

Curiosidades acerca de las neuronas II

Como otro off topic  hare otras citaciones acerca de las neuronas y del sistema nervioso en general.

El pulpo tiene 300000 millones de neuronas contra las 100000 millones del hombre. Su capacidad de aprender como evitar obstaculos, resolver simples problemas y memorizar patrones ya han sido comprobados por los cientificos de todo el mundo. De hecho se encuentran los llamados "pulpos imitadores", los cuales imitan a ciertos animales venenosos para no ser molestados.

Los nervios que se difunden por el cuerpo "estan hechos de mas neuronas". Por lo general los nervios que conducen los impulsos motorios estan compuestos en gran parte de axones de las neuronas que salen desde el encefalo y muchos sensores son neuronas mas especializadas.

El cerebro consume entre el 20% y el 25% de la energia metabolica basal. No es un misterio que el cerebro sea el organo que mas energia consume, de hecho tambien es uno de los organos que mas sangre y oxigeno necesitan. Casi toda la energia que necesita el cerebro es suministrada por la glucosa ( basicamente azucar ) la cual la transforman en CO2, piruvato, lactato y agua, los cuales son excretados.
Digamos que el esteriotipo de "el cerebro del grupo tiene bajo peso" queda justificado.

Algoritmo Error Back Propagation

El algoritmo "Error back propagation" o simplemente BP, un algoritmo muy utilizado en el campo de la redes neuronales, es el algoritmo usado para entrenar una red MLP. Esto consiste en calcular, como en el caso del perceptron simple, el error cometido a la salida y asi corregir el error en la capa de salida.
Despues este error se debe propagar a la capa oculta: digamos que "cada elemento en la capa oculta tiene parte de responsabilidad en el error cometido a la salida de la red, por lo tanto se debe corregir este error".
Hay que tener en cuenta que la salida de todos los elementos de la capa oculta se conectan a la entrada de cada uno de los elementos de la cada de salida, por lo tanto el valor del error retropropagado para la capa oculta es la suma ponderada del error de los elementos de salida, multiplicado por su respectivo peso sinaptico.
Asi tenemos que el error en la salida es:



Y el error en la capa oculta es:



Donde Z es la salida de los elementos de la capa oculta.
Asi tenemos que la variacion de los pesos sinapticos de la salida y de la capa oculta es respectivamente:





Donde I es la entrada a los elementos de la capa oculta, ya que como dijimos antes, en la capa de entrada no se realiza proceso alguno.

De este modo y repitiendo el entrenamiento hasta reducir el error de salida a un valor minimo o en cualquier modo aceptable, se hace que el MLP aprenda a dar respuesta segun el modo en el que nosotros lo hemos entrenado.
Este es un tipo de entrenamiento supervisado, ya que ademas de dar un patron de ingresos para el entrenamiento, tambien se dan patrones de la salida que se espera de la red.
Como ultima cosa, solo decir que hay muchas variantes de este algoritmo, algunas de esas variantes se utilizaran en futuro, otras solo se citaran como referencia teorica.

jueves, 4 de noviembre de 2010

Tipos de aprendizaje del perceptron: supervisado y no supervisado

Por ahora todos los ejemplos que hemos dado son de aprendizaje supervisado, pero también existen otros métodos de aprendizaje y que es necesario explicar para entrar completamente en la parte de los algoritmos de entrenamiento.
Cabe distinguir dos tipos de aprendizaje:
  • Aprendizaje supervisado
  • Aprendizaje no supervisado
El primero consiste en hacer como hemos hecho hasta el momento, dar un set de entradas a la ANN y además dar un set de las salida esperadas de parte de la red, de modo que a cada muestra se corrigen los errores entre la salida obtenida y la salida deseada de nuestra red ( seria puro caso no encontrar errores al inicio ).
En cambio, el aprendizaje no supervisado no se da un set de salidas esperadas, se deja que la red aprenda a responder organizadamente a través de las entradas que recibe y que se organice por si misma. De este modo, datos de ingreso similares ( o casi ) dan una determinada respuesta a la salida, consiguiendo una clasificación de las distintas entradas.

martes, 2 de noviembre de 2010

Perceptron multicapa ( multilayer perceptron: MLP )

Como dijimos anteriormente, el perceptron multicapa ( MLP de ahora en adelante ) ha sido una mejora en la arquitectura del perceptron simple. El MLP es capaz de resolver problemas que no son linealmente separables ( como la funcion logica XOR )
El MLP esta formado de multiples capas ( siempre mas de tres ) las cuales se dividen en:
  • Capa de entrada: es donde entra la informacion. En esta capa no se realiza ningun procesamiento.
  • Capa oculta: puede ser una o mas capas, y realizan parte del proceso para enviarlo a la salida.
  • Capa de salida: ultima capa del MLP, es donde se devuelve el resultado.

Cada una de estas capas puede estar formada por mas perceptrones, las cuales salidas estan conectadas unicamente con las capas seguientes, nunca entre la misma capa o una capa anterior. La funcion de transferencia de las salidas de los perceptrones deben ser derivables. Como estamos usando como funcion de transferencia la suncion sigmoide, tenemos una funcion derivable en todo el intervalo real, aunque no puede ser una funcion lineal.
El MLP tiene un algoritmo un poco mas complejo de entrenamiento que el del perceptron simple. Este algoritmo es denomidado BP ( del ingles back propagation, o retropropagacion ).
Como mejora del simple perceptron, el MLP puede emular cualquier funcion continua.
Uno de los problemas que pueda causar este tipo de redes neuronales es el hecho que no esta determinado el numero de capas o neuronas por capa en las capas ocultas. Esto solo se puede determinar mediante la experiencia, pero como regla general:
Si la red no logra aprender un determinado proceso se aumentan neuronas.
Si la red pierde capacidad de generalizacion, se quitan neuronas.
Otro problema en algunos casos seria el hecho que la cantidad de pesos sinapticos de actualizar por cada epoca se vuelve bastante elevado, haciendo que el tiempo de entrenamiento se incremente.