Tutorial di apprendimento sul trasferimento di PyTorch con esempi

Che cos'è il trasferimento di apprendimento?

Trasferimento di apprendimento è una tecnica che consiste nell'utilizzare un modello addestrato per risolvere un'altra attività correlata. È un metodo di ricerca di Machine Learning che memorizza la conoscenza acquisita durante la risoluzione di un particolare problema e utilizza la stessa conoscenza per risolvere un altro problema diverso ma correlato. Ciò migliora l'efficienza riutilizzando le informazioni raccolte dall'attività appresa in precedenza.

È prassi comune utilizzare un altro peso del modello di rete per ridurre i tempi di addestramento perché sono necessari molti dati per addestrare un modello di rete. Per ridurre il tempo di allenamento, utilizzi altre reti e il loro peso e modifichi l'ultimo strato per risolvere il nostro problema. Il vantaggio è che puoi utilizzare un piccolo set di dati per addestrare l'ultimo livello.

Successivamente in questo tutorial di apprendimento di PyTorch Transfer, impareremo come utilizzare Transfer Learning con PyTorch.

Caricamento set di dati

Caricamento set di dati

Fonte: Alien vs. Predator Kaggle

Prima di iniziare a utilizzare Transfer Learning PyTorch, devi comprendere il set di dati che utilizzerai. In questo esempio di Transfer Learning PyTorch, classificherai un alieno e un predatore da quasi 700 immagini. Per questa tecnica non è necessaria una grande quantità di dati per l'addestramento. È possibile scaricare il set di dati da Kaggle: Alieno contro predatore.

Come utilizzare il Transfer Learning?

Ecco una procedura passo passo su come utilizzare Transfer Learning per Deep Learning con PyTorch:

Passaggio 1) Caricare i dati

Il primo passo è caricare i nostri dati e apportare alcune trasformazioni alle immagini in modo che corrispondano ai requisiti di rete.

Caricherai i dati da una cartella con torchvision.dataset. Il modulo eseguirà un'iterazione nella cartella per suddividere i dati per il training e la convalida. Il processo di trasformazione ritaglierà le immagini dal centro, eseguirà un capovolgimento orizzontale, le normalizzerà e infine le convertirà in tensore utilizzando il Deep Learning.

from __future__ import print_function, division
import os
import time
import torch
import torchvision
from torchvision import datasets, models, transforms
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt

data_dir = "alien_pred"
input_shape = 224
mean = [0.5, 0.5, 0.5]
std = [0.5, 0.5, 0.5]

#data transformation
data_transforms = {
   'train': transforms.Compose([
       transforms.CenterCrop(input_shape),
       transforms.ToTensor(),
       transforms.Normalize(mean, std)
   ]),
   'validation': transforms.Compose([
       transforms.CenterCrop(input_shape),
       transforms.ToTensor(),
       transforms.Normalize(mean, std)
   ]),
}

image_datasets = {
   x: datasets.ImageFolder(
       os.path.join(data_dir, x),
       transform=data_transforms[x]
   )
   for x in ['train', 'validation']
}

dataloaders = {
   x: torch.utils.data.DataLoader(
       image_datasets[x], batch_size=32,
       shuffle=True, num_workers=4
   )
   for x in ['train', 'validation']
}

dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'validation']}

print(dataset_sizes)
class_names = image_datasets['train'].classes

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

Visualizziamo il nostro set di dati per PyTorch Transfer Learning. Il processo di visualizzazione otterrà il successivo batch di immagini dai caricatori di dati e dalle etichette del treno e lo visualizzerà con matplot.

images, labels = next(iter(dataloaders['train']))

rows = 4
columns = 4
fig=plt.figure()
for i in range(16):
   fig.add_subplot(rows, columns, i+1)
   plt.title(class_names[labels[i]])
   img = images[i].numpy().transpose((1, 2, 0))
   img = std * img + mean
   plt.imshow(img)
plt.show()
Gruppo di immagini
Gruppo di immagini

Passaggio 2) Definire il modello

In questa Deep Learning processo, utilizzerai ResNet18 dal modulo torchvision.

Utilizzerai torchvision.models per caricare resnet18 con il peso pre-addestrato impostato su True. Successivamente, congelerai i livelli in modo che questi livelli non siano addestrabili. Modifichi anche l'ultimo livello con un livello Lineare per adattarlo alle nostre esigenze ovvero 2 classi. Utilizzi anche CrossEntropyLoss per la funzione di perdita multi-classe e per l'ottimizzatore utilizzerai SGD con un tasso di apprendimento di 0.0001 e uno slancio di 0.9 come mostrato nell'esempio di apprendimento di trasferimento PyTorch di seguito.

## Load the model based on VGG19
vgg_based = torchvision.models.vgg19(pretrained=True)

## freeze the layers
for param in vgg_based.parameters():
   param.requires_grad = False

# Modify the last layer
number_features = vgg_based.classifier[6].in_features
features = list(vgg_based.classifier.children())[:-1] # Remove last layer
features.extend([torch.nn.Linear(number_features, len(class_names))])
vgg_based.classifier = torch.nn.Sequential(*features)

vgg_based = vgg_based.to(device)

print(vgg_based)

criterion = torch.nn.CrossEntropyLoss()
optimizer_ft = optim.SGD(vgg_based.parameters(), lr=0.001, momentum=0.9)

La struttura del modello di output

VGG(
  (features): Sequential(
	(0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(1): ReLU(inplace)
	(2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(3): ReLU(inplace)
	(4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
	(5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(6): ReLU(inplace)
	(7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(8): ReLU(inplace)
	(9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
	(10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(11): ReLU(inplace)
	(12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(13): ReLU(inplace)
	(14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(15): ReLU(inplace)
	(16): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(17): ReLU(inplace)
	(18): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
	(19): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(20): ReLU(inplace)
	(21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(22): ReLU(inplace)
	(23): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(24): ReLU(inplace)
	(25): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(26): ReLU(inplace)
	(27): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
	(28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(29): ReLU(inplace)
	(30): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(31): ReLU(inplace)
	(32): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(33): ReLU(inplace)
	(34): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(35): ReLU(inplace)
	(36): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (classifier): Sequential(
	(0): Linear(in_features=25088, out_features=4096, bias=True)
	(1): ReLU(inplace)
	(2): Dropout(p=0.5)
	(3): Linear(in_features=4096, out_features=4096, bias=True)
	(4): ReLU(inplace)
	(5): Dropout(p=0.5)
	(6): Linear(in_features=4096, out_features=2, bias=True)
  )
)

Passaggio 3) Formazione e test del modello

Utilizzeremo alcune delle funzioni di Transfer Learning Esercitazione su PyTorch per aiutarci ad addestrare e valutare il nostro modello.

def train_model(model, criterion, optimizer, num_epochs=25):
   since = time.time()

   for epoch in range(num_epochs):
       print('Epoch {}/{}'.format(epoch, num_epochs - 1))
       print('-' * 10)

       #set model to trainable
       # model.train()

       train_loss = 0

       # Iterate over data.
       for i, data in enumerate(dataloaders['train']):
           inputs , labels = data
           inputs = inputs.to(device)
           labels = labels.to(device)

           optimizer.zero_grad()
          
           with torch.set_grad_enabled(True):
               outputs  = model(inputs)
               loss = criterion(outputs, labels)

           loss.backward()
           optimizer.step()

           train_loss += loss.item() * inputs.size(0)

           print('{} Loss: {:.4f}'.format(
               'train', train_loss / dataset_sizes['train']))
          
   time_elapsed = time.time() - since
   print('Training complete in {:.0f}m {:.0f}s'.format(
       time_elapsed // 60, time_elapsed % 60))

   return model

def visualize_model(model, num_images=6):
   was_training = model.training
   model.eval()
   images_so_far = 0
   fig = plt.figure()

   with torch.no_grad():
       for i, (inputs, labels) in enumerate(dataloaders['validation']):
           inputs = inputs.to(device)
           labels = labels.to(device)

           outputs = model(inputs)
           _, preds = torch.max(outputs, 1)

           for j in range(inputs.size()[0]):
               images_so_far += 1
               ax = plt.subplot(num_images//2, 2, images_so_far)
               ax.axis('off')
               ax.set_title('predicted: {} truth: {}'.format(class_names[preds[j]], class_names[labels[j]]))
               img = inputs.cpu().data[j].numpy().transpose((1, 2, 0))
               img = std * img + mean
               ax.imshow(img)

               if images_so_far == num_images:
                   model.train(mode=was_training)
                   return
       model.train(mode=was_training)

Infine, in questo esempio di Transfer Learning in PyTorch, iniziamo il nostro processo di addestramento con il numero di epoche impostato su 25 e valutiamo dopo il processo di addestramento. Ad ogni fase dell'addestramento, il modello prenderà l'input e prevederà l'output. Successivamente, la produzione prevista verrà utilizzata come criterio per calcolare le perdite. Successivamente verrà eseguito un calcolo delle perdite per calcolare il gradiente e infine calcolare i pesi e ottimizzare i parametri con autograd.

Nel modello di visualizzazione, la rete addestrata verrà testata con un batch di immagini per prevedere le etichette. Quindi verrà visualizzato con l'aiuto di matplotlib.

vgg_based = train_model(vgg_based, criterion, optimizer_ft, num_epochs=25)

visualize_model(vgg_based)

plt.show()

Passaggio 4) Risultati

Il risultato finale è che hai raggiunto una precisione del 92%.

Epoch 23/24
----------
train Loss: 0.0044
train Loss: 0.0078
train Loss: 0.0141
train Loss: 0.0221
train Loss: 0.0306
train Loss: 0.0336
train Loss: 0.0442
train Loss: 0.0482
train Loss: 0.0557
train Loss: 0.0643
train Loss: 0.0763
train Loss: 0.0779
train Loss: 0.0843
train Loss: 0.0910
train Loss: 0.0990
train Loss: 0.1063
train Loss: 0.1133
train Loss: 0.1220
train Loss: 0.1344
train Loss: 0.1382
train Loss: 0.1429
train Loss: 0.1500
Epoch 24/24
----------
train Loss: 0.0076
train Loss: 0.0115
train Loss: 0.0185
train Loss: 0.0277
train Loss: 0.0345
train Loss: 0.0420
train Loss: 0.0450
train Loss: 0.0490
train Loss: 0.0644
train Loss: 0.0755
train Loss: 0.0813
train Loss: 0.0868
train Loss: 0.0916
train Loss: 0.0980
train Loss: 0.1008
train Loss: 0.1101
train Loss: 0.1176
train Loss: 0.1282
train Loss: 0.1323
train Loss: 0.1397
train Loss: 0.1436
train Loss: 0.1467
Training complete in 2m 47s

Al termine quindi l'output del nostro modello verrà visualizzato con matplot di seguito:

Visualizzato con Matplot
Visualizzato con Matplot

Sommario

Quindi, riassumiamo tutto! Il primo fattore è che PyTorch è un framework di deep learning in crescita per principianti o per scopi di ricerca. Offre un tempo di calcolo elevato, Dynamic Graph, supporto GPU ed è completamente scritto in Python. Puoi definire facilmente il tuo modulo di rete ed eseguire il processo di formazione con una semplice iterazione. È chiaro che PyTorch è l'ideale per i principianti per scoprire l'apprendimento profondo e per i ricercatori professionisti è molto utile con tempi di calcolo più rapidi e anche l'utilissima funzione autograd per assistere il grafico dinamico.