El aprendizaje por transferencia es una técnica poderosa en el campo del aprendizaje profundo que permite utilizar modelos preentrenados en grandes conjuntos de datos para resolver problemas específicos con menos datos y tiempo de entrenamiento. En este módulo, aprenderemos cómo aplicar el aprendizaje por transferencia utilizando PyTorch.

¿Qué es el Aprendizaje por Transferencia?

El aprendizaje por transferencia implica tomar un modelo que ha sido preentrenado en una tarea grande y general (como la clasificación de imágenes en el conjunto de datos ImageNet) y adaptarlo a una tarea específica. Los beneficios incluyen:

  • Reducción del tiempo de entrenamiento: Aprovechamos el conocimiento ya adquirido por el modelo.
  • Mejora del rendimiento: Los modelos preentrenados suelen tener una mejor capacidad de generalización.
  • Menor necesidad de datos: Podemos obtener buenos resultados con menos datos de entrenamiento.

Pasos para Implementar el Aprendizaje por Transferencia

  1. Seleccionar un modelo preentrenado: PyTorch proporciona varios modelos preentrenados a través de la biblioteca torchvision.models.
  2. Modificar la última capa: Adaptar la última capa del modelo para que coincida con el número de clases de nuestro problema específico.
  3. Congelar capas: Opcionalmente, congelar algunas capas del modelo para evitar que se actualicen durante el entrenamiento.
  4. Entrenar el modelo: Entrenar el modelo en nuestro conjunto de datos específico.

Ejemplo Práctico: Clasificación de Imágenes con ResNet

Paso 1: Importar Librerías y Cargar el Modelo Preentrenado

import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, models, transforms

# Configuración del dispositivo
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# Cargar el modelo preentrenado ResNet18
model = models.resnet18(pretrained=True)
model = model.to(device)

Paso 2: Modificar la Última Capa

La red ResNet18 tiene una capa totalmente conectada (fc) al final que produce 1000 salidas (para las 1000 clases de ImageNet). Necesitamos modificar esta capa para que coincida con el número de clases de nuestro problema.

num_classes = 10  # Ejemplo: 10 clases
model.fc = nn.Linear(model.fc.in_features, num_classes)
model = model.to(device)

Paso 3: Congelar Capas (Opcional)

Podemos congelar las capas iniciales del modelo para evitar que se actualicen durante el entrenamiento. Esto es útil si queremos aprovechar al máximo el conocimiento preentrenado.

for param in model.parameters():
    param.requires_grad = False

# Solo entrenar la última capa
for param in model.fc.parameters():
    param.requires_grad = True

Paso 4: Preparar el Conjunto de Datos y el Bucle de Entrenamiento

# Transformaciones de datos
data_transforms = {
    'train': transforms.Compose([
        transforms.RandomResizedCrop(224),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
    'val': transforms.Compose([
        transforms.Resize(256),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
}

data_dir = 'data/hymenoptera_data'
image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x), data_transforms[x]) for x in ['train', 'val']}
dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=4, shuffle=True, num_workers=4) for x in ['train', 'val']}
dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']}
class_names = image_datasets['train'].classes

# Definir la función de pérdida y el optimizador
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.fc.parameters(), lr=0.001, momentum=0.9)

Paso 5: Entrenar y Evaluar el Modelo

def train_model(model, criterion, optimizer, num_epochs=25):
    for epoch in range(num_epochs):
        print(f'Epoch {epoch}/{num_epochs - 1}')
        print('-' * 10)

        for phase in ['train', 'val']:
            if phase == 'train':
                model.train()
            else:
                model.eval()

            running_loss = 0.0
            running_corrects = 0

            for inputs, labels in dataloaders[phase]:
                inputs = inputs.to(device)
                labels = labels.to(device)

                optimizer.zero_grad()

                with torch.set_grad_enabled(phase == 'train'):
                    outputs = model(inputs)
                    _, preds = torch.max(outputs, 1)
                    loss = criterion(outputs, labels)

                    if phase == 'train':
                        loss.backward()
                        optimizer.step()

                running_loss += loss.item() * inputs.size(0)
                running_corrects += torch.sum(preds == labels.data)

            epoch_loss = running_loss / dataset_sizes[phase]
            epoch_acc = running_corrects.double() / dataset_sizes[phase]

            print(f'{phase} Loss: {epoch_loss:.4f} Acc: {epoch_acc:.4f}')

    return model

model = train_model(model, criterion, optimizer, num_epochs=25)

Ejercicio Práctico

Ejercicio 1: Aplicar Aprendizaje por Transferencia con VGG16

  1. Cargar el modelo VGG16 preentrenado.
  2. Modificar la última capa para un problema de clasificación con 5 clases.
  3. Congelar todas las capas excepto la última.
  4. Entrenar el modelo en un conjunto de datos de su elección.

Solución

# Cargar el modelo preentrenado VGG16
model_vgg = models.vgg16(pretrained=True)
model_vgg = model_vgg.to(device)

# Modificar la última capa
model_vgg.classifier[6] = nn.Linear(model_vgg.classifier[6].in_features, 5)
model_vgg = model_vgg.to(device)

# Congelar todas las capas excepto la última
for param in model_vgg.features.parameters():
    param.requires_grad = False

# Definir la función de pérdida y el optimizador
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model_vgg.classifier[6].parameters(), lr=0.001, momentum=0.9)

# Entrenar el modelo
model_vgg = train_model(model_vgg, criterion, optimizer, num_epochs=25)

Conclusión

En este módulo, hemos aprendido cómo aplicar el aprendizaje por transferencia utilizando modelos preentrenados en PyTorch. Esta técnica nos permite aprovechar modelos robustos y bien entrenados para resolver problemas específicos de manera eficiente. Hemos cubierto los pasos clave, desde la selección y modificación del modelo hasta el entrenamiento y evaluación. Con esta base, puedes explorar y aplicar el aprendizaje por transferencia a una variedad de problemas en el campo del aprendizaje profundo.

© Copyright 2024. Todos los derechos reservados