Jesús Manuel Mager Hois

Introducción

El perceptrón es un algoritmo bio inspirado desarrollado por Frank Rosenblatt y es capás de clasificar elementos que sean linealmente separables, generando un hiperplano que separe estos en n  dimensiones. Esto quiere decir, que si dibujamos datos que previamente separamos en clases, digamos una clase C1 y Cdonde C1 son buenos clientes y C2 son malos clientes, el algoritmo únicamente podrá clasificarlos si estos pueden ser separados por un plano. Para ver más sobre el concepto de separabilidad lineal recomiendo leer este artículo: Clasificación Lineal contra No lineal con Python. ¿Por qué un plano? Si cada cliente tuviera tres características, digamos calificación del buró de crédito, edad y compras pasadas en nuestra tienda, entonces los clientes tendrían tres dimensiones. Se pueden agregar n dimensiones, y el si se puede dibujar un hiperplano que atraviese estas n dimensiones, entonces el perceptrón será capáz de clasificar los datos.

La idea básica del perceptrón es es un vector de entrada xT = [x1, x2, ... xn], una unidad sumatoria, la función de evaluación y la salida de la misma, como se muestra en la siguiente figura. 

(Tomado de wikipedia, Alejandro Cartas )

 

En el trabajo se presentará un breve ejemplo de cómo realizar esta clasificación y cómo varían los resultados con algunas modificaciones. 

 

Desarrollo

Dadas dos clases de patrones de tres atributos cada uno, y donde cada clase contiene exactamente cuatro patrones, con los siguientes valores:

\[  C_1=\quad \begin{bmatrix} 0 & 0 & 0 \\ 1 & 0 & 1 \\ 1 & 0 & 0 \\ 1 & 1 & 0 \end{bmatrix}\]
\[ C_2=\quad \begin{bmatrix} 0 & 0 & 1 \\ 0 & 1 & 1 \\ 0 & 1 & 0 \\ 1 & 1 & 1 \end{bmatrix}  \]

Se va a utilizar un perceptrón para clasificar nuevos vectores. La regla de clasificación a usar será: 

 

\[ x^T\omega + \theta < 0, \wedge x\in C_1 \\ x^T\omega + \theta \geq 0, \wedge x\in C_2 \]

 

En dado caso de que no se cumpla las reglas de clasificación se generará una penalización sobre $\omega$ y en caso de corresponder a la regla no se realizará acción alguna. Las penalizaciones serán:

 

\[ x_n^T\omega>0 \wedge x_n\in C_1 \rightarrow \omega_{n+1}=\omega_n - rx_n\\ x_n^T\omega<0 \wedge x_n\in C_2 \rightarrow \omega_{n+1}=\omega_n + rx_n \]

Para tener una mejor comprensión del espacio donde se encuentran los patrones de entrenamiento se muestra a continuación su gráfica en el espacio R3:

Ahora se va a inicializar el vector omegai = 0  y el tamaño de paso r=1, que nos genera una convergencia en cuatro pasos. A continuación se presenta los puntos cortados en dos partes por el plano generado a con el perceptrón.

Para verificar que el perceptrón clasifique de manera correcta un nuevo vector se presenta xp = [1, 0.5, 0]t. La suma de los productos de los elementos de este vector y los pesos generados [-1, 1, 1] El punto xp pertenece a la clase 2, dado que

 

\[ x^T\omega + \theta \geq 0, \wedge x\in C_2 \\ .5 \geq 0, \wedge x\in C_2 \]

i el valor de $r$ cambia la manera de acercase al punto de convergencia va a cambiar. Se va a probar para $r=\{1, 0.5, 0,2, 0.1\}$. En la siguiente gráfica se muestra que entre más chico sea el valor de $r$ más ciclos va a requerir para llevar a la convergencia. Pero a partir de 0.5 no se suscede mejora alguna en los ciclos necesarios, por lo que 3 ciclos es el mejor resultado. 

 

Conclusiones

El perceptrón es un algoritmo simple que es útil en ciertas circunstancias, donde los datos son linealmente separables. Este no va a garantizar el resultado óptimo, pero su uno factible, y su convergencia va a estar dado por r que permitirá moverse en el espacio al plano. El valor ideal para este factor de convergencia está en .5 a 1, donde requiere menos ciclos. 

 

 

import numpy as np

# Vectores con los cuales se va a entrenar
d = np.matrix([[0,0,0],
              [1,0,1],
              [1,0,0],
              [1,1,0],
              [0,0,1],
              [0,1,1],
              [0,1,0],
              [1,1,1]])
#Matriz transpuesta
nd = np.transpose(d)

x3 = nd[0].tolist()
y3 = nd[1].tolist()
z3 = nd[2].tolist()

x3 = x3[0]
y3 = y3[0]
z3 = z3[0]

print(nd[0][0])
print(nd[1][0])
print(nd[2][0])


#Agregamos en el cuarto elemento del vector un 1
data = []
data.append(np.array([0,0,0,1]))
data.append(np.array([1,0,1,1]))
data.append(np.array([1,0,0,1]))
data.append(np.array([1,1,0,1]))
data.append(np.array([0,0,1,1]))
data.append(np.array([0,1,1,1]))
data.append(np.array([0,1,0,1]))
data.append(np.array([1,1,1,1]))


ciclosx= []
ciclosy= []
# Probamos con diferentes factores de convergencia
rlista = [1, 0.5, 0.2, 0.1]
for r in rlista:
    wn = np.array([1,1,1,r])
    newvec = 0
    clase = 0
    itr = 0
    # Ciclo principal del perceptron
    while True:
        itr = itr + 1
        errors = 0
        j = 0
        print("-"*75)
        for x in data:
            clasereal = 0
            xnwn = 0
            
            # Se prueba si genera la clase correcta
            for i in range(len(x)):
                xnwn= xnwn + x[i] * wn[i]
            if j < 4:
                clasereal = 1
            else:
                clasereal = 2

            if xnwn < 0: 
                clase = 1
            else:
                clase = 2
         
            pen = "0"
            # Penalizaciones
            if clase == 2 and clase != clasereal:
                newvec = wn - r*x
                errors = errors + 1
                pen = "-x"
            if clase == 1 and clase != clasereal:
                newvec = wn + r*x
                errors = errors + 1
                pen = "+x"

            # Se imprime en pantalla
            print(str(x), "\t|", str(wn), "\t|", str(xnwn), "\t|", str(clase), "\t|", str(clasereal), "\t|", pen)

            wn = newvec
            
            j = j + 1
        # Si todos los vectores tienen la clase correcta se 
        # termina el ciclo
        if errors == 0:
            break


    # Se calcula el numero de iteraciones
    print("Número de iteraciones:", str(itr)) 
    ciclosx.append(r)
    ciclosy.append(itr)

Share This