Calendar Icon - Dark X Webflow Template
September 2023
Clock Icon - Dark X Webflow Template
6
min lectura

Creando una Red Neuronal Multicapa desde Cero en Python

¡Bienvenido al apasionante mundo de las redes neuronales! Si eres nuevo en este terreno, estás en el lugar adecuado. Este contenido está diseñado especialmente para aquellos que están comenzando y desean comprender los conceptos básicos de las redes neuronales. A lo largo de estas líneas, te proporcionaremos definiciones simplificadas que te permitirán construir una base sólida en este fascinante campo.

Desmitificando las Redes Neuronales:

Si alguna vez has sentido que las redes neuronales son un enigma inaccesible, estás a punto de cambiar de opinión. Imagina que las redes neuronales son un intento de replicar el funcionamiento del cerebro humano para resolver problemas complejos. En lugar de neuronas biológicas, utilizamos unidades de procesamiento llamadas "neuronas artificiales" para lograr este propósito.

Neuronas Artificiales - Los Componentes Fundamentales:

Pensemos en una neurona artificial como el componente básico de una red neuronal. Imagina que es como un ladrillo en la construcción. Esta neurona toma entradas (datos numéricos) y les asigna ciertos "pesos", que indican su importancia. Luego, estas entradas ponderadas se combinan y se les aplica una "función de activación", que determina si la neurona debe activarse o no.

Capas y Conexiones - El Corazón de las Redes:

Aquí está el meollo de las redes neuronales. En lugar de tener una única neurona, tienes capas enteras de ellas. Las conexiones entre estas neuronas se relacionan con los "pesos" mencionados anteriormente. Una capa inicial recibe datos en bruto, como píxeles de una imagen. Luego, estas señales se transmiten a través de capas intermedias, cada una procesando la información de manera más abstracta. Finalmente, llegamos a la capa de salida, que proporciona la respuesta final de la red.

Aprendizaje a Través de Ejemplos:

¿Cómo mejora una red neuronal? Aprendiendo de ejemplos. Al proporcionarle una gran cantidad de ejemplos con sus respuestas conocidas, ajustamos los "pesos" y las conexiones para que la red haga predicciones más precisas. Este proceso de ajuste se conoce como "entrenamiento", es un proceso similar a cómo aprendemos de nuestros propios errores.

Invitación a Explorar:

Esta introducción te brindará una base sólida para comenzar tu viaje en el mundo de las redes neuronales. Observa la ilustración a continuación para visualizar mejor los conceptos que hemos discutido.

Manos a la Obra

En el emocionante mundo del aprendizaje automático, las redes neuronales multicapa son una de las herramientas más poderosas para resolver problemas complejos. En esta entrada de blog, te guiaré a través de los pasos para crear una red neuronal multicapa desde cero utilizando Python. Aprenderemos cómo diseñar la arquitectura de la red, implementar la propagación hacia adelante y hacia atrás, y entrenar la red utilizando datos reales. ¡Prepárate para sumergirte en el fascinante campo de las redes neuronales!

¿Que procesos se llevan a cabo en una red neuronal?

Sin ser demasiado técnicos, una red neuronal simple funciona de la siguiente manera.

Normalmente, antes de iniciar con el entreno de la red, se debe tener un conjunto de datos de entrada, y un conjunto de datos de salida, y su relación de estos conjuntos de daros debe ser, que para ciertas entradas, lo esperado es obtener ciertas salidas.

Ahora bien, las neuronas de la capa de entrada reciben los parámetros numericos del conjunto de datos de entrada, posteriormente, comienza el proceso de propagación hacia adelante.

La propagación hacia adelante consiste en que las salida de cada neurona de la capa de neuronas actual (en este caso, la de entrada), se conecta directamente a la entrada de todas y cada una de las neuronas de la capa siguiente, con el fin de que esta siguiente capa, tenga datos con los que trabajar y cuando termine cada neurona de esta capa el procesado de datos, hara lo mismo, es decir, sus salidas serán las entradas de todas las neuronas de la próxima capa.

Cuando se llega a la capa de salida (que es la ultima), se procede a comparar el resultado de la red con el esperado. Cuando hay una diferencia entre estas, se procede a hacer un ajuste en los pesos de las entradas de cada neurona, con la intención de que a la próxima vez que se administre el mismo conjunto de datos, se acerque cada vez más a lo deseado, y la diferencia entre lo que sale de la red y lo esperado, sea mínima o nula.

Ahora sí, podemos empezar a programar.

Paso 1: Entorno de trabajo:

Antes de comenzar, asegúrate de tener Python instalado en tu sistema. Recomiendo usar un entorno virtual para mantener limpio tu entorno de desarrollo. 

Puedes crear uno con el siguiente comando:


bash

python -m venv venv


Paso 2: Activa tu entorno virtual:

En Windows:


venv\Scripts\activate


En macOS y Linux:


source venv/bin/activate

Asegúrate de tener las bibliotecas necesarias instaladas, como NumPy para cálculos numéricos y matplotlib para visualización. Puedes instalarlas con:


pip install numpy matplotlib

Paso 3: Diseñando la Arquitectura:

Comencemos diseñando la arquitectura de nuestra red neuronal. Para este ejemplo, crearemos una red con una capa de entrada, una capa oculta y una capa de salida. Define los hiperparámetros como el número de neuronas en cada capa y la tasa de aprendizaje.

Nota: La cantidad de neuronas por capa puede variar. No hay una metodología infalible para calcular con certeza las neuronas justas y necesarias para cada problema. En muchos casos, nos apoyamos de arquitecturas ya existentes y estudiadas. Puede haber “métodos” para calcular el número total de neuronas en las capas ocultas, pero por simplicidad, comenzaremos una red neuronal con una neurona en su capa de entrada, una en su capa oculta y otra en su capa de salida. La siguiente imagen es solamente ilustrativa de una estructura general de una red.

Nota 2: La tasa de aprendizaje, es básicamente en qué proporción vamos a modificar los pesos en cada ajuste.
Si elegimos una taza alta, los pesos se modificarán de manera muy brusca, y quizá tarde mucho en ser entrenada la red, o de plano, no aprenderá.

Si elegimos una tasa baja de aprendizaje, será más precisa, pues modificará de a poco los pesos, pero puede ser más tardado.
 

Una sencilla Red Neuronal en Python con Keras y Tensorflow | Aprende  Machine Learning






import numpy as np


class NeuralNetwork:

   def __init__(self, input_size, hidden_size, output_size, learning_rate):

       self.input_size = input_size

       self.hidden_size = hidden_size

       self.output_size = output_size

       self.learning_rate = learning_rate

       

       self.weights_input_hidden = np.random.randn(self.input_size, self.hidden_size)

       self.bias_hidden = np.zeros((1, self.hidden_size))

       self.weights_hidden_output = np.random.randn(self.hidden_size, self.output_size)

       self.bias_output = np.zeros((1, self.output_size))


Algoritmos de la red neuronal
1- Propagación hacia Adelante:

La propagación hacia adelante implica calcular las activaciones en cada capa de la red neuronal. Utilizamos funciones de activación, como la sigmoide, para introducir no linealidad.


def sigmoid(self, x):

   return 1 / (1 + np.exp(-x))


def forward(self, X):

   self.hidden_activation = np.dot(X, self.weights_input_hidden) + self.bias_hidden

   self.hidden_output = self.sigmoid(self.hidden_activation)

   self.output_activation = np.dot(self.hidden_output, self.weights_hidden_output) + self.bias_output

   self.predicted_output = self.sigmoid(self.output_activation)

   return self.predicted_output


2-Retropropagación:

La retropropagación nos permite ajustar los pesos y sesgos de la red para reducir el error. Calculamos gradientes y actualizamos los parámetros utilizando el descenso de gradiente.


def backward(self, X, y):

   error = y - self.predicted_output

   d_output = error * self.predicted_output * (1 - self.predicted_output)

   d_hidden = np.dot(d_output, self.weights_hidden_output.T) * self.hidden_output * (1 - self.hidden_output)

   

   self.weights_hidden_output += np.dot(self.hidden_output.T, d_output) * self.learning_rate

   self.bias_output += np.sum(d_output, axis=0, keepdims=True) * self.learning_rate

   self.weights_input_hidden += np.dot(X.T, d_hidden) * self.learning_rate

   self.bias_hidden += np.sum(d_hidden, axis=0, keepdims=True) * self.learning_rate


3- Entrenamiento:

Ahora, es el momento de entrenar nuestra red neuronal. Iteraremos a través de los datos de entrenamiento, realizando la propagación hacia adelante y la retropropagación en cada iteración.


def train(self, X, y, epochs):

   for epoch in range(epochs):

       predicted_output = self.forward(X)

       self.backward(X, y)

       loss = np.mean(np.square(y - predicted_output))

       if epoch % 100 == 0:

           print(f"Epoch {epoch}, Loss: {loss:.4f}")


Ejecucion :

Finalmente, creamos una instancia de nuestra red neuronal y la entrenamos utilizando datos de ejemplo.

input_size = 2

hidden_size = 4

output_size = 1

learning_rate = 0.1


X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])

y = np.array([[0], [1], [1], [0]])


nn = NeuralNetwork(input_size, hidden_size, output_size, learning_rate)

nn.train(X, y, epochs=1000)


# Prueba

test_input = np.array([[0, 0]])

predicted_output = nn.forward(test_input)

print(f"Predicción para [{test_input[0][0]}, {test_input[0][1]}]: {predicted_output[0][0]:.4f}")


En consola, podemos ver los resultados por época de nuestra red neuronal.

Salida:

Epoch 0, Loss: 0.2823

Epoch 100, Loss: 0.2461

Epoch 200, Loss: 0.1980

Epoch 300, Loss: 0.1383

Epoch 400, Loss: 0.0906

Epoch 500, Loss: 0.0616

Epoch 600, Loss: 0.0447

Epoch 700, Loss: 0.0346

Epoch 800, Loss: 0.0277

Epoch 900, Loss: 0.0228

Predicción para [0, 0]: 0.0307


Conclusión

En resumen, hemos abordado los elementos fundamentales de las redes neuronales de una manera accesible. A medida que profundices en este emocionante campo, encontrarás que estos conceptos te servirán de base para explorar conceptos más avanzados. ¡Prepárate para descubrir las maravillas del aprendizaje automático a medida que te aventures en el apasionante mundo de las redes neuronales!

Sigue atento, en próximas entradas, ahondaremos más en los fundamentos matemáticos y teóricos!