Predicción de Neumonía en imágenes de tórax
Aplicación de arquitectura DenseNet-201 para clasificar radiografías de tórax y predecir la presencia de neumonía gracias al dataset público Chest X-Ray Images.
Contexto Médico
La neumonía es una infección pulmonar que inflama los sacos de aire de uno o ambos pulmones, llenándolos de líquido o pus. Esto provoca síntomas como tos con flema, fiebre, escalofríos y dificultad para respirar. Diversos microorganismos (bacterias, virus y hongos) pueden causarla.
En una radiografía de tórax, las diferencias clave son:
| Pulmón Sano | Pulmón con Neumonía |
|---|---|
| Transparencia pulmonar (se ven oscuros por el aire) | Opacidades o consolidaciones (áreas blancas/grises por líquido o pus) |
| Sin zonas blancas anormales | Broncograma aéreo (líneas oscuras dentro de zonas blancas) |
| Estructuras definidas (corazón, diafragma, vasos) | Infiltrados lobares o intersticiales |
DenseNet-201
DenseNet-201 es una red neuronal convolucional profunda de 201 capas, perteneciente a la familia de las Dense Convolutional Networks (DenseNets), introducidas en 2016 por Gao Huang y colaboradores.
En una red convolucional tradicional con L capas existen L conexiones (cada capa se conecta solo con su sucesora). En una DenseNet con L capas existen L(L+1)/2 conexiones directas: cada capa recibe como entrada los mapas de características de todas las capas anteriores y entrega los suyos a todas las capas siguientes. Esto permite un flujo de gradientes más eficiente y reduce el problema del desvanecimiento del gradiente.
Dataset
Se utilizó el dataset Pneumonia X-Ray Images de Paulo Breviglieri (Kaggle), una versión más balanceada del dataset original de Paul Mooney.
Distribución de imágenes:
| Split | Neumonía | Normal | Total |
|---|---|---|---|
| Train | 3.110 | 1.082 | 4.192 |
| Validation | 773 | 267 | 1.040 |
| Test | 390 | 234 | 624 |
Se observa un desbalance significativo: la clase “Neumonía” tiene aproximadamente el triple de imágenes que la clase “Normal” en cada split.
Preprocesamiento
- Redimensionamiento a 224×224 píxeles con 3 canales RGB
- Normalización de píxeles (rescaling 1/255)
- Data augmentation aplicada al generador de entrenamiento:
- Rotación aleatoria (±30°)
- Zoom aleatorio (0.2)
- Desplazamiento horizontal y vertical (0.2)
- Variación de brillo (rango 0.7–1.3)
- Volteo horizontal aleatorio
- Relleno con valores cercanos (nearest)
Arquitectura del Modelo
Se aplicó transfer learning usando DenseNet-201 pre-entrenada con pesos de ImageNet como extractor de características (capas congeladas), añadiendo capas superiores personalizadas:
Input (224×224×3)
└── DenseNet-201 (congelada, pesos ImageNet)
└── GlobalAveragePooling2D
└── Dense(1536, relu) → Dropout(0.1)
└── Dense(512, relu) → Dropout(0.1)
└── Dense(1024, relu) → Dropout(0.1)
└── Dense(512, relu) → Dropout(0.1)
└── Dense(2, softmax)
La configuración de capas y dropout (0.1) se basó en los resultados del paper “Optimizing DenseNet for Potato Leaf Disease Classification” (arXiv 2402.03347), que demostró que un dropout de 0.1 logra el mejor balance entre rendimiento en entrenamiento y validación.
Entrenamiento
| Parámetro | Valor |
|---|---|
| Optimizador | Adam |
| Función de pérdida | Categorical Crossentropy |
| Métrica | Accuracy |
| Épocas máximas | 20 |
| Early Stopping | Paciencia de 6 épocas, monitorizando val_loss |
| Batch size | 32 (entrenamiento), 8 (test) |
Se calculó pesos de clases inversamente proporcionales a la frecuencia, pero no se aplicaron durante el entrenamiento.
Resultados
Curva de entrenamiento
El modelo alcanzó ~95–96% de accuracy en entrenamiento y validación durante las 20 épocas, con pérdidas decrecientes y sobreajuste casi nulo entre ambas curvas.
Evaluación en test
| Métrica | Clase Normal (0) | Clase Neumonía (1) |
|---|---|---|
| Precisión | 0.95 | 0.80 |
| Recall | 0.59 | 0.98 |
| F1-score | 0.73 | 0.88 |
Accuracy global en test: 83.8% (loss: 0.42)
Matriz de Confusión
| Predicho Normal | Predicho Neumonía | |
|---|---|---|
| Real Normal | 135 | 99 |
| Real Neumonía | 6 | 384 |
Interpretación
- El modelo detecta correctamente la mayoría de los casos de neumonía (98% de recall).
- Sin embargo, tiene un rendimiento deficiente en la clase Normal (solo 59% de recall), clasificando erróneamente 99 imágenes normales como neumonía.
- Esto evidencia un sesgo hacia la clase dominante debido al desbalance del dataset y la no utilización de los pesos de clase calculados.
Conclusiones
- Alta precisión en neumonía — el modelo identifica correctamente la mayoría de los casos positivos.
- Bajo desempeño en clase normal — alta tasa de falsos positivos (99 imágenes) debido al desbalance.
- Sobreajuste — aunque la validación mostraba buen rendimiento, el test reveló una caída significativa, posiblemente porque train y validation provenían del mismo
ImageDataGenerator, lo que pudo llevar a memorización de patrones.
Mejoras Propuestas
- Aplicar class_weights durante el entrenamiento para equilibrar la importancia de ambas clases.
- Fine-tuning descongelando capas superiores de DenseNet-201 con un learning rate reducido.
- Data augmentation específica para la clase minoritaria (Normal) para mejorar la generalización.
Versiones
El proyecto se desarrolló con las siguientes librerías y versiones:
| Paquete | Versión |
|---|---|
| Python | 3.12.3 |
| TensorFlow | 2.18.0 |
| Keras | 3.7.0 |
| scikit-learn | 1.5.1 |
| matplotlib | 3.9.2 |
| numpy | 1.26.4 |
| pandas | 2.2.2 |
| seaborn | 0.13.2 |
Referencias
- Huang, G., Liu, Z., Van Der Maaten, L., & Weinberger, K. Q. (2017). Densely Connected Convolutional Networks. arXiv:1608.06993.
- Breviglieri, P. Pneumonia X-Ray Images. Kaggle.
- Mooney, P. Chest X-Ray Images (Pneumonia). Kaggle.
- Paper de referencia para arquitectura adaptada: arXiv 2402.03347.