Cómo entrené mi primera CNN para detectar COVID-19 en radiografías
Nunca había entrenado una red neuronal para imágenes. Esta es mi bitácora entrenando mi primera CNN para distinguir radiografías de tórax normales de casos COVID-19: lo que me confundió, lo que me hizo clic y los errores que me enseñaron más que los aciertos.
01 ¿Qué es una CNN y por qué para imágenes?
Lo primero que tuve que entender: una red neuronal normal ve una imagen como una lista gigante de píxeles sueltos y pierde la noción de "qué está al lado de qué". Una CNN (red neuronal convolucional) resuelve eso con la idea de convolución: una pequeña ventana que se va deslizando por la imagen buscando patrones (bordes, texturas, formas).
La imagen que me destrabó la intuición: es como pasar una lupa por toda la radiografía, y esa lupa aprende sola qué mirar. Las primeras capas detectan cosas simples (líneas, contrastes); las siguientes combinan eso en cosas más complejas (formas de los pulmones, opacidades). Nadie le dice qué buscar: lo aprende de los ejemplos.
02 Preparar los datos fue el 70% del trabajo
Yo pensaba que lo difícil era "la red". Mentira: lo que más tiempo me tomó fue dejar las imágenes listas. El dataset traía radiografías en dos carpetas (COVID y normal), y antes de entrenar tuve que:
- Redimensionar todo a 224×224 píxeles, porque la red necesita que todas las imágenes tengan el mismo tamaño.
- Normalizar los píxeles de 0–255 a un rango 0–1 (dividir entre 255). Esto ayuda a que la red aprenda más estable.
- Aumentar los datos (data augmentation): girar, hacer zoom y voltear las imágenes para crear variaciones. Con pocas imágenes médicas, este truco es oro.
- Separar en 80% entrenamiento, 10% validación y 10% prueba, para no hacerme trampa evaluando con las mismas imágenes con las que entrené.
from tensorflow.keras.preprocessing.image import ImageDataGenerator
train_datagen = ImageDataGenerator(
rescale=1./255, # de 0–255 a 0–1
rotation_range=15, # girar hasta ±15°
zoom_range=0.1, # zoom 10%
horizontal_flip=True, # espejar
validation_split=0.2
)
03 Armar la red por bloques (no fue tan místico)
Verlo como bloques que se repiten me quitó el miedo. Usé tres bloques convolucionales, cada uno con la misma receta: una capa que busca patrones (Conv2D), una que estabiliza (BatchNormalization), una que reduce el tamaño (MaxPooling) y una que apaga neuronas al azar para que no memorice (Dropout).
model = models.Sequential([
# Bloque 1: patrones simples
layers.Conv2D(32, (3,3), activation='relu', padding='same'),
layers.BatchNormalization(),
layers.MaxPooling2D(2,2),
layers.Dropout(0.25),
# Bloques 2 y 3: más filtros (64 y 128), patrones más complejos
# ...
layers.Flatten(),
layers.Dense(256, activation='relu'),
layers.Dropout(0.5),
layers.Dense(1, activation='sigmoid') # 1 salida: COVID o normal
])
La última capa tiene una sola neurona con sigmoid, que devuelve un número entre 0 y 1: la "probabilidad" de que la radiografía sea COVID. Si es mayor a 0,5, lo cuenta como COVID.
04 El fantasma del sobreajuste
El concepto que más me costó fue el sobreajuste (overfitting): cuando el modelo se aprende las imágenes de memoria en vez de aprender el patrón general. Anda perfecto con lo que ya vio y falla feo con imágenes nuevas. Es como un alumno que memoriza las respuestas del ensayo pero no entiende la materia.
Contra eso usé tres cosas, y ver que funcionaban fue muy satisfactorio:
- Dropout: apagar neuronas al azar obliga a la red a no depender de un solo camino.
- Data augmentation: al ver la misma imagen girada o con zoom, no la puede memorizar.
- EarlyStopping: detiene el entrenamiento solo cuando el modelo deja de mejorar, en vez de seguir hasta memorizar.
Al final la diferencia entre lo que acertaba en entrenamiento y en validación quedó por debajo del 3%. Esa señal —que rinde parecido en datos que nunca vio— fue la que me dijo "ok, esto está aprendiendo de verdad".
05 Las métricas: por qué el "accuracy" no basta
Mi primer instinto fue mirar solo la exactitud (accuracy): qué porcentaje acertó. Llegué a 92,86% y me puse feliz. Pero en un problema médico eso puede engañar, y esta fue la lección más importante del proyecto.
Imagina que de cada 100 radiografías, 90 son normales. Un modelo tramposo que diga "normal" siempre tendría 90% de accuracy… y dejaría pasar TODOS los casos COVID. Por eso hay que mirar otras métricas:
- Recall (sensibilidad): de todos los COVID reales, ¿cuántos detecté? Acá llegué a 94,29%. En medicina esta es la clave, porque el error más grave es un falso negativo (decir "sano" a alguien enfermo).
- Precisión: de los que marqué como COVID, ¿cuántos lo eran de verdad? (91,43%).
- F1-Score: un equilibrio entre las dos anteriores (0,928).
06 Lo que más me costó (siendo honesto)
Para que esto sea una bitácora de verdad y no una foto perfecta, acá van las partes que se me hicieron cuesta arriba:
- Los errores de dimensiones. Pasé horas peleando con mensajes de
shape mismatch. Al final casi siempre era una imagen que no había redimensionado bien, o el tamaño de entrada mal puesto. - Confiar en el accuracy. Me costó aceptar que un 92% podía engañar. Cambiar el chip a "¿qué error me duele más?" fue lo más valioso que aprendí en todo el proyecto.
- El sobreajuste invisible. No entendía por qué el modelo andaba genial en entrenamiento y feo con imágenes nuevas. Ver las curvas de entrenamiento y validación separándose fue el momento en que hizo clic.
- La paciencia. Entrenar toma tiempo y da ansiedad mirar cómo bajan los números. Aprendí a dejar que
EarlyStoppingdecidiera, en vez de cortar yo antes. - No copiar y pegar sin entender. Es fácil pegar código de un tutorial y que "funcione". Obligarme a entender qué hacía cada capa fue más lento, pero es lo que hizo que de verdad aprendiera.
07 Lo que me llevo
Entrenar mi primera CNN me enseñó que el deep learning no es magia negra: es preparar bien los datos, armar la red por bloques con sentido, cuidar el sobreajuste y elegir las métricas según el problema. Cada paso tiene una lógica, y cuando la entiendes deja de dar miedo.
¿El siguiente paso? Probar Transfer Learning: en vez de entrenar desde cero, partir de una red ya entrenada con millones de imágenes (como ResNet o MobileNet) y adaptarla. Dicen que rinde mejor con pocos datos, y quiero comprobarlo yo mismo.
¿Te interesa el machine learning?
Escríbeme y conversamos — de redes neuronales, datos, o de por qué tu modelo no converge.
Conversemos →