Reconocimiento de Patrones mediante redes neuronales

Share:
RECONOCIMIENTO DE PATRONES MEDIANTE REDES NEURONALES

Hola amigos en esta ocasión les comparto una aplicación que se realizo en un curso de Inteligencia Artificial que estuve llevando en la universidad espero les sea de utilidad como es de costumbre comenzare con algo de teoría para luego compartir con ustedes el código fuente de la aplicación.

REDES NEURONALES

Una red neuronal artificial es un procesador distribuido en paralelo de forma masiva que tiene una tendencia natural para almacenar conocimiento de forma experimental y lo hace disponible para su uso.

SIMILITUD CON EL CEREBRO HUMANO:

  • El conocimiento es adquirido por la red a través de un proceso de aprendizaje.
  • Los pesos sinápticos o fuerza con que están interconectadas las neuronas se utilizan para almacenar la información.

En esta publicación se describirá una aplicación típica de las redes neuronales multicapa, concretamente el reconocimiento de patrones.

PERCEPTRÓN MULTINIVEL
Dentro de las redes neuronales, las que más utilizadas son las redes con múltiples capas que funcionan hacia delante. Esta red esta compuesta por un conjunto de nodos de entrada que componen la capa de entrada, un conjunto de una o más capas ocultas de neuronas y una capa de neuronas de salida. La señal de entrada se propaga hacia adelante desde la capa de entrada por la oculta hasta la salida; este tipo de configuración se conoce como MLP o "MultiLayer Perceptrons".


El hecho de que este tipo de red se aplique para resolver con éxito multitud de problemas se debe a la utilización del algoritmo de aprendizaje que actualmente está más extendido, el algoritmo o regla back propagation, el cual es una generalización de la regla LMS "Least Mean Square", por lo tanto también se basa en la corrección del error.
Básicamente el proceso back propagation consiste en dos pasadas a través de las diferentes capas de la red, una pasada hacia adelante y una pasada hacia atrás. En la pasada hacia adelante, se aplica en la capa de entrada un patrón o vector de entrada, este propaga su efecto a través de las diferentes capas y como consecuencia produce un vector de salida. 
Durante este proceso, los pesos sinápticos de la red son fijos y no se modifican. Durante la pasada hacia atrás en cambio, los pesos si se modifican de acuerdo con la regla de corrección del error. La señal de salida real se compara con la señal deseada y como resultado se obtiene una señal de error, que se propaga en dirección contraria a través de la red modificando los pesos, de forma que, al volver a pasar el vector de entrada hacia adelante, la respuesta obtenida se asemeje más a la salida deseada. Concretando, se puede decir que un perceptrón multicapa tiene tres características:

  • El modelo de cada neurona (figura 2) incluye una función no lineal. En este caso, a diferencia del perceptrón donde es la función escalón, y debido a la necesidad de que sea una función continua y derivable, es la función sigmoide, donde uk es la suma total de la actividad interna en la neurona k (la señal de entrada) e yk la salida que se produce en la neurona.




  • La red contiene una o más capas ocultas de neuronas que no forman parte ni de la entrada ni de la salida. Estas neuronas ocultas capacitan a la red para aprender progresivamente cualquier correspondencia entre la entrada y la salida y almacenar internamente esta información.
  • La red posee un gran número de conexiones, estas vienen determinadas por los pesos de la red. Un cambio en la conexión entre las neuronas equivale a un cambio en los pesos.
La combinación de estas características, hace que la habilidad de esta red para aprender a partir del entrenamiento sea muy potente, por ejemplo es capaz de resolver el problema de la OR-exclusiva a diferencia del perceptrón.

De todas formas, este comportamiento hace que sea difícil conocer a priori la respuesta de la red. Esto se debe a dos motivos, el comportamiento no lineal de las neuronas, las cuales están muy interconectadas, (lo que hace difícil un análisis teórico de la red) y la existencia de neuronas ocultas, que impide poder "ver" como se produce el aprendizaje y determinar cuales son las características que mejorarían el aprendizaje.

El desarrollo del algoritmo back propagation proporciona un método eficiente para entrenar este tipo de redes. Aunque no es capaz de resolver todos los problemas, se ha demostrado como el mejor de todos. Su importancia está en su capacidad de autoadaptar los pesos de las neuronas intermedias para aprender la relación que existe entre el conjunto de vectores o patrones de entrada y su correspondiente salida, y poder aplicar esa relación después del entrenamiento a nuevos vectores de entrada imperfectos o con ruido. Esta capacidad se conoce como generalización. La red debe encontrar una representación interna que le permita generar las salidas deseadas durante la etapa de entrenamiento, y posteriormente durante el funcionamiento ser capaz de generar salidas para entradas que no le fueron mostradas durante el aprendizaje pero que se asemejan a alguna de las que si le fueron mostradas.

EJEMPLO DE APLICACIÓN:

Para simular el funcionamiento de un perceptrón multinivel entrenado mediante el algoritmo back propagation, se plantea un sencillo problema de reconocimiento de óptico de caracteres. Su descripción es la siguiente:

Dado un panel de entrada compuesto por una matriz de 7x5 puntos, se consideran 12 clases diferentes donde se pretenden clasificar las muestras que se introducen. Los patrones que definen correctamente a cada una de las clases son los números del 0 al 9, el punto y el guión (figura 3).

Cuando a la entrada se presente una muestra distinta de los patrones correctos, el sistema presentará a su salida la información decodificada de la clase a la que pertenece la muestra, o bien, de la clase a la cual se aproxima más. En base a este planteamiento, la red neuronal dispone de 35 entradas que se corresponden con los puntos de la matriz numerados en la figura 4. El valor de cada entrada puede ser 0 si el punto es blanco y 1 si el punto es negro. Por otro lado, dispone de 12 salidas, una por cada clase. Cuando se introduzca una muestra a la entrada únicamente se activará la salida de la clase a la que pertenezca, permaneciendo las 11 restantes desactivadas con valores próximos a cero. Se considera que una salida está activada cuando su valor es próximo a la unidad.




RESULTADOS DE LA SIMULACIÓN:
Se realizo la implementación de una red neuronal en Java.En él se ha programado un perceptrón multinivel con 35 entradas y 12 salidas. También dispone de dos capas ocultas a las cuales se les puede modificar el número de sus neuronas. La red neuronal se ha entrenado con el algoritmo back propagation fijando el valor del momento en 0.8 y el factor de aprendizaje en 0.2. En este proceso únicamente se han usado doce muestras diferentes, es decir, los doce patrones sin ningún punto erróneo.
En la tabla I se muestran los resultados obtenidos para una red neuronal de tamaño 35-30-20-12. Se aprecia que tras el proceso de entrenamiento, el sistema responde de forma casi ideal cuando se introduce un patrón sin error.


IMPLEMENTACIÓN:






package digitos;
import javax.swing.JOptionPane;
public class digitos {

        int filas_entrada = 7;
        int col_entrada = 5;
        int neuronas_entrada = 35;
        int neuronas_oculta = 4;
        int neuronas_salida = 6;
        int i, j, k;
        int respuesta;
        int[][] patron = new int[5][7];
        double[][] pesos_entrada_oculta = {{1.658270037469468, -0.49277400626557, 0.8458827274104553, -2.648551432075224},
            {1.1603936240938337, -2.518757565059801, -0.21162501186454472, 0.4483509644280242},
            {0.9770989216075385, -1.1100683771308992, 0.5996520501870459, -1.5726273589648947},
            {-0.013373815758508401, -1.8088573544737623, -0.1806466969385013, 1.5619996308946966},
            {1.5477043440927314, -0.7451285620786131, 0.9078974238442922, -2.35721899617673},
            {1.6375625959682456, 0.05352515438526517, -1.7744239541344213, 1.4633986290892553},
            {-0.4895683338278625, 1.8177553658981087, 1.2455793786819767, -2.190482442936407},
            {-1.6471092496923165, 3.229636202454947, 1.2981497902378096, -0.7057775268591435},
            {-1.5667407635246655, -1.3245937353788448, 2.136912211349784, 0.006483361683210399},
            {-0.30620712895539964, -2.082257488430547, -0.7831144540926332, 2.860170068975273},
            {1.90730880729867, 1.786324022652642, -2.7987064218352016, -0.01985271542781151},
            {0.6073378720265543, 2.964084801890168, -0.8036519556281736, -0.11124911355434831},
            {0.8920664710707924, 1.2889968423497409, 1.4524992877441234, -4.5753301334234395},
            {0.5438102680069633, 2.732096021393861, -2.46484031199823, 1.077136757466367},
            {-0.5920084064677441, -2.0176453417628553, -0.8929972447944864, 2.9295974905024473},
            {-1.2273348838814682, 0.9665674119959388, -1.5098278165865484, 2.3855936692870223},
            {0.00303354357445883, 0.001581271588014359, 0.5078086841379089, -0.15023910421206893},
            {-0.2793511488473059, 1.4245803844405784, -0.8720662059686077, -0.5734228021484368},
            {-2.0275946046978293, -3.0777889662395226, 2.599080818031238, 1.6382349764441964},
            {1.7261757824595334, 1.8271668605813292, -2.6230163017984798, -0.023102087227872905},
            {-1.0400284786362686, 0.7483028076885504, -1.4201964658386028, 2.5893497462079242},
            {-1.2173094553360448, 1.0413190887119863, -1.3232448940438146, 2.7280471684208245},
            {-2.0889500107780266, 1.2113367713729557, 1.834844976337663, 0.48588965399759093},
            {-1.3959767352554984, 1.340974141434604, 0.4669554523335953, 0.8396877795787216},
            {0.5504882733683742, -0.007280194521717799, -1.049601349327548, 0.10628579988651637},
            {1.443454707114963, -1.1329167860893807, -1.202733639186253, -1.1206540048585907},
            {-0.4331284905557263, -1.5624137840495447, 1.116280151906849, 1.4607759610209936},
            {-0.5819930384824622, 1.758192614385909, 0.9171022839298032, -2.0753538337866986},
            {-1.3256304624056356, 1.044596834400223, 0.26717962626473013, 1.1753997160814336},
            {1.5797847092614183, -1.103413366841749, -1.1869484693704706, -1.0426817633297494},
            {-0.42533166857338317, -1.5201849827392802, 0.8863374072683927, 1.5286999085413167},
            {0.7681134972990639, -0.9328664559674184, 0.3210235342096992, -1.6081085875846808},
            {0.8656526958020259, -1.075079526248985, 0.4316305641408157, 1.4876790164633573},
            {-0.3418033974126609, 0.26137924890846875, 0.44588921383473606, -0.44772778571106026},
            {-0.5446034869269726, -1.7972802169693622, 1.143196716800601, 1.244775128422288}};
        
        
        double[][] pesos_oculta_salida = {{0.43621096542085136, -4.4770098664620495, -3.4380683245083805, 1.8296159164887345, -8.118120689656921, 5.695458556119513},
            {-1.027258581059679, 5.023126898792579, -7.757507526435068, -7.156764734520939, 4.478145059142636, 2.0603488963286387},
            {-8.390374693334456, 2.4451631927893267, 1.1247117391293466, 3.3697153535415416, -1.6716192668623555, -5.293714775954221},
            {5.151637910542471, -7.364970554525968, 4.923974784168798, -6.575339204075441, 4.552711228559867, -6.736958999045322}};
        
        
        
        double[] bias_entrada = {-0.4332161363101981,
            -0.5121521114762152,
            -0.39471528129652694,
            -0.5445351790184725,
            -0.4226637563836109,
            -0.5350195879964442,
            -0.3350043955733998,
            -0.38791367789336956,
            -0.3785593217087376,
            -0.5461130438610313,
            -0.554558738450257,
            -0.44288964426354815,
            -0.4380540832801621,
            -0.5350394221895475,
            -0.5580057611292775,
            -0.5560034483432901,
            -0.12912939908250873,
            -0.4139805211691567,
            -0.48481548633114296,
            -0.5388170156483836,
            -0.5565657646610173,
            -0.5633684138684646,
            -0.26352247776223936,
            -0.17951484914217863,
            -0.3253386781429675,
            -0.5422856630504476,
            -0.3859925425287016,
            -0.2926752007933522,
            -0.33661294128974667,
            -0.5351966380727077,
            -0.43172146451991633,
            -0.3614435550912756,
            -0.3009252579538338,
            0.13116124654486072,
            -0.42061848358615506,};
        double[] bias_oculta = {-0.5396208362695601,
            0.2293253598179893,
            0.9023280877608804,
            -0.5367884581404073};
        
        double[] bias_salida = {-1.3662965402953284,
            -2.7832950402557444,
            -1.5508290258166995,
            -0.47188562328444716,
            -4.298755314842922,
            -2.4180200713742552,};
        
        int[] entrada = new int[neuronas_entrada];
        double[] sumatoria_entrada = new double[neuronas_entrada];
        double[] sigmoidal_entrada = new double[neuronas_entrada];
        
        double[] oculta = new double[neuronas_oculta];
        double[] sumatoria_oculta = new double[neuronas_oculta];
        double[] sigmoidal_oculta = new double[neuronas_oculta];
        
        double[] salida = new double[neuronas_salida];
        double[] sumatoria_salida = new double[neuronas_salida];
        double[] sigmoidal_salida = new double[neuronas_salida];
        public digitos(int patrones[][])
        {
            this.patron=patrones;
        }
        public void reconocimiento()
        {
            //procesamiento de la capa de entrada
            //linealizar el patron de entrada
            for (i = 0; i  <  filas_entrada; i++) {
                for (j = 0; j  <  col_entrada; j++) {

                    entrada[i * col_entrada + j] = patron[i][j];
                }
            }

            //1.2 sumar la entrada con el bias y calcular sigmidal
            for (i = 0; i  <  neuronas_entrada; i++) {
                sumatoria_entrada[i] = entrada[i] + bias_entrada[i];
                sigmoidal_entrada[i] = 1 / (1 + Math.exp(-1 * sumatoria_entrada[i]));
            }
            //2. procesamiento de la capa oculta
            // 2.1 sumatoria de productos de entrada por peso
            for (j = 0; j  <  neuronas_oculta; j++) {
                oculta[j] = 0;
                for (i = 0; i  <  neuronas_entrada; i++) {
                    oculta[j] += sigmoidal_entrada[i] * pesos_entrada_oculta[i][j];
                }
            }
            //2.2 sumatoria mas bias y calculo de sigmoidal
            for (i = 0; i  <  neuronas_oculta; i++) {
                sumatoria_oculta[i] = oculta[i] + bias_oculta[i];
                sigmoidal_oculta[i] = 1 / (1 + Math.exp(-1 * sumatoria_oculta[i]));
            }

            //3. procesamiento de la capa salida
            //3.1 suamtoria de productos de salida x peso
            for (j = 0; j  <  neuronas_salida; j++) {
                salida[j] = 0;
                for (i = 0; i  <  neuronas_oculta; i++) {
                    salida[j] += sigmoidal_oculta[i] * pesos_oculta_salida[i][j];
                }
            }
            //3.2 sumatoria mas bias y calculo de sigmoidal
            for (i = 0; i  <  neuronas_salida; i++) {
                sumatoria_salida[i] = salida[i] + bias_salida[i];
                sigmoidal_salida[i] = 1 / (1 + Math.exp(-1 * sumatoria_salida[i]));
                System.out.println("Sigmoidal [" + i + "]- " + sigmoidal_salida[i]);
            }
            // 4.construyendo la interface de salida
            double mayor = -0.999;
            int neurona_activada = -1;
            for (i = 0; i  <  neuronas_salida; i++) {
                if (sigmoidal_salida[i]  >  mayor) {

                    mayor = sigmoidal_salida[i];
                    neurona_activada = i;
                }
            }
            if (mayor  >  0.80 ) { // heuristica para saber si el patron es coherente
                switch (neurona_activada) {
                    case 0:
                        respuesta=0;
                        System.out.println("RESPUESTA:"+respuesta);
                        break;
                    case 1:
                        respuesta=1;
                        System.out.println("RESPUESTA:"+respuesta);
                        break;
                    case 2:
                        respuesta=2;
                        System.out.println("RESPUESTA:"+respuesta);
                        break;
                    case 3:
                        respuesta=3;
                        System.out.println("RESPUESTA:"+respuesta);
                        break;
                    case 4:
                        respuesta=4;
                        System.out.println("RESPUESTA:"+respuesta);
                        break;
                    case 5:
                        respuesta=5;
                        System.out.println("RESPUESTA:"+respuesta);
                        break;

                }
            } else
            { 
                respuesta=-1;
                System.out.println("RESPUESTA:"+respuesta);
            }
        }
        public int getReconocimiento()
        {
            return respuesta;
        }

}


RESULTADOS OBTENIDOS EN LA IMPLEMENTACIÓN



2 comentarios:

  1. Hello, me podrias pasar el resto del codigo...me haria muy bien. te pagaria si quieres

    ResponderEliminar