EN
Predicción de Neumonía en imágenes de tórax — banner
← Volver a proyectos

Predicción de Neumonía en imágenes de tórax

· 4 min de lectura

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.

Python TensorFlow Scikit-learn Matplotlib Docker

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 SanoPulmó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 anormalesBroncograma 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:

SplitNeumoníaNormalTotal
Train3.1101.0824.192
Validation7732671.040
Test390234624

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ámetroValor
OptimizadorAdam
Función de pérdidaCategorical Crossentropy
MétricaAccuracy
Épocas máximas20
Early StoppingPaciencia de 6 épocas, monitorizando val_loss
Batch size32 (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étricaClase Normal (0)Clase Neumonía (1)
Precisión0.950.80
Recall0.590.98
F1-score0.730.88

Accuracy global en test: 83.8% (loss: 0.42)

Matriz de Confusión

Predicho NormalPredicho Neumonía
Real Normal13599
Real Neumonía6384

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

  1. Alta precisión en neumonía — el modelo identifica correctamente la mayoría de los casos positivos.
  2. Bajo desempeño en clase normal — alta tasa de falsos positivos (99 imágenes) debido al desbalance.
  3. 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

  1. Aplicar class_weights durante el entrenamiento para equilibrar la importancia de ambas clases.
  2. Fine-tuning descongelando capas superiores de DenseNet-201 con un learning rate reducido.
  3. 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:

PaqueteVersión
Python3.12.3
TensorFlow2.18.0
Keras3.7.0
scikit-learn1.5.1
matplotlib3.9.2
numpy1.26.4
pandas2.2.2
seaborn0.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.