jueves, 1 de noviembre de 2012

Practica


Practica 3

Programación de Sistemas Adaptativos



Introducción

Para la practica 3 se   programaron dos  sistemas adaptativos relacionados con técnicas de sistemas inteligentes.

En este caso se programará un Ejemplo de RNA y Solución de problemas mediante búsqueda.

¿Qué son las redes neuronales artificiales?

Las redes de neuronas artificiales (denominadas habitualmente como RNA o en inglés como: "ANN"1 ) son un paradigma de aprendizaje y procesamiento automático inspirado en la forma en que funciona el sistema nervioso de los animales. Se trata de un sistema de interconexión de neuronas en una red que colabora para producir un estímulo de salida. En inteligencia artificial es frecuente referirse a ellas como redes de neuronas o redes neuronales.

Una red neuronal se compone de unidades llamadas neuronas. Cada neurona recibe una serie de entradas a través de interconexiones y emite una salida. Esta salida viene dada por tres funciones:

1.         Una función de propagación (también conocida como función de excitación), que por lo general consiste en el sumatorio de cada entrada multiplicada por el peso de su interconexión (valor neto). Si el peso es positivo, la conexión se denomina excitatoria; si es negativo, se denomina inhibitoria.

2.         Una función de activación, que modifica a la anterior. Puede no existir, siendo en este caso la salida la misma función de propagación.

3.         Una función de transferencia, que se aplica al valor devuelto por la función de activación. Se utiliza para acotar la salida de la neurona y generalmente viene dada por la interpretación que queramos darle a dichas salidas. Algunas de las más utilizadas son la función sigmoidea (para obtener valores en el intervalo [0,1]) y la tangente hiperbólica (para obtener valores en el intervalo [-1,1]).

El tipo de RNA que se desea simular es un perceptrón

El perceptrón  fue el primer modelo de Red Neuronal Artificial supervisada. Es la más simple de las Redes neuronales.

Sirve únicamente para problemas linealmente separables y que sean de dos clases. Hablando vulgarmente, esto quiere decir que el perceptrón sólo lo podemos usar cuando el problema sea distinguir entre una de dos posibles clases y, que trazando una línea, plano o hiperplano en un plano o hiperplano, se puedan separar perfectamente estas dos clases.

Objetivo



En esta práctica lograremos simular las propiedades observadas en los sistemas neuronales biológicos a través de modelos matemáticos recreados mediante mecanismos artificiales

Se entrenará un Perceptrón Simple para que aprenda a realizar la operación OR binaria.

Utilizar la técnica de resolución de problemas mediante búsqueda, es resolver el problema de las ocho reinas de un ajedrez, y así muestre la solución mejor o más cercana a esta. 



Justificación

¿Por qué estos  temas seleccionados ?

Las redes neuronales tienen  un aprendizaje Adaptativo, y esto es muy interesante ya que se caracterizan por su capacidad de aprender a realizar tareas basadas en un entrenamiento o en una experiencia inicial.



En Solución de problemas mediante búsqueda se manejó  un ejemplo intresante, por ser de un juego tan complejo como el ajedrez. Querer acomodar 8 reinas en un solo tablero es algo interesante por sus tipo de movimientos, por esto mismo se escogió resolver este problema por esta técnica.

Desarrollo
El perceptron programado consiste en dos capas de neuronas, una de entrada y otra de salida, Las entradas son discretas, y la función de activación de las neuronas de la capa de salida es de tipo escalón.
El ejemplo contiene dos entradas, el perceptron puede discriminar entre dos clases linealmente separables.
La operación efectuada por el perceptron consiste en :



El el caso de Solución se problemas mediante búsqueda  el sistema adaptativo  se realizo en Java, en el cual se resuelve el problema de las 8 Reinas. El cual busca colocar el mayor numero de reinas en el tablero, para esto no solo son 8 reinas en este caso es para resolver el problema con N reinas en un tablero.
Cuando empieza a ejecutarse va colocando las reinas en el tablero de manera que no se cruce con alguna otra, si las que se quieren acomodar tiene solución se colocan, si no solo coloca el numero que mejor presente solución.

Se muestra en un tablero impreso de puros “0” y en cada posición de la reina se coloca un numero del 1 al N que se ingreso, sin repetirse y sobretodo sin cruzarse una con otra.
También menciona cuantas reinas se pudieron colocar, o si se pudieron colocar todas las ingresadas.


Código:
Código Red Neuronal Artificial - Python 


import random
import math

class RNA:
     
    def __init__(self,Lp, Lpn, Lsn, ta,Lr, Lrd, Fa):
        print "                      RED NEURONAL ARTIFICIAL FUNCION OR        "
        print
        print 
        self.Lista_pesos=Lp 
        self.tasa_aprendizaje=ta
        self.Lista_primer_numero=Lpn
        self.Lista_segundo_numero=Lsn
        self.Lista_resultados=Lr
        self.Lista_resultado_deseado=Lrd
        self.Funcion_activacion=Fa
        
    def asignacion(self): #metodo para asignar las pesos de forma aleatoria
       
        
        for i in range(0,3):
            Lista_pesos.append(random.randint(0, 1))
        
        print "Lista de pesos Iniciales: ", Lista_pesos # impresion de pesos iniciales asignados
    
    def calculo_salida(self,y, Lista_resultados, Funcion_activacion):
        # metodo que calcula la salida de la red neuronal y lo almacena en una lista
        for i in range(0,4):
            
            Lista_resultados.append((Lista_pesos[1]*Lista_primer_numero[i]+Lista_pesos[2]*Lista_segundo_numero[i])+y)
            Funcion_activacion.append(Lista_resultados[i])
        print"Salidas obtenidas: ", Lista_resultados
        for i in range(0,4): # recorrido de la lista obtenida  
            # calculo de la funcion, para el caso del OR 
            if(Lista_resultados[i]>=0):
                Funcion_activacion[i]=1
            else:
                Funcion_activacion[i]=0
        # salida que obtiene el perceptron
        print"Funcion activacion, Valores de U: ", Funcion_activacion
        # si la salida no es la esperada , aui se actualizan los pesos
        if(Funcion_activacion!=Lista_resultado_deseado):
            print "El resultado no es correcto. hay que actualizar pesos"
            print 
            
            red.actualizar_pesos(Funcion_activacion)
             
        else: # cuando se  llega a la salida esperada...
            print "Los pesos adecuados son:", Lista_pesos
            print "las salidas  ya son correctas :)"
        
        
    def calcular_resultado_deseado(self):
        for i in range(0,4): #obtenemos las salidas de la funcion or 
            Lista_resultado_deseado.append(Lista_primer_numero[i] or Lista_segundo_numero[i])
        print "SALIDAS CORRECTAS DE LA FUNCION ",Lista_resultado_deseado
        
    
    def funcion(self, Funcion_activacion):
        
        for i in range(0,4):
            Funcion_activacion.append(Lista_resultados[i])
        
    def actualizar_pesos(self, Funcion_activacion):
        
# se actualizan pesos,
        for i in range(0,4):
            if(Funcion_activacion[i]!=Lista_resultado_deseado[i]):
                Lista_pesos[0]=Lista_pesos[0]+0.1*(x0)*(Lista_resultado_deseado[i]-Funcion_activacion[i])
                Lista_pesos[1]=Lista_pesos[1]+0.1*Lista_primer_numero[i]*(Lista_resultado_deseado[i]-Funcion_activacion[i])
                Lista_pesos[2]=Lista_pesos[2]+0.1*Lista_segundo_numero[i]*(Lista_resultado_deseado[i]-Funcion_activacion[i])
        
        print "peso w0 modificado",Lista_pesos[0]
        print "peso w1 modificado",Lista_pesos[1]
        print "peso w2 modificaco",Lista_pesos[2]
        print 
        print
        y=x0*Lista_pesos[0]
        Lista_resultados=[]
        Funcion_activacion=[]
        red.calculo_salida(y, Lista_resultados, Funcion_activacion)
        # se vuelve a calcular la salida con pesos nuevos
       
Lista_nuevas_salidas=[]
Lista_pesos=[]
Lista_primer_numero=[0,0,1,1] #entradas establecidas 
Lista_segundo_numero=[0,1,0,1]
Lista_resultados=[]
Lista_resultado_deseado=[]
Funcion_activacion=[]

x0=-1 
# se crea el objeto red  
red=RNA(Lista_pesos, Lista_primer_numero, Lista_segundo_numero,0.3, Lista_resultados, Lista_resultado_deseado, Funcion_activacion)  
red.asignacion()
red.calcular_resultado_deseado()
y=x0*Lista_pesos[0]
red.calculo_salida(y, Lista_resultados,Funcion_activacion)
print "Lista de resultado deseado", Lista_resultado_deseado


Código solución de problemas mediante búsqueda.

import java.util.Scanner;
 import java.util.Random;

 public class NReinas{
 Scanner entrada = new Scanner(System.in);
 Random aleatorio = new Random();
 private int Tamano;
 private int FracasosRequeridos = 1000;
 private int dado1;
 private int dado2;
 private int contadorReinas = 0;


 public void Principal(){ 
     int accesibilidad;
     
     System.out.println("\nPrograma para resolver el problemas de las 8 Reinas...");
     System.out.print("\nIntroducir el numero de casillas del tablero :D\n");
     Tamano = entrada.nextInt();
     int fracasos = 0;
     int A[][] = new int[Tamano + 1][Tamano + 1];
    
     while ( Tamano > contadorReinas && fracasos < FracasosRequeridos){
         Genera_Casilla(); 
         accesibilidad =  Verifica_Posicion(A);
         if ( 0 == accesibilidad )
             fracasos++;
         else
             A[dado1][dado2] = ++contadorReinas;
     }
    
     if ( Tamano != contadorReinas)
         System.out.printf("\nSolo se colocaron %d reinas\n", contadorReinas);
     else
         System.out.printf("\nSE COLOCARON LAS %d REINAS!\n", Tamano);
    
     Imprime(A);

 }
 
 public void Genera_Casilla(){
     dado1 = aleatorio.nextInt(Tamano) + 1;
     dado2 = aleatorio.nextInt(Tamano) + 1;
 }
 
 public int Verifica_Posicion(int B[][] ){
         int estatus = 1;
     if ( 0 == B[dado1][dado2] ){
     for ( int i = 1; i <= Tamano; i++ )
     for ( int j = 1; j <= Tamano; j++ ){  
         if ( 0 != B[i][j] ){  
             if ((( dado1 == i) || (dado2 == j ))  || (Math.abs(dado1 - i) == Math.abs(dado2 - j )) ){
                 estatus = 0;
                 break;
             }
         }   
     }  
    
     }else
         estatus = 0;
     return estatus;
 }

 public void Imprime(int C[][]){ 
     for ( int k = 1; k <= Tamano; k++ ){
         for ( int j = 1; j <= Tamano; j++){
             System.out.printf("%5d", C[k][j]);
         } 
         System.out.println("\n");
     }
 }
 
 public static void main(String args[]){
 NReinas miObjeto = new NReinas();
 miObjeto.Principal(); 
 }        

}


Resultados:
a continuación se presentan  las corridas de los programas.

















Video:






Conclusiones:

La importancia en el uso de técnicas inteligentes es que nos ayudan a resolver   problemas de una manera rápida.
La importancia en el perceptron radica en que es entrenable, el algoritmo que se utilizo permite que el perceptron determine automáticamente los pesos sinápticos que logran clasificar el conjunto de patrones.

1 comentario: