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.
Código:
Código Red Neuronal Artificial - Python
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:
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.
Revisado.
ResponderEliminar