Tutorial de învățare PyTorch Transfer cu exemple

Ce este Transfer Learning?

Transferul învățării este o tehnică de utilizare a unui model antrenat pentru a rezolva o altă sarcină conexe. Este o metodă de cercetare de învățare automată care stochează cunoștințele acumulate în timpul rezolvării unei anumite probleme și utilizează aceleași cunoștințe pentru a rezolva o altă problemă diferită, dar conexă. Acest lucru îmbunătățește eficiența prin reutilizarea informațiilor adunate din sarcina învățată anterior.

Este popular să folosiți alte modele de greutate pentru a reduce timpul de antrenament, deoarece aveți nevoie de multe date pentru a antrena un model de rețea. Pentru a reduce timpul de antrenament, utilizați alte rețele și greutatea acesteia și modificați ultimul strat pentru a ne rezolva problema. Avantajul este că puteți folosi un set de date mic pentru a antrena ultimul strat.

În continuare, în acest tutorial de învățare PyTorch Transfer, vom învăța cum să folosim Transfer Learning cu PyTorch.

Se încarcă setul de date

Se încarcă setul de date

Sursa: Alien vs Predator Kaggle

Înainte de a începe să utilizați Transfer Learning PyTorch, trebuie să înțelegeți setul de date pe care îl veți utiliza. În acest exemplu de Transfer Learning PyTorch, veți clasifica un Alien și un Predator din aproape 700 de imagini. Pentru această tehnică, nu aveți nevoie de o cantitate mare de date pentru antrenament. Puteți descărca setul de date de la Kaggle: Alien vs Predator.

Cum se utilizează Transfer Learning?

Iată un proces pas cu pas despre cum să utilizați Transfer Learning pentru Deep Learning cu PyTorch:

Pasul 1) Încărcați datele

Primul pas este să ne încărcăm datele și să facem unele transformări în imagini, astfel încât acestea să corespundă cerințelor rețelei.

Veți încărca datele dintr-un folder cu torchvision.dataset. Modulul va itera în folder pentru a împărți datele pentru tren și validare. Procesul de transformare va decupa imaginile din centru, va efectua o răsturnare orizontală, va normaliza și, în final, o va converti în tensor folosind 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")

Să vizualizăm setul nostru de date pentru PyTorch Transfer Learning. Procesul de vizualizare va obține următorul lot de imagini de la încărcătorul de date și etichetele trenului și îl va afișa cu 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()
Lot de imagini
Lot de imagini

Pasul 2) Definiți modelul

În acest Invatare profunda proces, veți folosi ResNet18 din modulul Torchvision.

Veți folosi torchvision.models pentru a încărca resnet18 cu greutatea pre-antrenată setată să fie True. După aceea, veți îngheța straturile, astfel încât aceste straturi să nu poată fi antrenate. De asemenea, modificați ultimul strat cu un strat Linear pentru a se potrivi nevoilor noastre, adică 2 clase. De asemenea, utilizați CrossEntropyLoss pentru funcția de pierdere cu mai multe clase, iar pentru optimizator veți folosi SGD cu o rată de învățare de 0.0001 și un impuls de 0.9, așa cum se arată în exemplul de mai jos PyTorch Transfer Learning.

## 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)

Structura modelului de ieșire

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)
  )
)

Pasul 3) Antrenează și testează modelul

Vom folosi unele dintre funcțiile de la Transfer Learning Tutorial PyTorch pentru a ne ajuta să ne instruim și să ne evaluăm modelul.

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)

În cele din urmă, în acest exemplu de Transfer Learning în PyTorch, să începem procesul nostru de instruire cu numărul de epoci setat la 25 și să evaluăm după procesul de instruire. La fiecare pas de antrenament, modelul va prelua intrarea și va prezice rezultatul. După aceea, rezultatul estimat va fi trecut la criteriul de calculare a pierderilor. Apoi pierderile vor efectua un calcul backprop pentru a calcula gradientul și în final se calculează greutățile și se vor optimiza parametrii cu autograd.

La modelul de vizualizare, rețeaua instruită va fi testată cu un lot de imagini pentru a prezice etichetele. Apoi va fi vizualizat cu ajutorul matplotlib.

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

visualize_model(vgg_based)

plt.show()

Pasul 4) Rezultate

Rezultatul final este că ați obținut o precizie de 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

Încheiați, apoi rezultatul modelului nostru va fi vizualizat cu matplot de mai jos:

Vizualizat cu Matplot
Vizualizat cu Matplot

Rezumat

Deci, haideți să rezumam totul! Primul factor este PyTorch este un cadru de învățare profundă în creștere pentru începători sau în scopuri de cercetare. Oferă timp mare de calcul, grafic dinamic, suport pentru GPU și este complet scris Python. Puteți să vă definiți cu ușurință propriul modul de rețea și să efectuați procesul de instruire cu o iterație ușoară. Este clar că PyTorch este ideal pentru începători pentru a afla învățarea profundă și pentru cercetătorii profesioniști este foarte util cu un timp de calcul mai rapid și, de asemenea, cu funcția de autograd foarte utilă pentru a ajuta graficul dinamic.