PyTorch Transfer Learning Tutorial med eksempler

Hvad er Transfer Learning?

Overfør læring er en teknik til at bruge en trænet model til at løse en anden relateret opgave. Det er en Machine Learning-forskningsmetode, der gemmer den opnåede viden, mens du løser et bestemt problem, og bruger den samme viden til at løse et andet andet, men relateret problem. Dette forbedrer effektiviteten ved at genbruge informationen indsamlet fra den tidligere lærte opgave.

Det er populært at bruge andre netværksmodelvægte til at reducere din træningstid, fordi du har brug for en masse data for at træne en netværksmodel. For at reducere træningstiden bruger du andre netværk og dets vægt og ændrer det sidste lag for at løse vores problem. Fordelen er, at du kan bruge et lille datasæt til at træne det sidste lag.

Næste i denne PyTorch Transfer-læringsvejledning lærer vi, hvordan du bruger Transfer Learning med PyTorch.

Indlæser datasæt

Indlæser datasæt

Kilde: Alien vs Predator Kaggle

Før du begynder at bruge Transfer Learning PyTorch, skal du forstå det datasæt, du skal bruge. I dette Transfer Learning PyTorch-eksempel vil du klassificere en Alien og en Predator fra næsten 700 billeder. Til denne teknik behøver du egentlig ikke en stor mængde data for at træne. Du kan downloade datasættet fra Kaggle: Alien vs. Predator.

Hvordan bruger man Transfer Learning?

Her er en trinvis proces om, hvordan du bruger Transfer Learning til Deep Learning med PyTorch:

Trin 1) Indlæs dataene

Det første skridt er at indlæse vores data og lave nogle transformationer til billeder, så de matcher netværkskravene.

Du vil indlæse data fra en mappe med torchvision.dataset. Modulet vil iterere i mappen for at opdele dataene til tog og validering. Transformationsprocessen vil beskære billederne fra midten, udføre en vandret vending, normalisere og til sidst konvertere dem til tensor ved hjælp af 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")

Lad os visualisere vores datasæt til PyTorch Transfer Learning. Visualiseringsprocessen vil hente det næste parti billeder fra togdataindlæserne og etiketter og vise det med 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()
Batch af billeder
Batch af billeder

Trin 2) Definer model

I denne Deep Learning proces, vil du bruge ResNet18 fra torchvision-modulet.

Du vil bruge torchvision.models til at indlæse resnet18 med den forudtrænede vægt indstillet til at være True. Derefter vil du fryse lagene, så disse lag ikke kan trænes. Du ændrer også det sidste lag med et lineært lag, så det passer til vores behov, dvs. 2 klasser. Du bruger også CrossEntropyLoss til multi-class tab-funktion og til optimizeren vil du bruge SGD med indlæringshastigheden på 0.0001 og et momentum på 0.9 som vist i nedenstående PyTorch Transfer Learning-eksempel.

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

Outputmodellens struktur

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

Trin 3) Træn og test model

Vi vil bruge nogle af funktionerne fra Transfer Learning PyTorch tutorial at hjælpe os med at træne og evaluere vores model.

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)

Til sidst i dette Transfer Learning i PyTorch eksempel, lad os starte vores træningsproces med antallet af epoker sat til 25 og evaluere efter træningsprocessen. Ved hvert træningstrin vil modellen tage input og forudsige output. Derefter vil det forudsagte output blive overført til kriteriet for at beregne tabene. Derefter vil tabene udføre en backprop-beregning for at beregne gradienten og til sidst beregne vægtene og optimere parametrene med autograd.

Ved visualiseringsmodellen vil det trænede netværk blive testet med en batch af billeder for at forudsige etiketterne. Derefter vil det blive visualiseret ved hjælp af matplotlib.

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

visualize_model(vgg_based)

plt.show()

Trin 4) Resultater

Det endelige resultat er, at du opnåede en nøjagtighed på 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

Slut så vil output fra vores model blive visualiseret med matplot nedenfor:

Visualiseret med Matplot
Visualiseret med Matplot

Resumé

Så lad os opsummere alt! Den første faktor er PyTorch er en voksende dyb læringsramme for begyndere eller til forskningsformål. Det tilbyder høj beregningstid, Dynamic Graph, GPU'er-understøttelse og det er fuldstændig skrevet ind Python. Du er i stand til at definere dit eget netværksmodul med lethed og udføre træningsprocessen med en nem iteration. Det er klart, at PyTorch er ideel for begyndere til at finde ud af dyb læring, og for professionelle forskere er det meget nyttigt med hurtigere beregningstid og også den meget nyttige autograd-funktion til at hjælpe dynamisk graf.