Vodič za učenje prijenosa PyTorcha s primjerima

Što je transferno učenje?

Prijenos učenja je tehnika korištenja uvježbanog modela za rješavanje drugog srodnog zadatka. To je istraživačka metoda strojnog učenja koja pohranjuje znanje stečeno tijekom rješavanja određenog problema i koristi isto znanje za rješavanje drugog različitog, ali povezanog problema. To poboljšava učinkovitost ponovnim korištenjem informacija prikupljenih iz prethodno naučenog zadatka.

Popularno je koristiti drugu težinu mrežnog modela kako biste smanjili vrijeme vježbanja jer vam je potrebno mnogo podataka za treniranje mrežnog modela. Da biste smanjili vrijeme treninga, koristite druge mreže i njihovu težinu i modificirajte posljednji sloj kako biste riješili naš problem. Prednost je što možete koristiti mali skup podataka za obuku posljednjeg sloja.

Zatim ćemo u ovom vodiču za učenje prijenosa PyTorch naučiti kako koristiti učenje prijenosa s PyTorchom.

Učitavanje skupa podataka

Učitavanje skupa podataka

Izvor: Alien vs. Predator Kaggle

Prije nego počnete koristiti Transfer Learning PyTorch, morate razumjeti skup podataka koji ćete koristiti. U ovom primjeru Transfer Learning PyTorch klasificirati ćete izvanzemaljca i predatora iz gotovo 700 slika. Za ovu tehniku ​​zapravo vam nije potrebna velika količina podataka za treniranje. Skup podataka možete preuzeti s Kaggle: Alien protiv Predatora.

Kako koristiti prijenos učenja?

Ovdje je korak po korak postupak kako koristiti Transfer Learning za duboko učenje s PyTorchom:

Korak 1) Učitajte podatke

Prvi korak je učitavanje naših podataka i neka transformacija slika tako da odgovaraju zahtjevima mreže.

Učitat ćete podatke iz mape s torchvision.dataset. Modul će ponavljati u mapi kako bi podijelio podatke za obuku i provjeru valjanosti. Proces transformacije izrezat će slike iz središta, izvršiti horizontalno okretanje, normalizirati i konačno pretvoriti u tenzor koristeći 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")

Idemo vizualizirati naš skup podataka za PyTorch Transfer Learning. Proces vizualizacije će dobiti sljedeću skupinu slika iz učitavača podataka o vlaku i naljepnica i prikazati ih s matplotom.

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()
Serija slika
Serija slika

Korak 2) Definirajte model

U ovom Duboko učenje procesu, koristit ćete ResNet18 iz torchvision modula.

Koristit ćete torchvision.models za učitavanje resnet18 s prethodno uvježbanom težinom postavljenom na True. Nakon toga ćete zamrznuti slojeve tako da se ti slojevi ne mogu trenirati. Također mijenjate posljednji sloj s linearnim slojem kako bi odgovarao našim potrebama, a to su 2 klase. Također koristite CrossEntropyLoss za funkciju gubitka više klasa, a za optimizator ćete koristiti SGD sa stopom učenja od 0.0001 i momentom od 0.9 kao što je prikazano u donjem primjeru učenja PyTorch Transfera.

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

Struktura izlaznog modela

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

Korak 3) Obuka i testiranje modela

Koristit ćemo neke od funkcija iz Transfer Learninga Vodič za PyTorch da nam pomognu u obuci i procjeni našeg modela.

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)

Konačno, u ovom primjeru prijenosa učenja u PyTorchu, započnimo naš proces obuke s brojem epoha postavljenim na 25 i procijenimo nakon procesa obuke. U svakom koraku obuke, model će uzeti ulaz i predvidjeti izlaz. Nakon toga, predviđeni izlaz će se proslijediti kriteriju za izračun gubitaka. Zatim će gubici izvršiti izračun pozadinske potpore za izračun gradijenta i na kraju izračunati težine i optimizirati parametre s autogradom.

Na modelu vizualizacije, obučena mreža će se testirati sa serijom slika za predviđanje oznaka. Zatim će se vizualizirati uz pomoć matplotliba.

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

visualize_model(vgg_based)

plt.show()

Korak 4) Rezultati

Konačni rezultat je da ste postigli točnost od 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

Kraj, tada će se izlaz našeg modela vizualizirati s matplotom ispod:

Vizualizirano s Matplotom
Vizualizirano s Matplotom

rezime

Dakle, rezimirajmo sve! Prvi faktor je da je PyTorch rastući okvir dubokog učenja za početnike ili u istraživačke svrhe. Nudi dugo vrijeme računanja, Dynamic Graph, podršku za GPU i potpuno je upisan Python. U mogućnosti ste s lakoćom definirati vlastiti mrežni modul i obaviti proces obuke s jednostavnom iteracijom. Jasno je da je PyTorch idealan za početnike kako bi saznali dubinsko učenje, a za profesionalne istraživače vrlo je koristan s bržim vremenom računanja i također vrlo korisnom funkcijom autograd za pomoć dinamičkom grafikonu.