Aplicación Práctica: Construcción de una Red Neuronal con Keras
7 min read
Por Alvaro Efren Bolaños Scalante
Aplicación Práctica: Construcción de una Red Neuronal con Keras
🎯 Introducción
Tras explorar los fundamentos matemáticos, es hora de pasar de la teoría a la práctica. Utilizaremos Keras, una biblioteca de alto nivel para Deep Learning, para construir, entrenar y evaluar una red neuronal.
📦 Caso de Estudio: Clasificación de Dígitos (MNIST)
Trabajaremos con el dataset MNIST: 70,000 imágenes de dígitos escritos a mano (0-9).
1📊 Dataset MNIST: 2 - Imágenes: 28×28 píxeles en escala de grises 3 - Entrenamiento: 60,000 imágenes 4 - Prueba: 10,000 imágenes 5 - Clases: 10 (dígitos 0-9)
🛠️ Paso 1: Preparación y Preprocesado de Datos
1.1 Instalación de Dependencias
bash1pip install tensorflow numpy matplotlib scikit-learn
1.2 Importar Bibliotecas
python1import numpy as np 2import matplotlib.pyplot as plt 3from tensorflow import keras 4from tensorflow.keras import Sequential 5from tensorflow.keras.layers import Dense, Flatten 6from tensorflow.keras.utils import to_categorical
1.3 Cargar el Dataset
python1# Cargar MNIST 2(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data() 3 4print(f"Forma de x_train: {x_train.shape}") # (60000, 28, 28) 5print(f"Forma de y_train: {y_train.shape}") # (60000,) 6print(f"Forma de x_test: {x_test.shape}") # (10000, 28, 28)
1.4 Visualizar Ejemplos
python1# Visualizar las primeras 9 imágenes 2plt.figure(figsize=(10, 10)) 3for i in range(9): 4 plt.subplot(3, 3, i+1) 5 plt.imshow(x_train[i], cmap='gray') 6 plt.title(f"Etiqueta: {y_train[i]}") 7 plt.axis('off') 8plt.tight_layout() 9plt.show()
1.5 Normalización
Escalar píxeles de [0, 255] → [0, 1]:
python1# Normalizar 2x_train = x_train.astype('float32') / 255.0 3x_test = x_test.astype('float32') / 255.0 4 5print(f"Rango de valores: [{x_train.min()}, {x_train.max()}]") 6# Salida: [0.0, 1.0]
1.6 Codificación One-Hot
Convertir etiquetas en vectores:
python1# One-hot encoding 2y_train_encoded = to_categorical(y_train, num_classes=10) 3y_test_encoded = to_categorical(y_test, num_classes=10) 4 5print(f"Etiqueta original: {y_train[0]}") 6print(f"Etiqueta codificada:\n{y_train_encoded[0]}") 7 8# Salida: 9# Etiqueta original: 5 10# Etiqueta codificada: [0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]
🏗️ Paso 2: Definición y Compilación del Modelo
2.1 Arquitectura de la Red
python1model = Sequential([ 2 # Aplanar imagen 28x28 a vector 784 3 Flatten(input_shape=(28, 28)), 4 5 # Primera capa oculta: 128 neuronas con ReLU 6 Dense(128, activation='relu'), 7 8 # Segunda capa oculta: 64 neuronas con ReLU 9 Dense(64, activation='relu'), 10 11 # Capa de salida: 10 neuronas con Softmax 12 Dense(10, activation='softmax') 13])
Arquitectura Visual:
1┌─────────────┐ 2│ Input │ 28×28 imagen 3│ (28, 28) │ 4└──────┬──────┘ 5 │ 6┌──────▼──────┐ 7│ Flatten │ Transforma a vector 784 8│ (784) │ 9└──────┬──────┘ 10 │ 11┌──────▼──────┐ 12│ Dense │ 128 neuronas + ReLU 13│ (128) │ 14└──────┬──────┘ 15 │ 16┌──────▼──────┐ 17│ Dense │ 64 neuronas + ReLU 18│ (64) │ 19└──────┬──────┘ 20 │ 21┌──────▼──────┐ 22│ Dense │ 10 neuronas + Softmax 23│ (10) │ (probabilidades por clase) 24└─────────────┘
2.2 Resumen del Modelo
python1model.summary()
Salida:
1_________________________________________________________________ 2Layer (type) Output Shape Param # 3================================================================= 4flatten (Flatten) (None, 784) 0 5_________________________________________________________________ 6dense (Dense) (None, 128) 100480 7_________________________________________________________________ 8dense_1 (Dense) (None, 64) 8256 9_________________________________________________________________ 10dense_2 (Dense) (None, 10) 650 11================================================================= 12Total params: 109,386 13Trainable params: 109,386 14Non-trainable params: 0
2.3 Compilar el Modelo
python1model.compile( 2 optimizer='adam', # Optimizador Adam 3 loss='categorical_crossentropy', # Para clasificación multiclase 4 metrics=['accuracy'] # Métrica a monitorear 5)
Opciones de optimizadores:
- : Descenso de gradiente estocástico
1'sgd'
- : Adam (recomendado para principiantes)
1'adam'
- : RMSprop
1'rmsprop'
🚀 Paso 3: Entrenamiento del Modelo
3.1 Entrenar
python1history = model.fit( 2 x_train, 3 y_train_encoded, 4 epochs=10, # Número de épocas 5 batch_size=32, # Tamaño del mini-lote 6 validation_split=0.2, # 20% para validación 7 verbose=1 # Mostrar progreso 8)
Salida durante el entrenamiento:
1Epoch 1/10 21500/1500 [======] - 3s 2ms/step - loss: 0.2645 - accuracy: 0.9234 - val_loss: 0.1345 - val_accuracy: 0.9612 3Epoch 2/10 41500/1500 [======] - 2s 1ms/step - loss: 0.1123 - accuracy: 0.9665 - val_loss: 0.1012 - val_accuracy: 0.9701 5...
3.2 Visualizar el Aprendizaje
python1# Extraer historial 2train_loss = history.history['loss'] 3val_loss = history.history['val_loss'] 4train_acc = history.history['accuracy'] 5val_acc = history.history['val_accuracy'] 6 7# Crear gráficas 8fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5)) 9 10# Gráfica de pérdida 11ax1.plot(train_loss, label='Entrenamiento', marker='o') 12ax1.plot(val_loss, label='Validación', marker='s') 13ax1.set_title('Pérdida durante el Entrenamiento') 14ax1.set_xlabel('Época') 15ax1.set_ylabel('Pérdida') 16ax1.legend() 17ax1.grid(True) 18 19# Gráfica de precisión 20ax2.plot(train_acc, label='Entrenamiento', marker='o') 21ax2.plot(val_acc, label='Validación', marker='s') 22ax2.set_title('Precisión durante el Entrenamiento') 23ax2.set_xlabel('Época') 24ax2.set_ylabel('Precisión') 25ax2.legend() 26ax2.grid(True) 27 28plt.tight_layout() 29plt.show()
📊 Paso 4: Evaluación del Modelo
4.1 Evaluar en Datos de Prueba
python1test_loss, test_accuracy = model.evaluate(x_test, y_test_encoded, verbose=0) 2 3print(f"\n{'='*50}") 4print(f"📊 RESULTADOS EN DATOS DE PRUEBA") 5print(f"{'='*50}") 6print(f"Pérdida (Loss): {test_loss:.4f}") 7print(f"Precisión (Accuracy): {test_accuracy:.4f} ({test_accuracy*100:.2f}%)") 8print(f"{'='*50}")
Salida esperada:
1================================================== 2📊 RESULTADOS EN DATOS DE PRUEBA 3================================================== 4Pérdida (Loss): 0.0856 5Precisión (Accuracy): 0.9741 (97.41%) 6==================================================
4.2 Hacer Predicciones
python1# Predecir las primeras 10 imágenes del test 2predictions = model.predict(x_test[:10]) 3 4# Convertir probabilidades a clases 5predicted_classes = np.argmax(predictions, axis=1) 6true_classes = np.argmax(y_test_encoded[:10], axis=1) 7 8# Mostrar resultados 9print("\n🔮 PREDICCIONES:") 10print(f"{'Índice':<10}{'Predicho':<12}{'Real':<10}{'¿Correcto?'}") 11print("-" * 45) 12for i in range(10): 13 correcto = "✅" if predicted_classes[i] == true_classes[i] else "❌" 14 print(f"{i:<10}{predicted_classes[i]:<12}{true_classes[i]:<10}{correcto}")
4.3 Visualizar Predicciones
python1plt.figure(figsize=(15, 6)) 2for i in range(10): 3 plt.subplot(2, 5, i+1) 4 plt.imshow(x_test[i], cmap='gray') 5 6 pred = predicted_classes[i] 7 true = true_classes[i] 8 color = 'green' if pred == true else 'red' 9 10 plt.title(f"Pred: {pred}\nReal: {true}", color=color) 11 plt.axis('off') 12plt.tight_layout() 13plt.show()
💾 Paso 5: Guardar y Cargar el Modelo
5.1 Guardar el Modelo
python1# Guardar el modelo completo 2model.save('modelo_mnist.h5') 3print("✅ Modelo guardado como 'modelo_mnist.h5'") 4 5# O guardar solo los pesos 6model.save_weights('pesos_mnist.h5')
5.2 Cargar el Modelo
python1# Cargar modelo completo 2modelo_cargado = keras.models.load_model('modelo_mnist.h5') 3 4# Verificar que funciona 5test_loss_cargado, test_acc_cargado = modelo_cargado.evaluate( 6 x_test, y_test_encoded, verbose=0 7) 8print(f"Precisión del modelo cargado: {test_acc_cargado:.4f}")
🎨 Código Completo
python1""" 2Red Neuronal para Clasificación de Dígitos MNIST 3Autor: Alvaro Efren Bolaños Scalante 4""" 5 6import numpy as np 7import matplotlib.pyplot as plt 8from tensorflow import keras 9from tensorflow.keras import Sequential 10from tensorflow.keras.layers import Dense, Flatten 11from tensorflow.keras.utils import to_categorical 12 13# ============================================ 14# 1. CARGAR Y PREPROCESAR DATOS 15# ============================================ 16print("📦 Cargando datos...") 17(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data() 18 19# Normalizar 20x_train = x_train.astype('float32') / 255.0 21x_test = x_test.astype('float32') / 255.0 22 23# One-hot encoding 24y_train = to_categorical(y_train, 10) 25y_test = to_categorical(y_test, 10) 26 27print(f"✅ Datos cargados: {x_train.shape[0]} entrenamiento, {x_test.shape[0]} prueba") 28 29# ============================================ 30# 2. DEFINIR MODELO 31# ============================================ 32print("\n🏗️ Construyendo modelo...") 33model = Sequential([ 34 Flatten(input_shape=(28, 28)), 35 Dense(128, activation='relu'), 36 Dense(64, activation='relu'), 37 Dense(10, activation='softmax') 38]) 39 40model.compile( 41 optimizer='adam', 42 loss='categorical_crossentropy', 43 metrics=['accuracy'] 44) 45 46model.summary() 47 48# ============================================ 49# 3. ENTRENAR 50# ============================================ 51print("\n🚀 Entrenando modelo...") 52history = model.fit( 53 x_train, y_train, 54 epochs=10, 55 batch_size=32, 56 validation_split=0.2, 57 verbose=1 58) 59 60# ============================================ 61# 4. EVALUAR 62# ============================================ 63print("\n📊 Evaluando modelo...") 64test_loss, test_acc = model.evaluate(x_test, y_test, verbose=0) 65print(f"\nPrecisión en test: {test_acc:.4f} ({test_acc*100:.2f}%)") 66 67# ============================================ 68# 5. VISUALIZAR 69# ============================================ 70# Gráficas de aprendizaje 71plt.figure(figsize=(14, 5)) 72 73plt.subplot(1, 2, 1) 74plt.plot(history.history['loss'], label='Entrenamiento') 75plt.plot(history.history['val_loss'], label='Validación') 76plt.title('Pérdida') 77plt.xlabel('Época') 78plt.ylabel('Loss') 79plt.legend() 80plt.grid(True) 81 82plt.subplot(1, 2, 2) 83plt.plot(history.history['accuracy'], label='Entrenamiento') 84plt.plot(history.history['val_accuracy'], label='Validación') 85plt.title('Precisión') 86plt.xlabel('Época') 87plt.ylabel('Accuracy') 88plt.legend() 89plt.grid(True) 90 91plt.tight_layout() 92plt.savefig('entrenamiento.png') 93plt.show() 94 95print("\n✅ ¡Entrenamiento completado!")
🎯 Ejercicios Propuestos
- Cambiar la arquitectura: Prueba con más/menos capas y neuronas
- Probar otros optimizadores: ,
1'sgd'
1'rmsprop'
- Ajustar hiperparámetros: learning rate, batch size
- Usar Fashion-MNIST: Dataset de prendas de ropa
- Agregar regularización: Dropout para evitar overfitting
python1# Ejemplo con Dropout 2from tensorflow.keras.layers import Dropout 3 4model = Sequential([ 5 Flatten(input_shape=(28, 28)), 6 Dense(128, activation='relu'), 7 Dropout(0.5), # 50% de dropout 8 Dense(64, activation='relu'), 9 Dropout(0.3), 10 Dense(10, activation='softmax') 11])
📚 Referencias
- Torres, J. (2020). Python Deep Learning: Introducción práctica con Keras y TensorFlow 2. Marcombo.
- Documentación de Keras: https://keras.io
- TensorFlow Tutorials: https://www.tensorflow.org/tutorials
Anterior: ← Blog 3: Proceso de Entrenamiento
Próximo: Blog 5: Evaluación y Desafíos →