Google+ Seguidores

domingo, 5 de agosto de 2018

Introducción a las Redes Neuronales - Parte #2: Nuestra primera red neuronal

Introducción:

Ya hemos terminado la primera parte de este proyecto. Vimos cuales eran las características y conceptos básicos de una red neuronal. Ahora es momento de emplear todo lo aprendido para crear nuestras propias redes neuronales.

En esta segunda parte, nos dedicaremos a la creación de las distintas redes neuronales. En este primer articulo practico, construiremos un Perceptrón el cual ya hemos visto y analizado anteriormente. 

Por supuesto, si no has visto la primera parte, te recomiendo que lo hagas:


Creación de nuestra propia red neuronal:

Existen miles de herramientas que nos ofrecen modelos y redes neuronales pre entrenadas. Incluso ya hemos visto algunas de esas librerías en este blog.

Pero no hay nada como crear nuestras propias herramientas. Esto nos permite conocer con exactitud con funciona el programa y sus procedimientos. Podemos acceder a ellas y alterarlas de la manera que creamos correcta.

Por ello en esta segunda parte de este proyecto, realizaremos redes neuronales desde cero, es decir que las programaremos nosotros mismos sin necesidad de una librería externa. 

En este caso realizaremos un Perceptrón , ya que es uno de los más sencillo y necesarios de conocer. Ya hemos hablado de el perceptrón y de sus características.

Sabemos que la forma de entrenar a un Perceptrón es la siguiente:

w = w + N(d(k)-y) x(k)

Donde:

W = El peso actual asociado a la sinapsis que une la neurona i de la capa de entrada y la neurona j de la capa de salida.
N = Es una constante entre 0 y 1 que indica cuanto aprende la red.
d(k) = El estado de la neurona de la capa de salida j.
y = El valor deseado para esa neurona.
x(k) = El estado de la neurona de la capa de entrada i.

Teniendo esto en cuenta, podemos entrenar a nuestra red neuronal.

Nuestro Primer Perceptrón:

Pateamiento del problema:
Nuestro objetivo es entrenar a un Perceptrón que pueda clasificar un conjuntos de datos sin clasificar.

Lo que haremos, sera crear un clase llamada Perceptron, de esta manera podremos crear todos los perceptrones que necesitemos y emplearlos para diferentes objetivos.

Tendrá dos entradas y una salida (p1, p2). 

Cada neurona de la red es una unidad de procesamiento de información; es decir, recibe información a través de las conexiones con las neuronas de la capa anterior, procesa la información, y emite el resultado a través de sus conexiones con las neuronas de la capa siguiente, siempre y cuando dicho resultado supere un valor "umbral".


En una red neuronal ya entrenada, las conexiones entre neuronas tienen un determinado peso ("peso sináptico").

El procesamiento de la información llevado a cabo por cada neurona Y, consiste en una función (F) que opera con los valores recibidos desde las neuronas de la capa anterior (Xi, generalmente 0 o 1), y que tiene en cuenta el peso sináptico de la conexión por la que se recibieron dichos valores (Wi). Así, una neurona dará mas importancia a la información que le llegue por una conexión de peso mayor que no a aquella que le llegue por una conexión de menor peso sináptico.

Para simplificar el sistema de entrenamiento, el valor umbral (U) pasa a expresarse como un peso sináptico más (-W0), pero asociado a una neurona siempre activa (X0). Esta neurona siempre activa, se denomina "bias", y se sitúa en la capa anterior a la neurona Y.


Neurona bias y su peso sináptico asociado (-W0), en substitución del valor umbral (U).


Teniendo todo esto en cuenta, podemos empezar a implementarlo todo en el lenguaje de programación Python.

Perceptron.py

Empezaremos declarando nuestra clase con sus respectivos atributos:

 # Importamos la librerias necesarias
import random

# Declaramos la clase
class Perceptron:
    def __iniit__(self, sample, exit, learn_rate=0.01, epoch_number=1000, bias=-1):
        # Atributos de la clase
        self.sample = sample # Datos de entrenamiento
        self.exit = exit # Salida esperada para cada dato
        self.learn_rate = learn_rate # Que tanto aprendera la red
        self.epoch_number = epoch_number
        self.bias = bias # Bias de la red
        self.number_sample = len(sample) # Numero de ejemplos
        self.col_sample = len(sample[0]) # Columnas de los datos
        self.weight = [] # Lista de pesos

Estos serán los atributos que utilizara la red. Cada parámetro determinara la configuración de la red así como su eficiencia. Es recomendable ir cambiando los valored de los parametros para conseguir los resultados más eficientes. 



def trannig(self): # Metodo de entrenamiento
    
        for sample in self.sample: # Se recorren los datos de entrenamiento
            sample.insert(0, self.bias) # Se inserta el bias en la primera pocisión
        
        for i in range(self.col_sample):
            self.weight.append(random.random()) # Asignamos pesos aleatorios
            
        self.weight.insert(0, self.bias) # Insertamos el bias en los pesos
        
        epoch_count = 0
        
        while True:
            erro = False
            for i in range(self.number_sample):
                u = 0
                for j in range(self.col_sample + 1):
                    # Función de activación
u = u + self.weight[j] * self.sample[i][j] y = self.sign(u) # Comprobar el valor del umbral if y != self.exit[i]: for j in range(self.col_sample+1): # Función de entrenamiento # w = w + N(d(k)-y) x(k) self.weight[j] = self.weight[j] + self.learn_rate * (self.ex it[i]-y) * self.sample[i][j] erro = True epoch_count = epoch_count+1 # Se aumenta el numero de epoch if erro == False: print(('\nEpoch: \n', epoch_count)) # Mostramos el valor de epoch print('-'*20) print("\n") break

Aquí hay otro tema a tener en cuenta. Epoch: Cada presentación completa al perceptrón multicapa del set de entrenamiento se denomina epoch. Así, el proceso de aprendizaje se repite epoch tras epoch hasta que los pesos sinápticos se estabilizan y la performance de la red converge a un valor aceptable.


def sort(self, sample):
        """
        Se inserta el bias, ya que como discutimos antes,
        sera una neurona que siempre estara activada.
        """
        sample.insert(0, self.bias)
        u = 0
        for i in range(self.col_sample + 1):
            # Función de activación
            u = u + self.weight[i] * sample[i]
        
        # Comprobamos el valor de la función de activación
        y = self.sign(u) 
    
        # Si y es igual a -1, la clasificación corresponde a P1
        if  y == -1:
            print(('Ejemplo: ', sample))
            print('Clasificación: P1')
        # Si y es igual a 1, la clasificación corresponde a P1
        elif y == 1:
            print(('Ejemplo: ', sample))
            print('Clasificación: P2')
            
def sign(self, u):
    return 1 if u >= 0 else -1

El método sort utilizara la función de activación. Luego se comprobara la salida y se le asignara una clasificación a cada uno de los datos. Si y = -1 se asignara la clasificación P1 de lo contrario, se le asignara la clasificación P2.

# Datos de entrenamiento
samples = [
    [0, 2],
    [-2, 2],
    [0, -2],
    [2, 0],
    [-2,2],
    [-2,-2],
    [2,-2],
    [2,2],
]

# Clasificación de los datos de entrenamiento (salidas que esperamos para cada conjunto de dato)
"""
[0,2] = 1
[-2,-2] = 1
[0,-2] = 0
...
"""
exit = [1, 1, 0, 0, 1, 1, 0, 1]

#Intancia de nuestra neurona
network = Perceptron(sample=samples, exit = exit, learn_rate=0.01, epoch_number=1000, bias=-1)
 
# Entrenamos a la neurona
network.trannig()

"""
Le pedimos al usuario datos para entrenar.
Luego mostramos el resultados
"""
while True:
    sample = []
    for i in range(2):
        sample.insert(i, float(input('Valor: ')))
    network.sort(sample) # Clasificacipon de nuevos datos
    print("\n")

Ahora es momentos de utilizar la clase y empezar a entrenar a la neurona.

Todo el código completo nos quedaría así:

'''
 Perceptron
 w = w + N * (d(k) - y) * x(k)

 p1 = -1
 p2 = 1
'''

import random

class Perceptron:
    def __init__(self, sample, exit, learn_rate=0.01, epoch_number=1000, bias=-1):
        self.sample = sample
        self.exit = exit
        self.learn_rate = learn_rate
        self.epoch_number = epoch_number
        self.bias = bias
        self.number_sample = len(sample)
        self.col_sample = len(sample[0])
        self.weight = []

    def trannig(self):
        for sample in self.sample:
            sample.insert(0, self.bias)

        for i in range(self.col_sample):
           self.weight.append(random.random())

        self.weight.insert(0, self.bias)

        epoch_count = 0

        while True:
            erro = False
            for i in range(self.number_sample):
                u = 0
                for j in range(self.col_sample + 1):
                    u = u + self.weight[j] * self.sample[i][j]
                y = self.sign(u)
                if y != self.exit[i]:

                    for j in range(self.col_sample + 1):

                        self.weight[j] = self.weight[j] + self.learn_rate * (self.exit[i] - y) * self.sample[i][j]
                    erro = True
            epoch_count = epoch_count + 1
            if erro == False:
                break

    def sort(self, sample):
        sample.insert(0, self.bias)
        u = 0
        for i in range(self.col_sample + 1):
            u = u + self.weight[i] * sample[i]

        y = self.sign(u)

        if  y == -1:
            print('Clasificación: P1 (-1)')
        else:
            print('Clasificación: P2 (1)')

    def sign(self, u):
        return 1 if u >= 0 else -1
        
# Datos de entrenamiento
samples = [
    [0, 2],
    [-2, 2],
    [0, -2],
    [2, 0],
    [-2,2],
    [-2,-2],
    [2,-2],
    [2,2],
]

# Clasificación de los datos de entrenamiento (salidas que esperamos para cada conjunto de dato)
"""
[0,2] = 1
[-2,-2] = 1
[0,-2] = 0
...
"""
exit = [1, 1, -1, -1, 1, 1, -1, 1]

network = Perceptron(sample=samples, exit = exit, learn_rate=0.01, epoch_number=1000, bias=-1)

network.trannig()

while True:
    sample = []
    for i in range(2):
        sample.insert(i, float(input('Valor: ')))
    network.sort(sample)
    print("\n")

Luego de realizar too esto, ya estamos aptos de ejecutar el algoritmos.

Valor: 1
Valor: -2
Clasificación: P1 (-1)


Valor: 1
Valor: 2
Clasificación: P2 (1)

El programa continuara pidiendo datos para clasificar hasta detener el programa.

Siempre lo digo, y lo volveré a decir. "Entre más datos, mejor", entrena a la red con todos los datos posibles. En la mayoría de los casos, los datos de entrenamiento son los que más influyen en la eficacia de la red neuronal.

Eso ha sido todo por hoy. ¿Alguna duda? No dudes en dejar tu comentario.

Mi nombre es Luis, y fue un placer compartir mis conocimientos con todos ustedes :D.

No hay comentarios :
Write comentarios

Tu comentario es importante y nos motiva a seguir escribiendo...

Powered by Blogger .