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
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()
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:
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.