Tarea 4: Clasificador de imágenes de ocho formas con EfficientNet.

Tarea 4: Clasificador de imágenes de ocho formas con EfficientNet.

Información de la Tarea

Descripción de la Tarea

Se deber realizar el clasificador de imagene de ocho formas utilizando transfering learning con EfficientNet, recortarla de la forma indicada, Aumentando las imagenes con el script Proporcionado.


Arquitectura

Del Script EfficientNet-B0.py Como se muestra en la imagen, recortamos para que solo nos quede con bloques de hasta el bloque 7. Modificamos la ultima capa para que tenga la forma adecuada para poder entrenar nuestra red.

inverted_residual_setting = [
bneck_conf(1, 3, 1, 32, 16, 1),
bneck_conf(6, 3, 2, 16, 24, 2),
bneck_conf(6, 5, 2, 24, 40, 2), #<- 8
# bneck_conf(6, 3, 2, 40, 80, 3),
# bneck_conf(6, 5, 1, 80, 112, 3),
# bneck_conf(6, 5, 2, 112, 192, 4),
bneck_conf(6, 3, 1, 40, 320, 1), # Block 7 adaptado (in:40 en lugar de 192)
]
last_chann

Utilizamos entonces el script para instanfciar el codigo y realizar el transfer.py De acuerdo a la estructura que modificamos.

# Cargo la red original
modelo1 = EfficientNet_B0.efficientnet_b0(weights=EfficientNet_B0.EfficientNet_B0_Weights.DEFAULT)
modelo1.eval()
modelo2 = EfficientNet_B0.efficientnet_b0_modif()
# Copiamos los pesos de la primera capa (de tres canales a uno)
w1 = modelo1.state_dict()['features.0.0.weight']
w2 = modelo2.state_dict()['features.0.0.weight']
# En EfficientNet_B0, la primera capa tiene 32 filtros
i = 0
while i < 32:
f1 = w1[i, 0]
f2 = w1[i, 1]
f3 = w1[i, 2]
g = 0.2989 * f1 + 0.5870 * f2 + 0.1140 * f3
w2[i, 0].copy_(g)
i += 1
# Copiamos el resto de los pesos que sean compatibles
k = 0
for i in modelo1.state_dict():
if i == 'features.0.0.weight':
continue
if i in modelo2.state_dict() and modelo1.state_dict()[i].shape == modelo2.state_dict()[i].shape:
p1 = modelo1.state_dict()[i]
p2 = modelo2.state_dict()[i]
p2.copy_(p1)
k += 1
modelo2.eval()
torch.save(modelo2.state_dict(), 'efficientnet_b0_recortada.pth')

Imprimi la red con torchinfo para visualizar que este correcta nuestra arquitectura.

Terminal window
=========================================================================================================
Layer (type:depth-idx) Output Shape Param #
=========================================================================================================
EfficientNet_modif [32, 8] --
├─Sequential: 1-1 [32, 1280, 28, 28] --
└─Conv2dNormActivation: 2-1 [32, 32, 112, 112] --
└─Conv2d: 3-1 [32, 32, 112, 112] 288
└─BatchNorm2d: 3-2 [32, 32, 112, 112] 64
└─SiLU: 3-3 [32, 32, 112, 112] --
└─Sequential: 2-2 [32, 16, 112, 112] --
└─MBConv: 3-4 [32, 16, 112, 112] 1,448
└─Sequential: 2-3 [32, 24, 56, 56] --
└─MBConv: 3-5 [32, 24, 56, 56] 6,004
└─MBConv: 3-6 [32, 24, 56, 56] 10,710
└─Sequential: 2-4 [32, 40, 28, 28] --
└─MBConv: 3-7 [32, 40, 28, 28] 15,350
└─MBConv: 3-8 [32, 40, 28, 28] 31,290
└─Sequential: 2-5 [32, 320, 28, 28] --
└─MBConv: 3-9 [32, 320, 28, 28] 95,210
└─Conv2dNormActivation: 2-6 [32, 1280, 28, 28] --
└─Conv2d: 3-10 [32, 1280, 28, 28] 409,600
└─BatchNorm2d: 3-11 [32, 1280, 28, 28] 2,560
└─SiLU: 3-12 [32, 1280, 28, 28] --
├─AdaptiveAvgPool2d: 1-2 [32, 1280, 1, 1] --
├─Sequential: 1-3 [32, 8] --
└─Dropout: 2-7 [32, 1280] --
└─Linear: 2-8 [32, 8] 10,248
=========================================================================================================
Total params: 582,772
Trainable params: 582,772
Non-trainable params: 0
Total mult-adds (Units.GIGABYTES): 15.91
=========================================================================================================
Input size (MB): 6.42
Forward/backward pass size (MB): 3172.97
Params size (MB): 2.33
Estimated Total Size (MB): 3181.73
=========================================================================================================

Data Augmentation

Para el entrenamiento de la red, se partió de una base de datos original compuesta por 480 imágenes distribuidas uniformemente en 8 clases (60 imágenes por clase).

Con el fin de evitar el problema de Fuga de Datos (Data Leakage) y asegurar una validación objetiva del modelo, el particionamiento de los datos se realizó antes de aplicar cualquier técnica de aumento, utilizando una proporción estándar de 80/20:

Conjunto de entrenamiento robusto de 77,184 imágenes y un conjunto de prueba puro de 96 imágenes.Los datos se estructuraron automáticamente en un formato de directorios por clases (ImageFolder) para facilitar su integración directa con los DataLoaders de PyTorch.

Entrenamiento

Se congelaron las capas base de la red (requires_grad = False). Solamente se descongelaron las últimas tres capas (el nuevo Bloque 7, la convolución final de proyección y el clasificador lineal de 8 clases).

ParámetroValor Configurado
OptimizadorSGD con Nesterov
Tasa de Aprendizaje0.001
Momentum0.95
Función de PérdidaCrossEntropyLoss
Tamaño de Lote (Batch)32
Épocas (Epochs)10

Resultados

Se obtuvo un tiempo aprox de 10min en una Macbook air M4-16gb utilizando mps para las 10 epocas.

Guardamos el mejor modelo en cada iteracion si disminuía el gap entre train y test loss.

Época Precisión (Train) Loss (Train) Precisión (Test) Loss (Test)
1 98.4% 0.053290 100.0% 0.004266
2 99.9% 0.006035 100.0% 0.000834
3 99.9% 0.003582 100.0% 0.001451
4 100.0% 0.002224 100.0% 0.000762
5 100.0% 0.001677 100.0% 0.000673
6 100.0% 0.001527 100.0% 0.001297
7 100.0% 0.001317 100.0% 0.000828
8 100.0% 0.001054 100.0% 0.000385
9 100.0% 0.000918 100.0% 0.000261
10 100.0% 0.000738 100.0% 0.000363
Gráfica de Resultados de Entrenamiento

Conclusión

La reducción estructural de EfficientNet-B0 (~582k parámetros) y el fine-tuning con prevención de data leakage resultaron en un modelo altamente eficiente. Se alcanzó un 100% de precisión en prueba (Loss 0.000261) sin sobreajuste, demostrando que es posible minimizar el costo computacional sin sacrificar rendimiento.