Reporte de modelo EfficientNet_B3

Modelo de Clasificación de Nubosidad por Nivel de Octas

EfficientNet B3

OBJETIVO

Se desarrolla un modelo diseñado para automatizar la clasificación del nivel de nubosidad en imágenes astronómicas, utilizando redes neuronales profundas. El objetivo principal es estimar el nivel de octas (de 0 a 8), lo cual permite optimizar la observación astronómica en la Estación Astronómica de Río Grande, facilitando la selección de imágenes útiles para análisis científicos.

Para lograr una clasificación precisa, se utilizará un modelo preentrenado EfficientNet B3, adaptado mediante técnicas de transferencia de aprendizaje. Este enfoque permite aprovechar el conocimiento previo del modelo en tareas de visión por computadora, acelerando el entrenamiento y mejorando la generalización en el dominio específico de imágenes astronómicas.

ALCANCE

El modelo desarrollado, entrenado y evaluado debera clasificar imágenes astronómicas según el nivel de nubosidad en octas (de 0 a 8). El modelo se enfoca en imágenes capturadas por la Estación Astronómica de Río Grande, considerando tanto condiciones de iluminación clara como oscura.

El alcance incluye:

  • Procesamiento y organización del dataset, con imágenes previamente etiquetadas por nivel de octas y tipo de iluminación.

  • Entrenamiento de un modelo EfficientNet B3 preentrenado, utilizando técnicas de transferencia de aprendizaje para adaptarlo al dominio específico de imágenes astronómicas.

  • Aplicación de técnicas de mejora del entrenamiento, como normalización de clases, early stopping y visualización de errores.

  • Evaluación del modelo mediante métricas como precisión, recall, F1-score y matriz de confusión.

  • Generación de un sistema automatizado capaz de clasificar nuevas imágenes de forma eficiente y confiable.

PROCEDIMIENTO DE DISEÑO DE MODELO

Preparación del entorno

El modelo se configuró un entorno de trabajo basado en Python y la biblioteca PyTorch. Se incorporaron librerías esenciales para el procesamiento de datos (NumPy, Pandas), visualización (Matplotlib, Seaborn), manipulación de imágenes (PIL), y aprendizaje profundo (torch, torchvision). Además, se utilizaron herramientas de evaluación como scikit-learn para el cálculo de métricas de rendimiento y balanceo de clases. Esta configuración permite un flujo de trabajo eficiente para el entrenamiento, validación y análisis del modelo.

Verificación e Instalación de GPU

Para acelerar el entrenamiento del modelo de clasificación de imágenes, se verificó la disponibilidad de una GPU en el entorno de ejecución. El uso de GPU permite realizar cálculos intensivos de forma más eficiente, reduciendo significativamente los tiempos de entrenamiento. Se utilizó la biblioteca PyTorch, que ofrece soporte nativo para CUDA y se confirmó la correcta instalación mediante comandos como torch.cuda.is_available(). Esta configuración garantiza un entorno óptimo para el procesamiento de imágenes a gran escala.

TextoEl contenido generado por IA puede ser incorrecto.

Ruta del Dataset

Las imágenes utilizadas para el entrenamiento y validación del modelo se encuentran organizadas en carpetas según el nivel de octas y el tipo de iluminación (clara u oscura). Estas carpetas están almacenadas localmente en una ruta específica del sistema, por ejemplo:

TextoEl contenido generado por IA puede ser incorrecto.

Cada subcarpeta dentro de esta ruta representa una clase correspondiente a un nivel de nubosidad, desde octa_0 hasta octa_8, permitiendo una carga estructurada y eficiente de los datos mediante PyTorch. Esta organización facilita el uso de ImageFolder o la creación de datasets personalizados para el entrenamiento supervisado del modelo.

Carga de Imágenes y Etiquetas

Para preparar el conjunto de datos, se recorren las carpetas almacenadas en la ruta base, donde cada carpeta representa un nivel de nubosidad en octas (por ejemplo, imagenes_clara_octa_0, imagenes_oscura_octa_5, etc.). Se extraen las rutas de las imágenes válidas (.jpg, .jpeg, .png) y se asigna la etiqueta correspondiente en función del número de octas indicado en el nombre de la carpeta.

Este proceso permite construir dos listas: una con las rutas de las imágenes (image_paths) y otra con sus respectivas etiquetas (octa_labels), que luego se utilizan para dividir el dataset y alimentar el modelo de clasificación.

Visualización del Balanceo de Clases

Luego se genera un gráfico para analizar la distribución de imágenes por nivel de octas en el dataset. Primero, se utiliza sns.countplot() para contar cuántas imágenes hay en cada clase (de 0 a 8 octas) y representarlas en un gráfico de barras. Luego se configuran el título y las etiquetas de los ejes para dar claridad a la visualización. Finalmente, el gráfico se guarda como un archivo PNG (distribucion_clases_octas.png) para su inclusión en el informe. Esta representación permite identificar si existe un desbalance entre las clases, lo cual es clave para aplicar técnicas de normalización durante el entrenamiento.

El histograma muestra la cantidad de imágenes disponibles para cada nivel de octas (de 0 a 8). Se puede observar lo siguiente:

  • Las clases 1 y 8 presentan la mayor cantidad de imágenes, superando las 450, lo que indica una alta representatividad.

  • Las clases 2, 4 y 5 son las menos representadas, con valores cercanos a 220-280 imágenes, lo que evidencia un desbalance en el dataset.

  • Las demás clases (0, 3, 6, 7) tienen una distribución intermedia, entre 350 y 420 imágenes.

Este desbalance afectaría el rendimiento del modelo, favoreciendo las clases más frecuentes. Por lo que más adelante será necesario aplicar técnicas como normalización de clases o ponderación de pérdida para mitigar el sesgo y mejorar la precisión en todas las categorías.

División del Dataset en Entrenamiento y Validación

Realizamos la separación del conjunto de datos en dos partes, 80% para entrenamiento y 20% para validación. Se utiliza la función train_test_split de scikit-learn, que divide las listas de rutas de imágenes (image_paths) y sus etiquetas (octa_labels) en subconjuntos. Se aplica el parámetro stratify=octa_labels para garantizar que la proporción de clases se mantenga en ambos conjuntos, evitando desbalances entre entrenamiento y validación. Además, se fija random_state=42 para asegurar reproducibilidad en la división.

TextoEl contenido generado por IA puede ser incorrecto.

Cálculo de Pesos de Clase

El cálculo de los pesos de clase se realiza para compensar el desbalance observado en la distribución de imágenes por nivel de octas. Se utiliza la función compute_class_weight de scikit-learn, que asigna un peso mayor a las clases menos representadas y un peso menor a las clases con más imágenes. Estos pesos se aplican durante el entrenamiento del modelo en la función de pérdida, con el objetivo de reducir el sesgo hacia las clases mayoritarias y mejorar la precisión global del sistema.

Detección de Clases Minoritarias

La distribución de imágenes por nivel de octas para identificar las clases menos representadas en el dataset. Primero, se calcula la cantidad de imágenes por clase utilizando value_counts() de pandas. Luego, se determina el promedio de imágenes entre todas las clases y se seleccionan aquellas que tienen un número inferior a este promedio. Finalmente, se imprime la lista de clases minoritarias detectadas. Este análisis es útil para aplicar estrategias de balanceo, como el uso de pesos de clase o técnicas de aumento de datos, con el fin de mejorar la equidad en el entrenamiento del modelo.

Creación del Dataset Personalizado

Se define la clase OctaDataset, que hereda de torch.utils.data.Dataset y permite gestionar las imágenes y etiquetas de forma flexible.

  • image_paths y labels: listas con las rutas de las imágenes y sus etiquetas.

  • img_width y img_height: dimensiones a las que se redimensionarán las imágenes.

  • augment: indica si se aplicarán técnicas de aumento de datos.

  • minority_classes: lista de clases minoritarias para aplicar estrategias de balanceo.

  • oversample_factor: factor para replicar imágenes de clases menos representadas.

Este diseño facilita la incorporación de transformaciones, el manejo de desbalance en las clases y la preparación de los datos para el entrenamiento del modelo.

TextoEl contenido generado por IA puede ser incorrecto.

Oversampling Dinámico

Si se detectan clases minoritarias, se recorren todas las etiquetas y por cada imagen perteneciente a una clase poco representada, se duplican sus entradas en el dataset según el valor definido en oversample_factor. Esto significa que las imágenes de clases minoritarias se agregan varias veces a las listas image_paths y labels, aumentando su presencia en el conjunto de datos. Esta técnica ayuda a equilibrar la distribución de clases y mejora la capacidad del modelo para aprender patrones en categorías menos frecuentes.

Aplicación de Transformaciones

Se define un conjunto de transformaciones para preparar las imágenes antes de ser utilizadas por el modelo. Se utiliza torchvision.transforms para aplicar dos configuraciones:

  • Modo con aumento de datos (augment=True): Incluye operaciones como redimensionamiento, volteo horizontal aleatorio, rotación, ajuste de brillo y contraste, transformaciones afines, recorte aleatorio, desenfoque gaussiano y conversión a tensor. Estas técnicas aumentan la variabilidad del dataset, mejorando la capacidad de generalización del modelo.

  • Modo sin aumento (augment=False): Aplica únicamente el redimensionamiento, conversión a tensor y normalización.

En ambos casos, se utiliza la normalización con los valores de mean y std predefinidos para modelos entrenados en ImageNet, lo que asegura compatibilidad con arquitecturas como EfficientNet B3.

Métodos __len__ y __getitem__

En la clase OctaDataset, se implementan dos métodos fundamentales para el funcionamiento del dataset personalizado:

  • __len__: Devuelve el número total de imágenes disponibles en el dataset, utilizando la longitud de la lista image_paths. Esto permite que PyTorch conozca el tamaño del conjunto de datos.

  • __getitem__: Recupera una imagen y su etiqueta correspondiente según el índice idx.

El proceso incluye:

  • Obtener la ruta de la imagen y su etiqueta.

  • Abrir la imagen con PIL y convertirla a formato RGB.

  • Aplicar las transformaciones definidas previamente (aumento de datos o normalización).

  • Manejar errores: si ocurre un problema al cargar la imagen, se imprime un mensaje y se devuelve un tensor vacío con las dimensiones esperadas.

Este diseño asegura que cada lote de datos se procese correctamente, incluso si alguna imagen presenta inconvenientes, evitando interrupciones en el entrenamiento.

Configuración de Parámetros y Creación de DataLoaders

En este metodo se definen los parámetros principales para el entrenamiento del modelo:

  • img_width, img_height: dimensiones a las que se redimensionarán las imágenes (224 × 224 píxeles), compatibles con arquitecturas como EfficientNet.

  • batch_size: tamaño del lote establecido en 64, lo que permite procesar varias imágenes en paralelo para optimizar el rendimiento.

Luego, se crean dos instancias del dataset personalizado:

  • train_dataset: incluye aumento de datos (augment=True) y aplica oversampling para clases minoritarias con un factor de 3.

  • val_dataset: no aplica aumento de datos, asegurando una evaluación consistente.

Finalmente, se construyen los DataLoaders:

  • train_loader: carga los datos de entrenamiento en lotes, con barajado aleatorio (shuffle=True) para mejorar la generalización.

  • val_loader: carga los datos de validación sin barajado (shuffle=False) para mantener la consistencia en la evaluación.

Esta configuración garantiza un flujo eficiente y balanceado para el entrenamiento y validación del modelo.

Definición del Modelo con Fine-Tuning Completo

El código inicializa el modelo EfficientNet B3 preentrenado en el conjunto de datos ImageNet utilizando la función models.efficientnet_b3(pretrained=True) de torchvision. Las capas del modelo serán entrenadas, permitiendo adaptar completamente la arquitectura al dominio específico de imágenes astronómicas. Esta estrategia de fine-tuning completo es útil cuando se dispone de un dataset suficientemente grande y se busca maximizar la precisión, aunque implica un mayor costo computacional.

TextoEl contenido generado por IA puede ser incorrecto.

Ajuste del Clasificador para el Número de Clases

El código modifica la capa final del modelo EfficientNet B3 para adaptarla al problema de clasificación de nubosidad en 9 clases (niveles de octas de 0 a 8). Esto se logra reemplazando la última capa totalmente conectada (nn.Linear) por una nueva que recibe el mismo número de características de entrada (in_features) y genera 9 salidas.

TextoEl contenido generado por IA puede ser incorrecto.

Función de Pérdida, Optimizador y Scheduler

Para abordar el desbalance de clases y mejorar la robustez del entrenamiento, se implementa la función de pérdida Función de Pérdida, que extiende la pérdida por entropía cruzada. Esta técnica reduce el impacto de las clases mayoritarias y pone mayor énfasis en las clases minoritarias mediante dos parámetros:

  • alpha: factor de ponderación para ajustar la importancia global.

  • gamma: controla cuánto se penalizan las predicciones fáciles, enfocando el aprendizaje en casos difíciles.

La función calcula la pérdida base con CrossEntropyLoss (incluyendo los pesos de clase) y aplica la fórmula de Focal Loss para obtener el valor final.

También:

  • Se utiliza el optimizador Adam con una tasa de aprendizaje inicial de 1e-4 y weight_decay para regularización.

  • Se incorpora un scheduler ReduceLROnPlateau, que reduce la tasa de aprendizaje automáticamente cuando la métrica de validación deja de mejorar, evitando estancamientos en el entrenamiento.

Esta configuración busca maximizar la precisión del modelo y garantizar una convergencia estable.

Entrenamiento con Early Stopping

En el código se implementa el ciclo de entrenamiento del modelo con la técnica de Early Stopping para evitar el sobreajuste. Se establecen los siguientes parámetros:

  • num_epochs \= 100: número máximo de épocas.

  • patience \= 8: número de épocas consecutivas sin mejora en la pérdida de validación antes de detener el entrenamiento.

  • best_val_loss: inicializado con infinito para registrar la mejor pérdida alcanzada.

  • best_model_wts: almacena los pesos del modelo cuando se obtiene la mejor validación.

  • epochs_no_improve: contador de épocas sin mejora.

Durante cada época:

  1. El modelo se pone en modo entrenamiento (model.train()).

  2. Se inicializan acumuladores para pérdida, aciertos y total de muestras.

  3. Se recorren los lotes del train_loader, aplicando:

  4. Carga de imágenes y etiquetas en el dispositivo (GPU).

  5. Cálculo de predicciones y pérdida con la función definida (criterion).

  6. Retropropagación (loss.backward()) y actualización de parámetros (optimizer.step()).

  7. Se acumula la pérdida y se calcula la precisión en entrenamiento.

  8. Se registran las métricas en listas para análisis posterior.

Este enfoque permite monitorear el rendimiento y detener el entrenamiento cuando no hay mejoras significativas, optimizando el tiempo y evitando sobreajuste.

Validación del Modelo y Registro de Métricas

Después de cada época de entrenamiento, el modelo se evalúa en el conjunto de validación para medir su rendimiento. El proceso incluye:

  1. Modo evaluación: Se activa con model.eval() para deshabilitar operaciones como dropout y batch normalization en modo entrenamiento.

  2. Desactivación del cálculo de gradientes: Se utiliza torch.no_grad() para reducir el consumo de memoria y acelerar la inferencia.

  3. Cálculo de pérdida y precisión:

  4. Se recorren los lotes del val_loader.

  5. Se calculan las predicciones y la pérdida con la misma función definida (criterion).

  6. Se acumulan los valores para obtener la pérdida promedio (val_loss) y la precisión (val_acc).

  7. Registro histórico: Se guardan las métricas en listas para análisis posterior (val_loss_history, val_acc_history). Archivo historial_entrenamiento.csv

  8. Ajuste dinámico de la tasa de aprendizaje: Se llama al scheduler ReduceLROnPlateau para reducir el learning rate si la pérdida de validación no mejora.

  9. Impresión de resultados por época: Se muestra la pérdida y precisión tanto en entrenamiento como en validación, permitiendo monitorear el progreso.

Este enfoque asegura un seguimiento detallado del rendimiento del modelo y facilita la aplicación de Early Stopping cuando no se observan mejoras significativas.

TextoEl contenido generado por IA puede ser incorrecto.

Luego en el código se implementa la lógica completa de Early Stopping para detener el entrenamiento cuando no se observa mejora en la pérdida de validación durante un número determinado de épocas (definido por patience). El flujo es el siguiente:

  1. Comparación de pérdidas: Si la pérdida de validación (val_loss) es menor que la mejor registrada (best_val_loss), se actualizan:

  2. best_val_loss con el nuevo valor.

  3. best_model_wts con los pesos actuales del modelo.

  4. Se guarda el modelo en disco como mejor_modelo_efficientnet_finetuning.pth.

  5. Se reinicia el contador epochs_no_improve a cero.

  6. Incremento del contador: Si no hay mejora, se incrementa epochs_no_improve.

  7. Activación de Early Stopping: Cuando epochs_no_improve alcanza el valor de patience, se imprime el mensaje "Early stopping activado" y se interrumpe el ciclo de entrenamiento.

  8. Restauración del mejor modelo: Al finalizar, se cargan los pesos del mejor modelo registrado para garantizar que se utilice la versión más precisa.

Este mecanismo optimiza el tiempo de entrenamiento y evita el sobreajuste, asegurando que el modelo final sea el más eficiente según la métrica de validación.

Registro del Historial de Entrenamiento

En el código se crea un DataFrame con las métricas registradas durante el entrenamiento y validación del modelo, incluyendo:

  • loss: pérdida promedio en el conjunto de entrenamiento.

  • val_loss: pérdida promedio en el conjunto de validación.

  • accuracy: precisión en entrenamiento.

  • val_accuracy: precisión en validación.

Estas métricas se almacenan en listas durante el ciclo de entrenamiento y luego se consolidan en un archivo CSV llamado historial_entrenamiento.csv. Este registro permite realizar análisis posteriores, generar visualizaciones como curvas de pérdida y precisión, también documentar el rendimiento del modelo en el informe

Imagen que contiene texto, periódicoEl contenido generado por IA puede ser incorrecto.

TextoEl contenido generado por IA puede ser incorrecto.

Evaluación del Modelo de Clasificación de Nubosidad por Nivel de Octa

En el siguiente parte del código está diseñado para evaluar el rendimiento de un modelo. Primero, se pone el modelo en modo de evaluación para desactivar funciones como el dropout, que solo se usan durante el entrenamiento. Luego se recorren las imágenes del conjunto de validación sin calcular gradientes, lo que ahorra recursos.

Para cada lote de imágenes, se obtienen las predicciones del modelo y se comparan con las etiquetas verdaderas. Las predicciones y las etiquetas se guardan en listas para analizarlas después.

Una vez que se tienen todas las predicciones, se genera una matriz de confusión que muestra cuántas veces el modelo acertó o se equivocó en cada clase. Esta matriz se gráfica y se guarda como una imagen en formato PNG.

Después, se calculan métricas de evaluación por clase: precisión, recall y F1-score. También se calcula la precisión global del modelo. Todos estos resultados se guardan en un archivo CSV, donde cada fila representa una clase de octa y sus métricas, y al final se agrega una fila con la precisión global.

TextoEl contenido generado por IA puede ser incorrecto.

CalendarioEl contenido generado por IA puede ser incorrecto.

TablaEl contenido generado por IA puede ser incorrecto.

Rendimiento global

  • Exactitud global: 70.28%. El modelo acierta aproximadamente 7 de cada 10 imágenes, lo cual es aceptable, pero indica espacio para mejora, especialmente en clases intermedias.

Observaciones de la matriz de confusión

  • Clases bien clasificadas:

  • Clase 0 (octa 0): 67 aciertos, 10 errores → muy buen desempeño.

  • Clase 8 (octa 8): 78 aciertos, 19 errores → también muy sólido.
    Estas clases extremas (cielo despejado y cielo totalmente cubierto) son más fáciles de identificar.

  • Clases con confusión alta:

  • Clase 6: Predicciones dispersas (26 como clase 5, 16 como clase 7).

  • Clase 4 y 5: Se confunden entre sí y con clase 6.
    Esto indica que el modelo tiene dificultad para diferenciar niveles intermedios de nubosidad.

  • Patrón general:
    La diagonal es dominante, pero hay desplazamientos hacia clases vecinas, lo que sugiere que el modelo entiende la progresión de nubosidad, aunque no con precisión perfecta.

Métricas por clase

  • Mejor precisión: Clase 8 (0.90) y clase 0 (0.89).

  • Peor precisión: Clase 5 (0.50) y clase 7 (0.61).

  • Mejor recall: Clase 0 (0.87) y clase 3 (0.78).

  • Peor recall: Clase 6 (0.42), lo que confirma que el modelo falla en detectar correctamente esta clase.

  • F1-score más bajo: Clase 5 (0.58) y clase 6 (0.52).
    Esto indica que las clases intermedias son el punto débil del modelo.

Interpretación

  • El modelo es robusto en extremos (cielos despejados y cubiertos), pero débil en nubosidad parcial, donde las diferencias visuales son más sutiles.

  • La confusión entre clases consecutivas sugiere que el modelo capta la tendencia, pero necesita más discriminación en niveles medios.

TextoEl contenido generado por IA puede ser incorrecto.

Imagen que contiene AplicaciónEl contenido generado por IA puede ser incorrecto.

Las imágenes muestran errores de clasificación del modelo en niveles intermedios de nubosidad. En todos los casos, la predicción está cerca del valor real, lo que indica que el modelo entiende la tendencia general, pero falla en la discriminación precisa. Por ejemplo, cuando la etiqueta real es 6, el modelo predice 5; cuando es 1, predice 2; y cuando es 7, predice 6. Esto sugiere que el error más común es una desviación de ±1 nivel.

Se observa que las imágenes con iluminación artificial (bordes amarillos o naranjas, típicos de tomas nocturnas) y las que presentan nubes difusas o mezcladas con claros son las más problemáticas. Las condiciones de luz y la textura irregular de las nubes parecen influir en la confusión del modelo. No hay errores extremos (como confundir 0 con 8), lo que confirma que el modelo tiene una noción correcta de la progresión de nubosidad.

Grafica de aprendizaje de Octas

Gráfico, Gráfico de líneasEl contenido generado por IA puede ser incorrecto.

Gráfico, Gráfico de líneasEl contenido generado por IA puede ser incorrecto.

Pérdida (Loss) por época

  • Train Loss: Disminuye de forma continua desde \~1.3 hasta casi 0.05, lo que indica que el modelo aprende bien en entrenamiento.

  • Validation Loss: Baja rápido al inicio (de \~0.9 a \~0.35 en las primeras 4 épocas), pero luego se estabiliza y oscila entre 0.25 y 0.35.

  • Interpretación:

  • El hecho de que la pérdida de validación deje de mejorar mientras la de entrenamiento sigue bajando indica sobreajuste a partir de la época 6-7.

  • El modelo memoriza el conjunto de entrenamiento, pero no mejora en generalización.

Exactitud (Accuracy) por época

  • Train Accuracy: Sube de \~0.32 a \~0.88, mostrando un aprendizaje fuerte.

  • Validation Accuracy: Mejora rápido al inicio (de \~0.45 a \~0.68 en las primeras 6 épocas), pero luego se estanca cerca de 0.70.

  • Interpretación:

  • El estancamiento en validación confirma el sobreajuste.

  • La brecha entre entrenamiento (0.88) y validación (0.70) al final es significativa.

Resultado - Conclusión

  • El modelo aprende bien, pero no generaliza óptimamente.

  • El sobreajuste comienza alrededor de la época 6-7.

  • Se sugiere realizar entrenamiento con otra versión de modelo pre-entrenado

alt text