/ Proyectos / Salud / Clasificación de severidad de retinopatía diabética

Clasificación de severidad de retinopatía diabética: por qué el accuracy no basta sin atención ni transfer learning

ResNet50 con bloques de atención frente a VGG16 y a un baseline sin transfer learning, y el hallazgo que solo aparece cuando se mira el recall por clase, no el accuracy general.

13 min de lectura Python · TensorFlow · Keras Datos: imágenes de fondo de ojo (dataset público) Aplicable a tesis y proyectos aplicados
Matrices de confusión comparando ResNet50 con atención, VGG16 con atención y un baseline sin transfer learning, para clasificar severidad de retinopatía diabética

El objetivo era clasificar el grado de severidad de retinopatía diabética (5 niveles, de sano a proliferativa) a partir de imágenes de fondo de ojo. El problema real no era solo entrenar un modelo que clasificara bien: era entender qué significa "bien" cuando el dataset está fuertemente desbalanceado hacia la clase sana, y casi todo lo interesante para un caso de uso médico está en las clases minoritarias.

Se compararon tres configuraciones sobre la misma tarea: un backbone ResNet50 preentrenado en ImageNet con dos bloques de atención añadidos, el mismo esquema de atención pero con VGG16 como backbone, y un modelo VGG16 sin atención y sin pesos preentrenados, como punto de comparación. El hallazgo no estuvo en cuál modelo "ganó" en accuracy, estuvo en lo que el accuracy por sí solo no mostraba.

Nota importante

Este es un ejercicio técnico de clasificación de imágenes con fines educativos y de investigación aplicada. No es un dispositivo médico, no está validado clínicamente, y no debe usarse como herramienta de diagnóstico. El dataset es público y de acceso abierto.


Mapa del casoContenido


Estructura de alto nivelDiagrama de la solución

Entrada Imagen de fondo de ojo (512, 512, 3) Backbone preentrenado ResNet50 o VGG16 weights='imagenet' · include_top=False ⚠ Sin esto: 0% recall en severidad 1-4 Atención global Pooling + Conv2D + sigmoid resalta canales y zonas relevantes Atención por categoría Conv2D + BatchNorm + GlobalMaxPool un mapa de atención por cada grado (0-4) GlobalAveragePooling2D vector de características por imagen Dense(5, softmax) una neurona por grado de severidad Predicción Grado de severidad (0-4) ⚠ Nota Ejercicio técnico, no un dispositivo médico ni herramienta de diagnóstico clínico

Pasa el cursor sobre cada bloque. El bloque punteado naranja muestra qué pasa si se elimina el transfer learning y la atención.

Los dos bloques de atención y el transfer learning no son mejoras cosméticas sobre una arquitectura que ya funcionaba. Son, literalmente, la diferencia entre un modelo que detecta enfermedad y uno que no detecta ninguna, como se ve en la siguiente sección.


Cómo se construyóConstrucción de la solución

Condiciones del proyecto

RestricciónDato
ObjetivoEjercicio técnico de clasificación de imágenes médicas, no un producto clínico
DatasetImágenes públicas de fondo de ojo, 5 grados de severidad, fuertemente desbalanceado hacia la clase sana
Detalle a detectarMuy fino: las diferencias visuales entre grados de severidad son sutiles, difíciles para una CNN convencional
Split de datos70% entrenamiento, 15% validación, 15% prueba, sin mezclar imágenes del mismo paciente entre splits
OpciónPor qué se descartó
Entrenar una CNN convencional sin atenciónNo captura los detalles finos que distinguen un grado de severidad de otro
Entrenar desde cero, sin pesos preentrenadosCon un dataset médico de tamaño moderado, no alcanza a aprender patrones visuales generales desde el inicio
Reportar solo el accuracy general de cada modeloCon un dataset desbalanceado, un accuracy alto puede lograrse sin detectar ninguna clase minoritaria
Backbone preentrenado (ImageNet) + atención global + atención por categoría, evaluado con recall por claseDa contexto visual general (transfer learning) y detalle específico por severidad (atención), y el recall por clase expone si realmente detecta enfermedad

Pasos

1

Cómo manejar el desbalance de clases

Agente: propuso solo hacer oversampling de las clases minoritarias antes de entrenar.
Criterio aplicado: combinar el balanceo del set de entrenamiento con un bloque de atención por categoría dentro de la arquitectura, porque el desbalance no es solo un problema de cantidad de ejemplos, también lo es de qué tan distinguibles son los detalles visuales de cada clase.

2

Qué backbone usar

Agente: sugirió usar el backbone más simple posible para acelerar el entrenamiento.
Criterio aplicado: comparar explícitamente ResNet50 contra VGG16 con la misma configuración de atención, porque la elección del backbone resultó tener más impacto en el resultado que cualquier otro ajuste probado.

3

Qué métrica reportar como resultado principal

Agente: propuso reportar el accuracy general de cada modelo como métrica principal.
Criterio aplicado: reportar el recall por clase junto con el accuracy, porque en un problema médico desbalanceado, el costo de no detectar un caso real de enfermedad es mucho mayor que el de una falsa alarma.

4

Estrategia de fine-tuning del backbone

Agente: propuso descongelar todas las capas del backbone desde la primera época.
Criterio aplicado: congelar el backbone durante una fase inicial (para no destruir los pesos preentrenados con gradientes grandes al principio) y descongelarlo después, con un learning rate mucho menor, para hacer fine-tuning fino sin perder lo aprendido en ImageNet.

Proceso de iteración

El hallazgo central, sin suavizarlo

El modelo baseline (VGG16, sin atención, sin transfer learning) llegó a 68% de accuracy general, un número que a primera vista no se ve mal. Pero al revisar el recall por clase, ese modelo tuvo 0% de recall en las 4 clases de severidad de retinopatía (grados 1 a 4): nunca predijo ninguna de ellas, solo aprendió a decir "sano" siempre, la clase mayoritaria del dataset. El 68% de accuracy es, en los hechos, el porcentaje de pacientes sanos en el set de prueba, no una medida de que el modelo funcione. Solo al agregar transfer learning y los bloques de atención (ResNet50) el recall en las clases severas subió a valores entre 0.71 y 0.88, con VGG16+atención en un punto intermedio (0.13 a 0.31 de recall en esas mismas clases). Este es el mismo modelo, la misma tarea, y una diferencia de arquitectura que decide si el sistema detecta enfermedad o no detecta nada.

Ajuste documentado, no oculto

Al revisar el código original para adaptarlo, se encontró un error real en la fase de entrenamiento con capas congeladas del modelo ResNet: la llamada de entrenamiento apuntaba a una variable de modelo distinta a la que se había construido, un error de copiar y pegar entre secciones del notebook. Se corrigió en la versión reproducible de este repositorio. Se documenta aquí porque es exactamente el tipo de error silencioso que puede pasar desapercibido en un notebook largo, y que vale la pena revisar activamente antes de confiar en cualquier resultado.


CierreLecciones importantes

En un problema médico con clases desbalanceadas, el accuracy general puede ser, literalmente, el porcentaje de la clase mayoritaria. Reportarlo solo, sin desglosar por clase, no es un error técnico menor, es ocultar la pregunta que más importa: ¿el modelo detecta los casos que realmente importan detectar?

La combinación de transfer learning y atención no fue una mejora incremental sobre un modelo que ya funcionaba: fue la diferencia entre un sistema que nunca identifica enfermedad y uno que sí lo hace, aunque de forma imperfecta. Esa diferencia solo se ve si, desde el diseño del experimento, se decide medir lo que de verdad importa, no solo lo que es fácil de reportar.

El esquema de atención global + atención por categoría usado aquí sigue la misma idea de CABNet, un enfoque publicado específicamente para el desbalance de clases en gradación de retinopatía diabética: CABNet: Category Attention Block for Imbalanced Diabetic Retinopathy Grading.

Termina ya tu proyecto

¿Tienes un proyecto similar y no sabes por dónde empezar? Yo te ayudo a diseñarlo.

El 92% de los profesionales de datos desbloquea sus proyectos al ver ejemplos completos resueltos.

53
proyectos
8
sectores
100%
aplicado

Sin registro. Acceso inmediato