CONSTRUYE TU PRIMERA RED NEURONAL CON KERAS EN 2025
Introducción a la creación de redes neuronales con Keras
Las redes neuronales son herramientas esenciales en el aprendizaje profundo, y su implementación práctica ha sido simplificada gracias a bibliotecas como Keras. En este tutorial, exploraremos cómo construir una red neuronal desde cero utilizando Keras en Python para predecir si el precio de una casa está por encima o por debajo del valor mediano. Cubriremos todo el proceso, desde la preparación de los datos hasta la visualización de resultados y la aplicación de técnicas para mitigar el sobreajuste. Este artículo está diseñado para principiantes en aprendizaje automático que deseen dominar los fundamentos de las redes neuronales en un entorno práctico con código reproducible. A lo largo de esta guía, usaremos un conjunto de datos adaptado de una competencia de Kaggle sobre predicción de precios de viviendas, simplificado para enfocarnos en un problema de clasificación binaria.
Antes de comenzar, asegúrate de tener un entorno de Python configurado con las bibliotecas necesarias: Keras, TensorFlow, pandas, scikit-learn y matplotlib. Puedes instalarlas ejecutando el siguiente comando en tu terminal:
pip install tensorflow pandas scikit-learn matplotlib
Además, necesitarás un conjunto de datos en formato CSV que contenga características de viviendas, como el área del terreno, la calidad general y el número de habitaciones, junto con una columna que indique si el precio está por encima o por debajo de la mediana. Este tutorial asume que tienes conocimientos básicos de Python y una comprensión intuitiva de conceptos como redes neuronales, sobreajuste y regularización.
Exploración y procesamiento de los datos
El primer paso para construir una red neuronal es preparar los datos en un formato que el modelo pueda procesar. Esto implica leer el archivo CSV, convertir los datos en arreglos, dividirlos en características de entrada y etiquetas, escalarlos para uniformidad y separar el conjunto en datos de entrenamiento, validación y prueba.
Comenzamos importando la biblioteca pandas para leer el archivo CSV. El siguiente código carga el conjunto de datos en un DataFrame:
import pandas as pd
df = pd.read_csv('housepricedata.csv')
El conjunto de datos contiene 10 columnas de características de entrada, como área del terreno, calidad general (escala de 1 a 10), condición general, área del sótano, número de baños completos y medios, dormitorios sobre el suelo, número total de habitaciones, chimeneas y área del garaje. La última columna indica si el precio de la casa está por encima de la mediana (1 para sí, 0 para no). Para explorar el contenido, puedes ejecutar:
df
Esto mostrará una tabla con las primeras filas del conjunto de datos. A continuación, convertimos el DataFrame en un arreglo NumPy para facilitar su manipulación:
dataset = df.values
El arreglo resultante contiene todas las filas y columnas del DataFrame. Ahora, dividimos el conjunto en características de entrada (X) y etiquetas (Y). Las primeras 10 columnas corresponden a las características, mientras que la última es la etiqueta:
X = dataset[:, 0:10]
Y = dataset[:, 10]
En el código anterior, [:, 0:10] selecciona todas las filas y las primeras 10 columnas, mientras que [:, 10] toma la última columna. Este paso asegura que X contenga las características y Y las etiquetas.
El siguiente paso es escalar las características para que tengan magnitudes similares, lo que facilita el entrenamiento de la red neuronal. Características como el área del terreno (en miles) y el número de chimeneas (0 a 2) tienen rangos muy diferentes, lo que puede dificultar la convergencia del modelo. Usaremos el escalador MinMaxScaler de scikit-learn para normalizar las características al rango [0, 1]:
from sklearn import preprocessing
min_max_scaler = preprocessing.MinMaxScaler()
X_scale = min_max_scaler.fit_transform(X)
Para verificar el resultado, puedes inspeccionar X_scale:
X_scale
El resultado será un arreglo donde todas las características están escaladas entre 0 y 1. Finalmente, dividimos el conjunto de datos en entrenamiento (70%), validación (15%) y prueba (15%). Usamos la función train_test_split de scikit-learn para realizar esta división en dos pasos:
from sklearn.model_selection import train_test_split
X_train, X_val_and_test, Y_train, Y_val_and_test = train_test_split(X_scale, Y, test_size=0.3)
X_val, X_test, Y_val, Y_test = train_test_split(X_val_and_test, Y_val_and_test, test_size=0.5)
El primer split asigna el 30% de los datos a validación y prueba, mientras que el segundo divide este subconjunto equitativamente. Para confirmar las dimensiones de los conjuntos resultantes, ejecuta:
print(X_train.shape, X_val.shape, X_test.shape, Y_train.shape, Y_val.shape, Y_test.shape)
La salida debería ser similar a:
(1022, 10) (219, 10) (219, 10) (1022,) (219,) (219,)
Esto indica que el conjunto de entrenamiento tiene 1022 muestras, los conjuntos de validación y prueba tienen 219 cada uno, y las características de entrada tienen 10 dimensiones, mientras que las etiquetas son unidimensionales.
En resumen, hemos preparado los datos convirtiendo el CSV en arreglos, separando características y etiquetas, escalando las características y dividiendo el conjunto en entrenamiento, validación y prueba, listos para entrenar nuestra red neuronal.
Construcción y entrenamiento de la red neuronal
Con los datos preparados, pasamos a construir y entrenar la red neuronal. Este proceso se divide en dos pasos: definir la arquitectura del modelo y encontrar los mejores parámetros mediante entrenamiento.
Definición de la arquitectura
Diseñaremos una red neuronal con tres capas: dos capas ocultas con 32 neuronas cada una y activación ReLU, y una capa de salida con una neurona y activación sigmoide, adecuada para un problema de clasificación binaria. Usaremos el modelo Sequential de Keras, que permite apilar capas de manera lineal.
Primero, importamos los módulos necesarios:
from keras.models import Sequential
from keras.layers import Dense
Luego, definimos la arquitectura:
model = Sequential([
Dense(32, activation='relu', input_shape=(10,)),
Dense(32, activation='relu'),
Dense(1, activation='sigmoid')
])
En este código, Sequential crea un modelo donde las capas se apilan en orden. La primera capa tiene 32 neuronas, activación ReLU y un input_shape de 10 para coincidir con las 10 características de entrada. La segunda capa también tiene 32 neuronas y activación ReLU, sin necesidad de especificar la forma de entrada, ya que Keras la infiere automáticamente. La capa de salida tiene una neurona con activación sigmoide, que produce una probabilidad entre 0 y 1, ideal para clasificación binaria.
Configuración y entrenamiento
Antes de entrenar, configuramos el modelo especificando el optimizador, la función de pérdida y las métricas a monitorear. Usaremos gradiente descendente estocástico (SGD) como optimizador, entropía cruzada binaria como función de pérdida (adecuada para clasificación binaria) y precisión como métrica adicional:
model.compile(optimizer='sgd',
loss='binary_crossentropy',
metrics=['accuracy'])
Con el modelo configurado, lo entrenamos usando los datos de entrenamiento y validación:
hist = model.fit(X_train, Y_train,
batch_size=32, epochs=100,
validation_data=(X_val, Y_val))
El método fit ajusta los parámetros del modelo a los datos. Especificamos un tamaño de lote de 32, lo que significa que el modelo procesa 32 muestras antes de actualizar los pesos, y entrenamos durante 100 épocas. Los datos de validación permiten monitorear el rendimiento en un conjunto separado durante el entrenamiento. El historial del entrenamiento se almacena en hist para su posterior análisis.
Para evaluar el modelo en el conjunto de prueba, ejecutamos:
model.evaluate(X_test, Y_test)[1]
Esto devuelve la precisión en el conjunto de prueba, que debería estar entre 80% y 95%, dependiendo de la aleatoriedad en la división de datos y la inicialización de pesos. La salida será un valor numérico, como:
0.8858447670936584
Hemos construido y entrenado nuestra primera red neuronal con solo unas pocas líneas de código, logrando una precisión aceptable en un problema de clasificación real.
Visualización de pérdida y precisión
Para evaluar si nuestro modelo sufre de sobreajuste, visualizaremos la pérdida y la precisión tanto en los conjuntos de entrenamiento como de validación a lo largo de las épocas. Esto nos ayudará a identificar si el modelo está aprendiendo patrones generalizables o simplemente memorizando los datos de entrenamiento.
Usaremos la biblioteca matplotlib para generar gráficos. Primero, importamos el módulo:
import matplotlib.pyplot as plt
Para graficar la pérdida, ejecutamos:
plt.plot(hist.history['loss'])
plt.plot(hist.history['val_loss'])
plt.title('Pérdida del modelo')
plt.ylabel('Pérdida')
plt.xlabel('Época')
plt.legend(['Entrenamiento', 'Validación'], loc='upper right')
plt.show()
Este código genera un gráfico que muestra cómo la pérdida del modelo disminuye con el tiempo. Si las curvas de entrenamiento y validación son similares, el modelo no está sobreajustando significativamente. La salida será un gráfico donde ambas curvas deberían converger hacia valores bajos.
Para la precisión, usamos un código similar:
plt.plot(hist.history['accuracy'])
plt.plot(hist.history['val_accuracy'])
plt.title('Precisión del modelo')
plt.ylabel('Precisión')
plt.xlabel('Época')
plt.legend(['Entrenamiento', 'Validación'], loc='lower right')
plt.show()
Este gráfico mostrará cómo la precisión aumenta con las épocas. Si la precisión de entrenamiento es mucho mayor que la de validación, podría indicar sobreajuste. En nuestro caso, las curvas deberían estar relativamente cercanas, sugiriendo un modelo bien equilibrado.
Estos gráficos proporcionan una herramienta visual para diagnosticar el rendimiento del modelo y ajustar hiperparámetros si es necesario.
Aplicación de regularización para mitigar el sobreajuste
Para ilustrar cómo manejar el sobreajuste, crearemos un modelo más grande que sea propenso a este problema y luego aplicaremos técnicas de regularización, como L2 y dropout, para mejorarlo.
Definimos un modelo con cuatro capas ocultas de 1000 neuronas cada una, usando el optimizador Adam, que es una variante avanzada de gradiente descendente:
model_2 = Sequential([
Dense(1000, activation='relu', input_shape=(10,)),
Dense(1000, activation='relu'),
Dense(1000, activation='relu'),
Dense(1000, activation='relu'),
Dense(1, activation='sigmoid')
])
model_2.compile(optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy'])
hist_2 = model_2.fit(X_train, Y_train,
batch_size=32, epochs=100,
validation_data=(X_val, Y_val))
Para visualizar el sobreajuste, graficamos la pérdida:
plt.plot(hist_2.history['loss'])
plt.plot(hist_2.history['val_loss'])
plt.title('Pérdida del modelo')
plt.ylabel('Pérdida')
plt.xlabel('Época')
plt.legend(['Entrenamiento', 'Validación'], loc='upper right')
plt.show()
El gráfico probablemente mostrará una pérdida de entrenamiento que disminuye constantemente, mientras que la pérdida de validación aumenta después de unas pocas épocas, indicando sobreajuste severo. Un gráfico de precisión similar confirmará esta divergencia:
plt.plot(hist_2.history['accuracy'])
plt.plot(hist_2.history['val_accuracy'])
plt.title('Precisión del modelo')
plt.ylabel('Precisión')
plt.xlabel('Época')
plt.legend(['Entrenamiento', 'Validación'], loc='lower right')
plt.show()
Para mitigar el sobreajuste, incorporaremos regularización L2 y dropout. Importamos los módulos necesarios:
from keras.layers import Dropout
from keras import regularizers
Definimos un tercer modelo con las mismas capas, pero añadimos regularización L2 (con un factor de 0.01) y dropout (con una probabilidad de 0.3):
model_3 = Sequential([
Dense(1000, activation='relu', kernel_regularizer=regularizers.l2(0.01), input_shape=(10,)),
Dropout(0.3),
Dense(1000, activation='relu', kernel_regularizer=regularizers.l2(0.01)),
Dropout(0.3),
Dense(1000, activation='relu', kernel_regularizer=regularizers.l2(0.01)),
Dropout(0.3),
Dense(1000, activation='relu', kernel_regularizer=regularizers.l2(0.01)),
Dropout(0.3),
Dense(1, activation='sigmoid', kernel_regularizer=regularizers.l2(0.01))
])
model_3.compile(optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy'])
hist_3 = model_3.fit(X_train, Y_train,
batch_size=32, epochs=100,
validation_data=(X_val, Y_val))
La regularización L2 agrega una penalización basada en la magnitud de los pesos al cálculo de la pérdida, mientras que dropout desactiva aleatoriamente un 30% de las neuronas en cada iteración, promoviendo generalización. Graficamos la pérdida con un rango ajustado para mejor visualización:
plt.plot(hist_3.history['loss'])
plt.plot(hist_3.history['val_loss'])
plt.title('Pérdida del modelo')
plt.ylabel('Pérdida')
plt.xlabel('Época')
plt.legend(['Entrenamiento', 'Validación'], loc='upper right')
plt.ylim(top=1.2, bottom=0)
plt.show()
El gráfico resultante mostrará curvas de pérdida más cercanas, indicando que la regularización ha reducido el sobreajuste. Para la precisión, ejecutamos:
plt.plot(hist_3.history['accuracy'])
plt.plot(hist_3.history['val_accuracy'])
plt.title('Precisión del modelo')
plt.ylabel('Precisión')
plt.xlabel('Época')
plt.legend(['Entrenamiento', 'Validación'], loc='lower right')
plt.show()
Este gráfico debería mostrar una mejora significativa en la alineación entre la precisión de entrenamiento y validación, confirmando que las técnicas de regularización han hecho el modelo más robusto.
Conclusiones
Este tutorial ha cubierto el proceso completo de construcción de una red neuronal con Keras, desde la preparación de datos hasta la mitigación del sobreajuste. Hemos aprendido a cargar y procesar un conjunto de datos, definir y entrenar una red neuronal, visualizar métricas de rendimiento y aplicar regularización para mejorar la generalización. Con solo unas pocas líneas de código, Keras simplifica la creación de modelos de aprendizaje profundo, haciéndolo accesible para principiantes mientras ofrece flexibilidad para experimentos avanzados. Puedes extender este conocimiento explorando arquitecturas más complejas, como redes convolucionales para visión por computadora, o ajustando hiperparámetros para optimizar el Rendimiento. Continúa practicando con diferentes conjuntos de datos y configuraciones para consolidar tus habilidades en aprendizaje profundo.