Redes perceptrón y multicapa#
Bienvenidos al notebook de redes perceptrón y multicapa.
En este notebook aprenderemos los conceptos fundamentales detrás de las redes neuronales, comenzando desde el modelo más básico conocido como el perceptrón, hasta extendernos a las redes neuronales multicapa (MLP). Las redes neuronales son uno de los pilares en el aprendizaje profundo y tienen aplicaciones en diversas áreas como la clasificación de datos, predicción de comportamientos, procesamiento de imágenes, y más. A través de este material, explicaremos desde los conceptos básicos y las fórmulas matemáticas, hasta la implementación de ejemplos prácticos en Python.
A lo largo del notebook:
Conocerás qué es un perceptrón y cómo funciona.
Aprenderás a entrenar un modelo de perceptrón para resolver problemas de clasificación binaria.
Entenderás el concepto de redes neuronales multicapa (MLP) y cómo se utilizan para resolver problemas más complejos.
Practicarás con ejemplos prácticos y ejercicios diseñados para que puedas aplicar los conocimientos adquiridos.
Comencemos.
#1. Conceptos básicos y el perceptrón: ###1. ¿Qué es un perceptrón? Un perceptrón es el modelo más simple de una neurona artificial. Imita el comportamiento de una neurona biológica y toma decisiones basadas en las entradas que recibe. En términos simples, un perceptrón toma varias entradas, realiza algunos cálculos y da una salida, que puede ser 0 o 1.
###2. ¿Qué es un peso (weight)? Un peso es un valor numérico que indica la importancia de cada entrada. Si una entrada tiene un peso alto, significa que esa entrada tiene un gran impacto en la salida del perceptrón. Si el peso es bajo, la entrada tiene menos impacto.
Por ejemplo, si estamos evaluando a un estudiante basado en su asistencia y su calificación, podríamos darle más importancia (mayor peso) a la calificación si creemos que es más relevante para decidir si aprueba o no.
###3. ¿Qué es el sesgo (bias)? El sesgo es otro valor numérico que se añade para ajustar la salida del perceptrón. Permite que el perceptrón decida correctamente incluso si todas las entradas son 0. En otras palabras, el sesgo permite desplazar la función de activación y hacerla más flexible.
###4. ¿Qué es una suma ponderada? Una suma ponderada es una operación en la que cada entrada se multiplica por su peso y luego se suman todos esos valores, junto con el sesgo:
Donde:
\(𝑤_1\), \(𝑤_2\) son los pesos de las entradas,
\(𝑥_1\), \(𝑥_2\) son las entradas,
𝑏 es el sesgo.
Usamos esta suma ponderada para calcular qué tan fuerte debe ser la salida.
###5. ¿Qué es una función de activación? La función de activación toma la suma ponderada y decide la salida final del perceptrón. En este ejemplo, usaremos la función escalón.
###¿Qué es la función escalón? La función escalón es una función muy simple que devuelve 1 si la entrada es mayor o igual a 0, y devuelve 0 si la entrada es menor que 0:
Usamos esta función para decidir si el estudiante aprueba (1) o no (0), basándonos en la suma ponderada de sus calificaciones y asistencia.
###6. ¿Qué es la lógica AND? La lógica AND es una operación en la que el resultado es verdadero (1) solo si ambas condiciones son verdaderas. Por ejemplo, si estamos evaluando la asistencia (A) y la calificación (C):
A = 1 (buena asistencia) y C = 1 (buena calificación) ➔ Resultado: 1 (aprueba) A = 0 o C = 0 ➔ Resultado: 0 (no aprueba) Ahora que conocemos estos conceptos, vamos a aplicar todo en un código simple.
import numpy as np
# Función de activación Escalón
def step_function(x):
"""
La función escalón devuelve 1 si x es mayor o igual a 0,
de lo contrario devuelve 0.
"""
return 1 if x >= 0 else 0
# Clase Perceptrón Simple
class Perceptron:
def __init__(self, weights, bias):
"""
Inicializa el perceptrón con pesos y sesgo.
- weights: Lista de pesos para las entradas.
- bias: Valor del sesgo.
"""
self.weights = weights # Asignamos los pesos a cada entrada
self.bias = bias # Asignamos el sesgo para ajustar la salida
def predict(self, inputs):
"""
Predice el resultado usando los pesos, el sesgo y la función de activación.
- inputs: Lista de entradas [x1, x2].
"""
# Calcula la suma ponderada de las entradas más el sesgo
total = np.dot(self.weights, inputs) + self.bias
# Aplica la función escalón para determinar la salida
return step_function(total)
# Definimos los pesos y el sesgo
# Ambos pesos iguales para dar la misma importancia a las entradas, sesgo negativo para ajustar la salida
weights = np.array([1, 1]) # Pesos de las entradas (asistencia y calificación)
bias = -1.5 # Sesgo para desplazar la función
# Crear el perceptrón
perceptron = Perceptron(weights, bias)
# Pruebas con los datos de entrada (asistencia y calificación)
test_inputs = [
(0, 0), # No asistió lo suficiente y no aprobó el examen
(0, 1), # No asistió lo suficiente pero aprobó el examen
(1, 0), # Asistió lo suficiente pero no aprobó el examen
(1, 1) # Asistió lo suficiente y aprobó el examen
]
# Salidas esperadas para la lógica AND: [0, 0, 0, 1]
for inputs in test_inputs:
result = perceptron.predict(np.array(inputs))
print(f"Entradas: {inputs}, Resultado: {result}")
Entradas: (0, 0), Resultado: 0
Entradas: (0, 1), Resultado: 0
Entradas: (1, 0), Resultado: 0
Entradas: (1, 1), Resultado: 1
##Clases, instancias y métodos en python Para entender cómo funciona el perceptrón en el código, es importante aclarar algunos conceptos fundamentales de la programación orientada a objetos (OOP), un paradigma que organiza el código en torno a objetos que representan entidades del mundo real o conceptos abstractos.
###¿Qué es una clase? Una clase es como un plano o plantilla para crear objetos. Define las propiedades (variables) y los comportamientos (funciones o métodos) que los objetos creados a partir de esa clase tendrán.
Por ejemplo, si queremos modelar un «Perceptrón», la clase Perceptron sería el plano que define cómo funciona un perceptrón y qué datos necesita manejar.
Analogía: Piensa en una clase como el plano de un coche. El plano indica que los coches deben tener ruedas, motor y volante, y también explica cómo se encienden o se conducen. Pero el plano no es el coche en sí.
###¿Qué es una instancia? Una instancia es un objeto creado a partir de una clase. Si la clase es el plano, entonces una instancia es el coche real que construimos a partir de ese plano.
En el contexto del perceptrón, cuando escribimos:
mi_perceptron = Perceptron()
Estamos creando una instancia del perceptrón. Esa instancia mi_perceptron es un objeto que tiene sus propios datos y puede utilizar los métodos definidos en la clase Perceptron.
Analogía: Si la clase es el plano de un coche, entonces la instancia es el coche específico que has construido basándote en ese plano.
###¿Qué son los métodos? Los métodos son funciones que se definen dentro de una clase y que describen el comportamiento de las instancias de esa clase. Los métodos pueden manipular datos que pertenecen a la instancia, y para hacer esto, utilizan self, que representa la propia instancia.
Por ejemplo:
class Perceptron:
def entrenar(self, datos, etiquetas):
# Aquí `entrenar` es un método que usa `self` para operar en la instancia
# `self` permite acceder a los datos que pertenecen a esta instancia particular
En el código del perceptrón, los métodos definen cómo el perceptrón se entrena y realiza predicciones. Cada vez que se llama a un método en un objeto, como mi_perceptron.entrenar(datos, etiquetas), ese método actúa sobre la instancia específica de mi_perceptron.
Analogía: Volviendo a la idea del coche, un método sería la función para «arrancar» el coche. Todos los coches (instancias) tienen la capacidad de arrancar, pero cada coche específico puede arrancar independientemente del otro.
###¿Qué es self? En Python, self es una referencia a la instancia actual de la clase. Cuando definimos métodos dentro de una clase, el primer parámetro siempre es self, y se utiliza para acceder a las variables y métodos de la propia instancia. Es como si dijéramos: «Usa el valor o método que pertenece a este objeto en particular.»
Por ejemplo, si tenemos:
class Perceptron:
def __init__(self):
self.peso = 0.5
##¿Cómo funciona esto como perceptrón? La principal tarea del perceptron es clasificar datos binarios basándose en una combinación lineal de entradas.
###Entradas y pesos (weights y inputs):
Las entradas (x1, x2, etc.) son valores que se pasan al perceptrón. Los pesos (w1, w2, etc.) son valores que indican la importancia de cada entrada. Por ejemplo, si una entrada es más relevante que otra, su peso será mayor.
###Suma ponderada (weighted sum):
El perceptrón toma las entradas y multiplica cada una por su peso correspondiente, luego suma esos valores y agrega un sesgo (bias). Esto se llama «suma ponderada»:
###Función de activación:
Después de calcular la suma ponderada, el perceptrón pasa el resultado a través de una función de activación, que decide si la salida será 1 (verdadero) o 0 (falso). En el ejemplo anterior, la función de activación era una función escalón, que devuelve 1 si la suma es mayor o igual a 0, y 0 si es menor. Clasificación:
Basándose en la salida de la función de activación, el perceptrón decide si clasificar las entradas como una categoría u otra.
#2. Redes neuronales multicapa (MLP) Ahora que hemos visto el perceptrón simple, es momento de introducir una estructura más compleja y potente: las Redes Neuronales Multicapa o MLP (Multilayer Perceptrons). Estas redes son una extensión del perceptrón simple, donde en lugar de tener una sola capa de neuronas, tenemos múltiples capas que permiten aprender patrones más complejos.
##¿Qué es una red neuronal multicapa? Una Red Neuronal Multicapa (MLP) consiste en:
Una capa de entrada: Recibe los datos de entrada. Una o más capas ocultas: Estas capas están «escondidas» entre la entrada y la salida. Cada capa oculta está formada por múltiples neuronas (perceptrones) que procesan la información y la pasan a la siguiente capa. Una capa de salida: Produce el resultado final, que puede ser una clasificación, una regresión, etc. Analogía: Imagina que tienes que decidir qué ropa ponerte en la mañana. Primero miras el clima (entrada), luego piensas en qué ropa es adecuada para ese clima (capa oculta), y finalmente decides qué ponerte (salida). La capa oculta procesa la información de entrada para ayudarte a tomar una decisión.
###Funcionamiento de las MLP El flujo de información en una MLP se da de la siguiente manera:
La capa de entrada recibe los datos. Cada dato pasa a través de la red, comenzando en esta capa.
La información fluye hacia adelante, desde la capa de entrada, a través de las capas ocultas, hasta llegar a la capa de salida. Este proceso se llama feedforward.
Cada neurona realiza una operación matemática (similar a la del perceptrón) que involucra multiplicar los valores de entrada por pesos, sumar un sesgo y aplicar una función de activación.
Aprendizaje: Los pesos y sesgos de la red se ajustan durante el proceso de entrenamiento para que la red pueda hacer mejores predicciones. Este ajuste se realiza mediante algoritmos de optimización que minimizan el error entre la salida de la red y los valores reales.
###Fórmula básica de una red neuronal multicapa En una MLP, cada neurona realiza una operación como la siguiente:
donde:
𝑦 es la salida de la neurona,
𝑓 es la función de activación,
𝑤𝑖 son los pesos asociados a cada entrada 𝑥𝑖,
𝑏 es el sesgo.
###La función sigmoide La función sigmoide es una función matemática que transforma cualquier valor real en un número entre 0 y 1. Se utiliza en redes neuronales porque puede interpretar los resultados como probabilidades. La fórmula de la función sigmoide es:
###¿Por qué usamos una red neuronal multicapa (MLP)? A diferencia del perceptrón simple que puede resolver problemas sencillos, como la lógica AND/OR, las redes multicapa pueden manejar situaciones más complejas gracias a las capas ocultas. Estas capas ayudan a descubrir patrones más profundos en los datos, permitiendo que la red sea capaz de resolver problemas más difíciles, como clasificar tipos de flores o predecir si un cliente comprará un producto.
###Tasa de aprendizaje La tasa de aprendizaje (learning rate) es un parámetro que determina el tamaño de los pasos que la red da al ajustar los pesos durante el proceso de entrenamiento. En cada iteración, la red ajusta los pesos para minimizar el error, y la tasa de aprendizaje define cuánto se ajustan los pesos en cada paso.
Ejemplo: Imagina que estás ajustando el volumen de una radio. Si haces ajustes grandes, podrías pasar de un volumen muy bajo a uno muy alto rápidamente. En cambio, si haces ajustes pequeños, puedes encontrar el volumen perfecto poco a poco. En este caso, la tasa de aprendizaje sería el tamaño de esos ajustes.
###Épocas Una época se refiere a un ciclo completo en el que el modelo de red neuronal ve todos los ejemplos del conjunto de datos una vez. Durante el entrenamiento, la red necesita pasar por varias épocas para ajustar sus pesos correctamente.
Ejemplo: Si tienes 100 imágenes para entrenar a una red a reconocer perros, una época sería cuando la red ha visto esas 100 imágenes una vez. Si repites este proceso 10 veces, habrás completado 10 épocas.
###Backpropagation Backpropagation (retropropagación) es el algoritmo que se utiliza para ajustar los pesos de la red neuronal durante el entrenamiento. Funciona calculando el error en la salida (la diferencia entre el resultado esperado y el resultado actual), y luego retropropaga ese error a través de la red para ajustar los pesos y reducir el error.
Cálculo del Error: El algoritmo mide la diferencia entre la salida esperada y la salida actual.
Derivadas Parciales: Utiliza derivadas parciales para calcular cómo afecta cada peso al error.
Ajuste de Pesos: Ajusta los pesos de la red para reducir el error la próxima vez que se procese un dato similar.
###Ajuste de pesos y sesgos Durante el entrenamiento, la red ajusta los pesos y sesgos para minimizar el error. Los pesos determinan la importancia que tiene cada entrada en la red, mientras que el sesgo actúa como un ajuste adicional que ayuda a desplazar la función de activación.
Pesos: Si un peso es alto, significa que la entrada asociada tiene un impacto significativo en la salida.
Sesgos: Ayudan a que la red pueda ajustar las funciones de activación para que el modelo aprenda patrones complejos.
###Entrenar la red Entrenar una red significa permitirle ajustar sus pesos y sesgos para que pueda aprender a producir las salidas correctas a partir de las entradas dadas. Durante el entrenamiento, el modelo se presenta con datos, ajusta los pesos y sesgos utilizando backpropagation, y repite este proceso durante muchas épocas.
Es decir, el entrenamiento es el proceso de aprendizaje en el que la red se ajusta a los datos que se le dan para poder predecir o clasificar nuevos datos con precisión en el futuro.
##Ejemplo: Clasificación de tipos de flores Imaginemos que tenemos un pequeño jardín con dos tipos de flores: rosas y girasoles. Queremos que nuestra red neuronal pueda identificar qué flor es cuál basándose en características simples como el tamaño de los pétalos y el color.
import numpy as np
# Definimos la función sigmoide y su derivada
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def sigmoid_derivada(x):
return x * (1 - x)
# Creamos una clase para la red neuronal multicapa
class RedNeuronal:
def __init__(self, entrada_neuronas, ocultas_neuronas, salida_neuronas):
# Inicializamos los pesos aleatoriamente
self.pesos_entrada_oculta = np.random.rand(entrada_neuronas, ocultas_neuronas)
self.pesos_oculta_salida = np.random.rand(ocultas_neuronas, salida_neuronas)
# Inicializamos los sesgos aleatoriamente
self.sesgo_oculta = np.random.rand(ocultas_neuronas)
self.sesgo_salida = np.random.rand(salida_neuronas)
def feedforward(self, x):
# Paso 1: Multiplicamos entradas por los pesos y sumamos el sesgo, aplicando la función sigmoide
self.capa_oculta = sigmoid(np.dot(x, self.pesos_entrada_oculta) + self.sesgo_oculta)
# Paso 2: Repetimos para la capa de salida
self.salida = sigmoid(np.dot(self.capa_oculta, self.pesos_oculta_salida) + self.sesgo_salida)
return self.salida
def entrenar(self, x, y, tasa_aprendizaje=0.1, epocas=10000):
for _ in range(epocas):
# Alimentamos la red
salida_predicha = self.feedforward(x)
# Calculamos el error
error = y - salida_predicha
# Backpropagation para ajustar los pesos
ajuste_salida = error * sigmoid_derivada(salida_predicha)
error_oculta = ajuste_salida.dot(self.pesos_oculta_salida.T)
ajuste_oculta = error_oculta * sigmoid_derivada(self.capa_oculta)
# Ajustamos los pesos y sesgos
self.pesos_oculta_salida += self.capa_oculta.T.dot(ajuste_salida) * tasa_aprendizaje
self.pesos_entrada_oculta += x.T.dot(ajuste_oculta) * tasa_aprendizaje
self.sesgo_salida += np.sum(ajuste_salida, axis=0) * tasa_aprendizaje
self.sesgo_oculta += np.sum(ajuste_oculta, axis=0) * tasa_aprendizaje
# Datos de entrada (por ejemplo, tamaño del pétalo, color en valores normalizados)
x = np.array([[0.3, 0.7], [0.6, 0.1], [0.8, 0.3], [0.2, 0.8]])
# Salidas esperadas (1 = rosa, 0 = girasol)
y = np.array([[1], [0], [0], [1]])
# Creación de la red neuronal con 2 neuronas de entrada, 2 ocultas, 1 de salida
mlp = RedNeuronal(entrada_neuronas=2, ocultas_neuronas=2, salida_neuronas=1)
# Entrenamos la red
mlp.entrenar(x, y)
# Predicciones para las mismas entradas de entrenamiento
for flor in x:
prediccion = mlp.feedforward(flor)
print(f"Entrada: {flor} - Predicción: {prediccion}")
Entrada: [0.3 0.7] - Predicción: [0.96976808]
Entrada: [0.6 0.1] - Predicción: [0.02280046]
Entrada: [0.8 0.3] - Predicción: [0.02699387]
Entrada: [0.2 0.8] - Predicción: [0.98691131]
##Interpretación de los resultados En el código que se ha ejecutado, hemos entrenado una red neuronal multicapa para clasificar diferentes tipos de flores según ciertas características de entrada. Vamos a explicar qué significan los resultados obtenidos para que veamos cómo la red está funcionando:
###Datos de entrada Los datos de entrada representan características de las flores que queremos clasificar. En nuestro ejemplo, cada entrada tiene dos valores:
Ejemplos:
[0.3, 0.7]
: Supongamos que representa características como el tamaño del pétalo y el color.
[0.6, 0.1]
, [0.8, 0.3]
, [0.2, 0.8]
: Son otras combinaciones de características que describen distintas flores.
Salidas esperadas: Las salidas esperadas definen las etiquetas que queremos que la red aprenda a predecir:
1 (rosa) y 0 (girasol): Hemos asignado 1 para identificar una rosa y 0 para un girasol.
Predicciones de la red: Después de entrenar la red, se realiza la predicción para las mismas entradas que se usaron para entrenar. Los resultados obtenidos son valores que indican la «certeza» de la red de que la entrada corresponde a una rosa (1) o un girasol (0):
Interpretación de resultados:
Entrada
[0.3, 0.7]
: Predicción:0.9697
Esto significa que la red está muy segura de que esta combinación de características corresponde a una rosa, ya que el valor está cerca de 1.
Entrada
[0.6, 0.1]
: Predicción:0.0228
Aquí, la red está segura de que esta flor no es una rosa, sino un girasol, porque la predicción es cercana a 0.
Entrada
[0.8, 0.3]
: Predicción:0.0260
Al igual que en el caso anterior, la red indica que esta flor es un girasol.
Entrada
[0.2, 0.8]
: Predicción:0.9869
Esta entrada también es clasificada como una rosa con un alto grado de certeza.
#3. Ejemplos aplicados. ##Perceptrón: Detección de celdas solares dañadas Contexto: Imagina que trabajas en una empresa de energía renovable que utiliza paneles solares para generar electricidad. Uno de los problemas que enfrentan es detectar celdas solares dañadas rápidamente para que puedan ser reemplazadas sin afectar la producción de energía. Para hacer esto, puedes usar un perceptrón que ayude a clasificar si una celda solar está funcionando correctamente o si está dañada, basándose en ciertas mediciones de corriente y voltaje.
Explicación del problema:
Entrada (x1, x2):
x1: Corriente generada por la celda solar.
x2: Voltaje de la celda solar.
Salida (y):
1: La celda está funcionando correctamente.
0: La celda está dañada.
Para simplificar, podemos asumir que si la corriente y el voltaje son bajos, la celda probablemente esté dañada, y si ambos son altos, la celda está funcionando correctamente. El perceptrón ayudará a clasificar estas entradas en dos categorías: funcionando o dañada.
import numpy as np
class Perceptron:
def __init__(self, tasa_aprendizaje=0.1, epocas=10):
self.tasa_aprendizaje = tasa_aprendizaje
self.epocas = epocas
self.pesos = None
self.sesgo = None
def funcion_activacion(self, suma_ponderada):
# Función Escalón
return 1 if suma_ponderada >= 0 else 0
def predecir(self, entrada):
suma_ponderada = np.dot(entrada, self.pesos) + self.sesgo
return self.funcion_activacion(suma_ponderada)
def entrenar(self, entradas, salidas_esperadas):
num_entradas = entradas.shape[1]
self.pesos = np.zeros(num_entradas)
self.sesgo = 0
for _ in range(self.epocas):
for entrada, salida in zip(entradas, salidas_esperadas):
prediccion = self.predecir(entrada)
error = salida - prediccion
# Ajuste de pesos y sesgo
self.pesos += self.tasa_aprendizaje * error * entrada
self.sesgo += self.tasa_aprendizaje * error
# Ejemplos de datos de celdas solares
entradas = np.array([
[0.5, 0.7], # Celda funcionando bien
[0.2, 0.1], # Celda dañada
[0.6, 0.9], # Celda funcionando bien
[0.1, 0.3] # Celda dañada
])
# Salidas esperadas: 1 para funcionando, 0 para dañada
salidas_esperadas = np.array([1, 0, 1, 0])
# Creación y entrenamiento del perceptrón
perceptron = Perceptron()
perceptron.entrenar(entradas, salidas_esperadas)
# Prueba
nueva_entrada = np.array([0.4, 0.6]) # Celda potencialmente buena
prediccion = perceptron.predecir(nueva_entrada)
print(f"La predicción para la celda con entrada {nueva_entrada} es: {'Funciona correctamente' if prediccion == 1 else 'Está dañada'}")
La predicción para la celda con entrada [0.4 0.6] es: Está dañada
##MLP: Predicción de tipo de clima Contexto: En meteorología, es importante predecir el clima a partir de datos como la temperatura, la humedad y la velocidad del viento. Vamos a construir una Red Neuronal Multicapa (MLP) que pueda predecir si el clima será «soleado», «nublado» o «lluvioso» basándose en estas entradas.
Explicación del problema:
Entradas (x1, x2, x3):
x1: Temperatura.
x2: Humedad.
x3: Velocidad del viento.
Salidas (y):
0: Soleado.
1: Nublado.
2: Lluvioso.
En este ejemplo, la red neuronal aprenderá a reconocer patrones en los datos de entrada para hacer predicciones sobre el clima.
import numpy as np
class RedNeuronal:
def __init__(self, entrada_neuronas, ocultas_neuronas, salida_neuronas, tasa_aprendizaje=0.1):
self.tasa_aprendizaje = tasa_aprendizaje
# Inicialización de pesos
self.pesos_entrada_oculta = np.random.rand(entrada_neuronas, ocultas_neuronas)
self.pesos_oculta_salida = np.random.rand(ocultas_neuronas, salida_neuronas)
def sigmoid(self, x):
return 1 / (1 + np.exp(-x))
def derivada_sigmoid(self, x):
return x * (1 - x)
def feedforward(self, x):
self.capa_oculta = self.sigmoid(np.dot(x, self.pesos_entrada_oculta))
salida = self.sigmoid(np.dot(self.capa_oculta, self.pesos_oculta_salida))
return salida
def backprop(self, x, y, salida):
error = y - salida
ajuste_salida = error * self.derivada_sigmoid(salida)
# Ajuste de pesos
error_oculta = ajuste_salida.dot(self.pesos_oculta_salida.T)
ajuste_oculta = error_oculta * self.derivada_sigmoid(self.capa_oculta)
self.pesos_oculta_salida += self.capa_oculta.T.dot(ajuste_salida) * self.tasa_aprendizaje
self.pesos_entrada_oculta += x.T.dot(ajuste_oculta) * self.tasa_aprendizaje
def entrenar(self, x, y, epocas=10000):
for _ in range(epocas):
salida = self.feedforward(x)
self.backprop(x, y, salida)
# Datos de entrenamiento (temperatura, humedad, velocidad del viento)
x = np.array([
[30, 40, 10], # Soleado
[20, 70, 20], # Nublado
[18, 90, 15], # Lluvioso
[25, 50, 5], # Soleado
])
# Salidas esperadas en formato one-hot: 0 = Soleado, 1 = Nublado, 2 = Lluvioso
y = np.array([
[1, 0, 0], # Soleado
[0, 1, 0], # Nublado
[0, 0, 1], # Lluvioso
[1, 0, 0], # Soleado
])
# Creación y entrenamiento de la red neuronal
mlp = RedNeuronal(entrada_neuronas=3, ocultas_neuronas=4, salida_neuronas=3)
mlp.entrenar(x, y)
# Prueba de predicción con nuevos datos
nuevo_clima = np.array([22, 65, 10]) # Clima potencialmente nublado
prediccion = mlp.feedforward(nuevo_clima)
print(f"Predicción del clima: {prediccion}")
Predicción del clima: [0.49999973 0.24999977 0.24999986]
Actividad: Interpreta los resultados de la predicción de la MLP.
#Ejercicios de práctica ##Ejercicio 1: Clasificación binaria con perceptrón - detección de correo spam Contexto: Imagina que estás desarrollando un sistema básico de detección de correos electrónicos para clasificar si un mensaje es «spam» o «no spam».
Tienes algunas características simples que puedes usar:
Entrada (x1, x2):
x1: Número de enlaces en el correo.
x2: Cantidad de palabras en mayúsculas.
Salida (y):
1: Spam.
0: No Spam.
Objetivo: Construir el perceptrón y entrenarlo con algunos ejemplos básicos, luego probar con nuevos correos para ver si el sistema puede detectar correctamente si son spam o no.
###Pseudocódigo
Inicializar los pesos y el sesgo.
Definir la función de activación (función escalón).
Entrenar el perceptrón con ejemplos de correos (número de enlaces y palabras en mayúsculas):
Ajustar los pesos y el sesgo según los errores.
Probar con nuevos datos para ver si el perceptrón clasifica correctamente.
Ejemplo de Entradas:
Entrada 1: [5 enlaces, 8 mayúsculas] -> Spam (1)
Entrada 2: [1 enlace, 2 mayúsculas] -> No Spam (0)
_____ Perceptron:
def __init__(self, tasa_aprendizaje=0.1, e___s=10):
self.tasa_aprendizaje = tasa_aprendizaje
____.epocas = epocas
self._____ = None # Pesos iniciales (se deben inicializar en el entrenamiento)
self.sesgo = None # Sesgo inicial (se debe inicializar en el entrenamiento)
___ funcion_activacion(self, suma_ponderada):
# Aquí estamos usando la función escalón
return 1 if suma_ponderada >= 0 else 0
def predecir(self, entrada):
# Aquí calculamos la suma ponderada para una entrada específica
suma_ponderada = sum([w * x for w, x in zip(self.pesos, entrada)]) + self.sesgo
return self.funcion_activacion(suma_ponderada)
def entrenar(self, e______s, salidas_esperadas):
# Inicializar pesos y sesgo en 0
self.pesos = [0 for _ in range(len(entradas[0]))]
self.sesgo = 0
for _ in range(self.epocas):
for entrada, salida_esperada in zip(entradas, salidas_esperadas):
# Calcular la predicción y el error
prediccion = self.predecir(entrada)
e____ = salida_esperada - prediccion
# Ajustar pesos y sesgo
___ i in range(len(self.pesos)):
self.pesos[i] += self.tasa_aprendizaje * error * entrada[i]
self.sesgo += self.tasa_aprendizaje * error
# EJEMPLOS DE ENTRENAMIENTO Y PRUEBA
________ = [[5, 8], [1, 2], [7, 3], [0, 0]] # Datos de ejemplo para clasificar como spam o no
salidas = [1, 0, 1, 0] # Salidas esperadas
# Crear y entrenar el perceptrón
perceptron = Perceptron(tasa_aprendizaje=0._, epocas=__)
p________n.entrenar(entradas, salidas)
# Probar con nuevas entradas
nuevas_entradas = [[_, _], [_, _]]
for entrada __ nuevas_entradas:
prediccion = perceptron.predecir(entrada)
print(f"Entrada: {entrada} - Predicción: {prediccion}")
Entrada: [4, 6] - Predicción: 1
Entrada: [2, 0] - Predicción: 1
##Ejercicio 2: Red neuronal mlticapa (MLP) - Predicción de enfermedades en plantas Contexto: En la agricultura, es importante detectar signos tempranos de enfermedades en las plantas para actuar a tiempo. Supongamos que se han recogido tres características clave de las hojas de las plantas:
x1: Índice de color verde (más bajo indica hojas amarillas).
x2: Tamaño de manchas en las hojas.
x3: Número de hojas afectadas.
Vamos a construir una red neuronal multicapa que pueda predecir si la planta tiene «ninguna enfermedad», «enfermedad leve» o «enfermedad grave» basada en estos valores.
Salidas (y):
0: Ninguna enfermedad.
1: Enfermedad leve.
2: Enfermedad grave.
###Pseudocódigo
Inicializar los pesos de las capas (entrada-oculta y oculta-salida).
Definir funciones:
Función de activación (sigmoide).
Derivada de la función de activación.
Entrenamiento:
Hacer feedforward para calcular las predicciones.
Usar backpropagation para ajustar los pesos.
Probar con nuevos datos para verificar la predicción de la red.
Ejemplo de Entradas:
Entrada 1:
[70 (verde intenso), 1 (manchas pequeñas), 0 (ninguna hoja afectada)]
->Ninguna enfermedad (0)
Entrada 2:
[30 (amarillenta), 3 (manchas grandes), 10 (múltiples hojas afectadas)]
->Enfermedad grave (2)
class RedNeuronal:
def __init__(self, entrada_neuronas, ocultas_neuronas, salida_neuronas, tasa_aprendizaje=0.1):
# INICIALIZAR LOS PESOS
def sigmoid(self, x):
# DEFINIR FUNCIÓN SIGMOIDE
def derivada_sigmoid(self, x):
# DEFINIR DERIVADA SIGMOIDE
def feedforward(self, x):
# COMPLETAR FEEDFORWARD
def backprop(self, x, y, salida):
# COMPLETAR BACKPROPAGATION
def entrenar(self, x, y, epocas=10000):
# ENTRENAMIENTO: COMPLETAR
# EJEMPLOS DE ENTRENAMIENTO Y PRUEBA: COMPLETAR
#Conclusión En este notebook, hemos cubierto los fundamentos de las Redes Perceptrón y Multicapa. Comenzamos explicando los conceptos básicos detrás de un perceptrón y cómo este puede ser utilizado para problemas simples de clasificación. Luego, exploramos cómo las redes neuronales multicapa (MLP) pueden resolver problemas más complejos gracias a su capacidad para aprender representaciones más profundas y no lineales de los datos.
Hemos aprendido:
La importancia de los pesos, sesgos y funciones de activación en las redes neuronales.
Cómo ajustar los pesos y sesgos a través del entrenamiento para que el modelo mejore su rendimiento.
Los conceptos clave como la tasa de aprendizaje, épocas y el algoritmo de backpropagation que permiten a las redes aprender de los datos.
Implementaciones prácticas que nos muestran cómo las redes pueden ser aplicadas a situaciones reales, como clasificar flores según sus características.
Esperamos que este material haya proporcionado una base sólida para entender las redes neuronales. ¡Sigue practicando, experimenta con diferentes parámetros, y no dudes en explorar más allá para descubrir el poder del aprendizaje profundo!