lunes, 17 de mayo de 2010

Entrenando un Perceptrón para que resuelva operaciones lógicas

Como nos indica el título de este post, hoy voy a mostrar como entrenar un perceptrón para que resuelva operaciones lógicas básicas linealmente separables entre dos variables proposicionales. Como preámbulo, podemos decir por un lado que un perceptrón es una neurona artificial, la unidad de una red neuronal y por otro que una operación es linealmente separable si las clases (resultados distintos) pueden dividirse con una recta. En caso de que esto último no sea posible debe implementarse una solución a partir de redes de preceptrones.
La magia del perceptrón, su diferenciación y la forma en que resuelve las operaciones reside en su vector de pesos que no es ni mas ni menos que un vector numérico que multiplicado por el vector de entrada (datos de usuario) devuelve el resultado correspondiente.


Se puede plantear a grandes rasgos que el periodo de "creación" de un perceptrón consta de las siguientes etapas:
- Presentación de los patrones al perceptrón (se le muestra que tiene que devolver)
- Entrenamiento del perceptrón (se lo prepara para que devuelva lo que debería)
- Se devuelven los resultados con los pesos de su Vector de pesos.

Pasada ya la explicación de que es un perceptrón, a muuuuuuuuy alto nivel y no apta para estudio, vamos a lo que realmente creo que puede ser mi granito de arena. Este granito consta de una simple implementación en python de un perceptrón que resuelve operaciones lógicas linealmente separables. Digo aporte no por la complejidad de este algoritmo sino porque me costó, y en realidad no pude encontrar, en la red algo parecido.

Para correr el script se debe tener instalado:

Ahi va el código de perceptron.py:

# -*- encoding: utf-8 -*-
# Inteligencia Artificial - UNLu
# Juan Manuel Fernández - 89937

import numpy, Gnuplot, random
from functions import *

ITERATIONS = 50

X00 = raw_input("Patron para (0, 0): ")
X01 = raw_input("Patron para (0, 1): ")
X10 = raw_input("Patron para (1, 0): ")
X11 = raw_input("Patron para (1, 1): ")
VELOCIDAD = raw_input("Velocidad de Aprendizaje: ")
print "Vector de Pesos inicial"
VectorPesos = [0, 0, 0]
VectorPesos[0] = raw_input("Wio[0]: ")
VectorPesos[1] = raw_input("Wio[1]: ")
VectorPesos[2] = raw_input("Wio[2]: ")

if not(VELOCIDAD):
    VELOCIDAD = 1
else:
    VELOCIDAD = int(VELOCIDAD)

PesosDefinitivos = []
for Peso in VectorPesos:
    if not(Peso):
        Peso = round(random.uniform(-0.1 , 0.1), 2)
    else:
        Peso = round(float(Peso), 2)
    PesosDefinitivos.append(Peso)

print PesosDefinitivos

# Inicialización del vector pesos con -0.1 < wio < 0.1
Wio = numpy.array([PesosDefinitivos[0], PesosDefinitivos[1], PesosDefinitivos[2]])

patron = [  [numpy.array([0, 0, 1]), int(X00)],
            [numpy.array([0, 1, 1]), int(X01)],
            [numpy.array([1, 0, 1]), int(X10)],
            [numpy.array([1, 1, 1]), int(X11)]  ]

clase0, clase1 = dividirPuntosPorClase(patron)

encontro_solucion = False
for i in range(ITERATIONS):
    cambios = 0
    for pattern in patron:
        vector_input = pattern[0]
        valor_esperado = pattern[1]
        temp = numpy.dot(Wio, vector_input)
        if ((valor_esperado == 1) and (temp <= 0)):
            Wio += VELOCIDAD * vector_input
            cambios += 1
        elif ((valor_esperado == 0) and (temp >= 0)):
            Wio -= VELOCIDAD * vector_input
            cambios += 1
    if (cambios == 0):
        encontro_solucion = True
        break

if encontro_solucion:
    graficarRecta(Wio, clase0, clase1)
    print "La solucion se encuentra en la iteración " + str(i)
    print "El vector de pesos Wio es " + str(Wio)
else:
    print "El problema no es linealmente separable."
raw_input("-Perceptrón- ha terminado su ejecución...")

Y ahi el código de functions.py:

# -*- encoding: utf-8 -*-
import Gnuplot
from functions import *

def graficarRecta(Wio, clase0, clase1):
    # Despejamos y para formar la ecuación de la recta
    y = Wio[1]
    x = str(-((Wio[0])/y))
    b = str(-(Wio[2])/y)
    # Especificamos en texto plano la ecuación
    f = x + '*x + ' + b
    # Se inicializa el objeto de la gráfica
    g = Gnuplot.Gnuplot()
    g.title('Gráfica de la solución del Perceptron')
    g.xlabel('x')
    g.ylabel('y')
    g('set xrange [0:2]')
    g('set yrange [0:2]')
    g('set pointsize 2')
    g.plot(f, clase0, clase1)   
    raw_input("Presione cualquier tecla...")

# Divido las clases en clase0 y clase1
def dividirPuntosPorClase(patron):
    clase0 = []
    clase1 = []
    for pattern in patron:
        valor_punto = pattern[1]
        punto_recta = [pattern[0][0], pattern[0][1]]
        if (valor_punto == 0):
            clase0.append(punto_recta)
        if (valor_punto == 1):
            clase1.append(punto_recta)
    return clase0, clase1

Hasta aca todo, la seguimos en la próxima!

3 comentarios:

  1. al fin un codigo de como crear un perceptron ;) gracias maestro todos hablan de teoriaque es muy importante pero sin la practica no se puede aprender, gracias por el aporte!

    ResponderEliminar