Evaluación del Rendimiento y Desafíos Comunes en Deep Learning
5. Evaluación del Rendimiento y Desafíos Comunes
🎯 Introducción
Aunque la precisión (accuracy) es una métrica intuitiva, no siempre es suficiente para una evaluación completa de un modelo. Además, durante el desarrollo de modelos, es común enfrentarse a desafíos como el sobreajuste y el subajuste, que deben ser identificados y gestionados adecuadamente.
📊 La Matriz de Confusión
Una herramienta más profunda para la evaluación es la Matriz de Confusión. Esta tabla visualiza el rendimiento de un algoritmo de clasificación, mostrando explícitamente cuándo una clase es confundida con otra.
Para Clasificación Binaria
Predicción Positiva | Predicción Negativa | |
---|---|---|
Observación Positiva | Verdaderos Positivos (VP) | Falsos Negativos (FN) |
Observación Negativa | Falsos Positivos (FP) | Verdaderos Negativos (VN) |
Componentes:
- VP (True Positives): Casos positivos correctamente identificados
- VN (True Negatives): Casos negativos correctamente identificados
- FP (False Positives): Error Tipo I - predecir positivo cuando es negativo
- FN (False Negatives): Error Tipo II - predecir negativo cuando es positivo
Implementación en Python
python1from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay 2import matplotlib.pyplot as plt 3import numpy as np 4 5# Obtener predicciones del modelo 6y_pred = model.predict(x_test) 7y_pred_classes = np.argmax(y_pred, axis=1) 8y_true = np.argmax(y_test, axis=1) 9 10# Calcular matriz de confusión 11cm = confusion_matrix(y_true, y_pred_classes) 12 13# Visualizar la matriz de confusión 14disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=range(10)) 15disp.plot(cmap='Blues', values_format='d') 16plt.title('Matriz de Confusión - MNIST') 17plt.show()
📈 Métricas Derivadas
1. Precisión (Accuracy)
Mide la proporción de predicciones correctas sobre el total.
Fórmula:
1Accuracy = (VP + VN) / (VP + VN + FP + FN)
Limitación: No es adecuada para conjuntos de datos desbalanceados.
python1from sklearn.metrics import accuracy_score 2 3accuracy = accuracy_score(y_true, y_pred_classes) 4print(f"Accuracy: {accuracy:.4f} ({accuracy*100:.2f}%)")
2. Recall (Sensibilidad o Exhaustividad)
Mide la proporción de positivos reales que fueron correctamente identificados.
Fórmula:
1Recall = VP / (VP + FN)
¿Cuándo es crucial?
- 🏥 Detección de enfermedades: Es crítico no perder ningún caso positivo
- 💳 Identificación de fraudes: Detectar todas las transacciones fraudulentas
- 🍄 Clasificación de setas venenosas: No queremos clasificar erróneamente una seta venenosa como comestible
python1from sklearn.metrics import recall_score 2 3recall = recall_score(y_true, y_pred_classes, average='weighted') 4print(f"Recall: {recall:.4f}")
3. Precisión (Precision)
Mide la proporción de predicciones positivas que fueron correctas.
Fórmula:
1Precision = VP / (VP + FP)
¿Cuándo es crucial?
- 📧 Filtrado de spam: Minimizar que correos legítimos vayan a spam
- 🎯 Recomendaciones de productos: Asegurar que las recomendaciones sean relevantes
python1from sklearn.metrics import precision_score 2 3precision = precision_score(y_true, y_pred_classes, average='weighted') 4print(f"Precision: {precision:.4f}")
4. F1-Score
Media armónica entre Precision y Recall.
Fórmula:
1F1 = 2 · (Precision · Recall) / (Precision + Recall)
python1from sklearn.metrics import f1_score 2 3f1 = f1_score(y_true, y_pred_classes, average='weighted') 4print(f"F1-Score: {f1:.4f}")
Reporte Completo de Clasificación
python1from sklearn.metrics import classification_report 2 3report = classification_report(y_true, y_pred_classes, 4 target_names=[str(i) for i in range(10)], 5 digits=4) 6print(report)
⚠️ Desafíos Comunes: Subajuste y Sobreajuste
🔻 Subajuste (Underfitting)
Definición: Ocurre cuando un modelo es demasiado simple para capturar la complejidad subyacente de los datos.
Características:
- ❌ Alto error en datos de entrenamiento
- ❌ Alto error en datos de validación/prueba
- ❌ El modelo no aprende los patrones subyacentes
Código para detectar underfitting:
python1def detectar_underfitting(history): 2 train_loss = history.history['loss'][-5:] 3 val_loss = history.history['val_loss'][-5:] 4 5 avg_train_loss = np.mean(train_loss) 6 avg_val_loss = np.mean(val_loss) 7 8 if avg_train_loss > 0.5 and avg_val_loss > 0.5: 9 print("⚠️ ALERTA: Posible UNDERFITTING detectado") 10 print(f" - Error de entrenamiento: {avg_train_loss:.4f}") 11 print(f" - Error de validación: {avg_val_loss:.4f}") 12 print("\n💡 Soluciones sugeridas:") 13 print(" 1. Aumentar la complejidad del modelo") 14 print(" 2. Añadir más capas o neuronas") 15 print(" 3. Entrenar por más épocas") 16 return True 17 return False
Estrategias de solución:
1. Aumentar la Complejidad del Modelo
python1# Modelo SIMPLE (propenso a underfitting) 2model_simple = Sequential([ 3 Flatten(input_shape=(28, 28)), 4 Dense(32, activation='relu'), 5 Dense(10, activation='softmax') 6]) 7 8# Modelo MÁS COMPLEJO (mejor capacidad) 9model_complejo = Sequential([ 10 Flatten(input_shape=(28, 28)), 11 Dense(256, activation='relu'), 12 Dense(128, activation='relu'), 13 Dense(64, activation='relu'), 14 Dense(10, activation='softmax') 15])
🔺 Sobreajuste (Overfitting)
Definición: Ocurre cuando un modelo es demasiado complejo y "memoriza" los datos de entrenamiento.
Características:
- ✅ Muy bajo error en datos de entrenamiento
- ❌ Alto error en datos de validación/prueba
- ⚠️ Gran brecha entre error de entrenamiento y validación
Código para detectar overfitting:
python1def detectar_overfitting(history, threshold=0.1): 2 train_loss = history.history['loss'][-5:] 3 val_loss = history.history['val_loss'][-5:] 4 5 avg_train_loss = np.mean(train_loss) 6 avg_val_loss = np.mean(val_loss) 7 8 gap = avg_val_loss - avg_train_loss 9 10 if gap > threshold: 11 print("⚠️ ALERTA: Posible OVERFITTING detectado") 12 print(f" - Error de entrenamiento: {avg_train_loss:.4f}") 13 print(f" - Error de validación: {avg_val_loss:.4f}") 14 print(f" - Brecha: {gap:.4f}") 15 print("\n💡 Soluciones sugeridas:") 16 print(" 1. Usar Dropout") 17 print(" 2. Aplicar regularización L1/L2") 18 print(" 3. Usar Early Stopping") 19 print(" 4. Aumentar datos de entrenamiento") 20 return True 21 return False
Estrategias de solución:
1. Dropout
python1from tensorflow.keras.layers import Dropout 2 3model = Sequential([ 4 Flatten(input_shape=(28, 28)), 5 Dense(128, activation='relu'), 6 Dropout(0.5), # Desactiva 50% de neuronas 7 Dense(64, activation='relu'), 8 Dropout(0.3), 9 Dense(10, activation='softmax') 10])
2. Regularización L1/L2
python1from tensorflow.keras import regularizers 2 3model = Sequential([ 4 Flatten(input_shape=(28, 28)), 5 Dense(128, activation='relu', 6 kernel_regularizer=regularizers.l2(0.01)), 7 Dense(64, activation='relu', 8 kernel_regularizer=regularizers.l1(0.01)), 9 Dense(10, activation='softmax') 10])
3. Early Stopping
python1from tensorflow.keras.callbacks import EarlyStopping 2 3early_stop = EarlyStopping( 4 monitor='val_loss', 5 patience=10, 6 restore_best_weights=True, 7 verbose=1 8) 9 10history = model.fit( 11 x_train, y_train, 12 epochs=100, 13 validation_split=0.2, 14 callbacks=[early_stop] 15)
4. Data Augmentation
python1from tensorflow.keras.preprocessing.image import ImageDataGenerator 2 3datagen = ImageDataGenerator( 4 rotation_range=10, 5 width_shift_range=0.1, 6 height_shift_range=0.1, 7 zoom_range=0.1 8) 9 10history = model.fit( 11 datagen.flow(x_train, y_train, batch_size=32), 12 steps_per_epoch=len(x_train) // 32, 13 epochs=20, 14 validation_data=(x_test, y_test) 15)
🎯 Resumen de Estrategias
Problema | Síntoma | Soluciones |
---|---|---|
Underfitting | Alto error en train y test | Aumentar complejidad del modelo, Más capas/neuronas, Entrenar más épocas |
Overfitting | Bajo error en train, Alto en test | Dropout, Regularización L1/L2, Early stopping, Data augmentation, Más datos |
🧪 Ejemplo Completo: Pipeline Anti-Overfitting
python1import numpy as np 2from tensorflow import keras 3from tensorflow.keras import Sequential 4from tensorflow.keras.layers import Dense, Flatten, Dropout 5from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint 6from tensorflow.keras import regularizers 7 8# Cargar datos 9(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data() 10x_train, x_test = x_train / 255.0, x_test / 255.0 11y_train = keras.utils.to_categorical(y_train, 10) 12y_test = keras.utils.to_categorical(y_test, 10) 13 14# Modelo con técnicas anti-overfitting 15model = Sequential([ 16 Flatten(input_shape=(28, 28)), 17 Dense(128, activation='relu', 18 kernel_regularizer=regularizers.l2(0.001)), 19 Dropout(0.5), 20 Dense(64, activation='relu', 21 kernel_regularizer=regularizers.l2(0.001)), 22 Dropout(0.3), 23 Dense(10, activation='softmax') 24]) 25 26model.compile( 27 optimizer='adam', 28 loss='categorical_crossentropy', 29 metrics=['accuracy'] 30) 31 32# Callbacks 33early_stop = EarlyStopping( 34 monitor='val_loss', 35 patience=10, 36 restore_best_weights=True 37) 38 39checkpoint = ModelCheckpoint( 40 'mejor_modelo.h5', 41 monitor='val_accuracy', 42 save_best_only=True 43) 44 45# Entrenar 46history = model.fit( 47 x_train, y_train, 48 epochs=100, 49 batch_size=32, 50 validation_split=0.2, 51 callbacks=[early_stop, checkpoint] 52) 53 54# Evaluar 55test_loss, test_acc = model.evaluate(x_test, y_test) 56print(f"\nPrecisión en test: {test_acc:.4f} ({test_acc*100:.2f}%)")
🎓 Conclusión
Hemos completado este recorrido por los fundamentos del Deep Learning:
- ✅ Fundamentos del ML: Paradigmas y conceptos básicos
- ✅ Redes Neuronales: Arquitectura y componentes
- ✅ Entrenamiento: Función de costo y backpropagation
- ✅ Implementación: Aplicación práctica con Keras
- ✅ Evaluación: Métricas avanzadas y solución de desafíos
Puntos Clave
🔹 Evaluación: Usa métricas múltiples, no solo accuracy 🔹 Underfitting: Aumenta complejidad, más features, más épocas 🔹 Overfitting: Dropout, regularización, early stopping 🔹 Balance: Busca el punto óptimo entre simplicidad y complejidad
📚 Referencias
- Goodfellow, I., Bengio, Y., & Courville, A. (2016). Deep learning. MIT Press.
- AWS. (s.f.). ¿En qué consiste el ajuste de hiperparámetros?
- Ng, A. (2017). Neural Networks and Deep Learning. Coursera.
← Anterior: Blog 4: Aplicación Práctica con Keras
🏠 Inicio de la serie: Blog 1: Introducción al Machine Learning