PyTorch Transfer Learning Tutorial ja esimerkkejä

Mitä on Transfer Learning?

Siirrä oppiminen on tekniikka, jossa käytetään koulutettua mallia toisen asiaan liittyvän tehtävän ratkaisemiseen. Se on koneoppimisen tutkimusmenetelmä, joka tallentaa tietyn ongelman ratkaisemisen aikana saadun tiedon ja käyttää samaa tietoa toisen erilaisen, mutta siihen liittyvän ongelman ratkaisemiseen. Tämä parantaa tehokkuutta käyttämällä uudelleen aiemmin opitusta tehtävästä kerättyä tietoa.

On suosittua käyttää muita verkkomallipainoja harjoitusajan lyhentämiseen, koska tarvitset paljon dataa verkkomallin harjoittamiseen. Harjoitusajan lyhentämiseksi käytät muita verkkoja ja niiden painoa ja muokkaat viimeistä kerrosta ongelmamme ratkaisemiseksi. Etuna on, että voit käyttää pientä tietojoukkoa viimeisen kerroksen kouluttamiseen.

Seuraavaksi tässä PyTorch Transfer -oppimisoppaassa opimme käyttämään Transfer Learning -toimintoa PyTorchin kanssa.

Ladataan tietojoukkoa

Ladataan tietojoukkoa

Lähde: Alien vs. Predator Kaggle

Ennen kuin aloitat Transfer Learning PyTorchin käytön, sinun on ymmärrettävä käytettävä tietojoukko. Tässä Transfer Learning PyTorch -esimerkissä luokittelet alienin ja predatorin lähes 700 kuvasta. Tätä tekniikkaa käytettäessä harjoittelu ei todellakaan tarvitse suurta datamäärää. Voit ladata tietojoukon osoitteesta Kaggle: Alien vs. Predator.

Kuinka käyttää siirtooppimista?

Tässä on vaiheittainen prosessi Transfer Learningin käyttämiseksi syväoppimisessa PyTorchin kanssa:

Vaihe 1) Lataa tiedot

Ensimmäinen askel on ladata tietomme ja tehdä kuviksi jonkin verran muunnoksia, jotta ne vastasivat verkkovaatimuksia.

Lataat tiedot kansiosta, jossa on torchvision.dataset. Moduuli toistuu kansiossa jakaakseen tiedot junaa ja validointia varten. Muunnosprosessi rajaa kuvat keskeltä, suorittaa vaakasuoran käännön, normalisoi ja lopuksi muuntaa sen tensoriksi Deep Learningin avulla.

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

Visualisoidaan PyTorch Transfer Learning -tietojoukkomme. Visualisointiprosessi noutaa seuraavan erän kuvia junatietojen latauslaitteista ja tarroista ja näyttää sen matplotilla.

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()
Joukko kuvia
Joukko kuvia

Vaihe 2) Määritä malli

Tässä Deep Learning prosessissa, käytät ResNet18:aa torchvision-moduulista.

Käytät torchvision.models-tiedostoa resnet18:n lataamiseen, kun esiopetettu paino on asetettu arvoon True. Tämän jälkeen jäähdytät kerrokset, jotta nämä kerrokset eivät ole koulutettavissa. Voit myös muokata viimeistä kerrosta Lineaarisella kerroksella, joka sopii tarpeisiimme, joka on 2 luokkaa. Käytät myös CrossEntropyLossia usean luokan häviötoimintoon, ja optimoijassa käytät SGD:tä, jonka oppimisnopeus on 0.0001 ja liikemäärä 0.9, kuten alla olevassa PyTorch Transfer Learning -esimerkissä näkyy.

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

Tulosmallin rakenne

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

Vaihe 3) Kouluta ja testaa malli

Käytämme joitain Transfer Learningin toimintoja PyTorch opetusohjelma auttaa meitä kouluttamaan ja arvioimaan malliamme.

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)

Lopuksi tässä PyTorchin Transfer Learning -esimerkissä aloitetaan harjoitusprosessi epokkien määrällä 25 ja arvioidaan koulutusprosessin jälkeen. Jokaisessa harjoitusvaiheessa malli ottaa syötteen ja ennustaa lähdön. Sen jälkeen ennustettu tuotto siirretään kriteeriin häviöiden laskemiseksi. Sitten häviöt suorittavat backprop-laskelman gradientin laskemiseksi ja lopuksi painojen laskemisen ja parametrien optimoinnin autogradilla.

Visualisointimallissa koulutettua verkkoa testataan kuvaerällä tarrojen ennustamiseksi. Sitten se visualisoidaan matplotlibin avulla.

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

visualize_model(vgg_based)

plt.show()

Vaihe 4) Tulokset

Lopputulos on, että saavutit 92 %:n tarkkuuden.

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

Lopuksi mallimme tulos visualisoidaan alla olevalla matplotilla:

Visualisoitu Matplotilla
Visualisoitu Matplotilla

Yhteenveto

Joten, tiivistetään kaikki! Ensimmäinen tekijä on, että PyTorch on kasvava syväoppimiskehys aloittelijoille tai tutkimustarkoituksiin. Se tarjoaa pitkän laskentaajan, dynaamisen grafiikan, grafiikkasuorittimen tuen ja se on täysin sisäänkirjoitettu Python. Pystyt määrittelemään oman verkkomoduulisi helposti ja suorittamaan koulutusprosessin helpolla iteraatiolla. On selvää, että PyTorch on ihanteellinen aloittelijoille syväoppimisen selvittämiseen, ja ammattitutkijoille se on erittäin hyödyllinen nopeamman laskenta-ajan ja myös erittäin hyödyllisen autograd-toiminnon ansiosta, joka auttaa dynaamista kuvaajaa.