PyTorchi ülekande õppimise õpetus koos näidetega

Mis on ülekandeõpe?

Ülekandeõpe on tehnika, mille abil kasutatakse koolitatud mudelit mõne muu seotud ülesande lahendamiseks. See on masinõppe uurimismeetod, mis salvestab konkreetse probleemi lahendamisel saadud teadmised ja kasutab samu teadmisi teise erineva, kuid samas seotud probleemi lahendamiseks. See suurendab tõhusust, kasutades eelnevalt õpitud ülesandest kogutud teavet.

Treeningaja vähendamiseks on populaarne kasutada teisi võrgumudeli kaalu, kuna võrgumudeli treenimiseks on vaja palju andmeid. Treeningaja vähendamiseks kasutate teisi võrke ja selle kaalu ning muudate meie probleemi lahendamiseks viimast kihti. Eeliseks on see, et saate viimase kihi treenimiseks kasutada väikest andmekogumit.

Järgmisena selles PyTorch Transferi õppeõpetuses õpime, kuidas kasutada PyTorchiga ülekandeõpet.

Andmestiku laadimine

Andmestiku laadimine

Allikas: Alien vs Predator Kaggle

Enne Transfer Learning PyTorchi kasutamise alustamist peate mõistma kasutatavat andmekogumit. Selles Transfer Learning PyTorchi näites liigitate ligi 700 pildi hulgast tulnuka ja kiskja. Selle tehnika jaoks ei vaja te treenimiseks suurt hulka andmeid. Andmestiku saate alla laadida aadressilt Kaggle: Tulnukas vs. kiskja.

Kuidas kasutada ülekandeõpet?

Siin on samm-sammuline protsess, kuidas kasutada PyTorchiga süvaõppeks mõeldud ülekandeõpet:

Samm 1) Laadige andmed

Esimene samm on meie andmete laadimine ja piltide muutmine, et need vastaksid võrgunõuetele.

Laadite andmed kaustast torchvision.dataset. Moodul korrutab kaustas, et jagada andmed rongi ja valideerimise jaoks. Teisendusprotsess kärbib pilte keskelt, sooritab horisontaalse ümberpööramise, normaliseerib ja lõpuks teisendab need süvaõppe abil tensoriks.

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

Visualiseerime oma PyTorch Transfer Learningi andmestikku. Visualiseerimisprotsess võtab rongi andmelaadijatelt ja siltidelt järgmise pildipartii ning kuvab selle matplotiga.

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()
Piltide partii
Piltide partii

Samm 2) Määratlege mudel

Selle Sügav õppimine protsessi, kasutate torchvisioni moodulist ResNet18.

Kasutate faili resnet18 laadimiseks torchvision.models, mille eeltreenitud kaal on seatud väärtusele Tõene. Pärast seda külmutate kihid, nii et need kihid pole treenitavad. Samuti muudate viimast kihti lineaarse kihiga, et see sobiks meie vajadustega, mis on 2 klassi. Kasutate ka CrossEntropyLossi mitme klassi kadufunktsiooni jaoks ja optimeerija jaoks kasutate SGD-d õppimiskiirusega 0.0001 ja impulsiga 0.9, nagu on näidatud allolevas PyTorchi ülekande õppimise näites.

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

Väljundmudeli struktuur

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

3. samm) Treenige ja katsetage mudelit

Kasutame mõnda Transfer Learningi funktsiooni PyTorchi õpetus et aidata meil oma mudelit koolitada ja hinnata.

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)

Lõpuks selles PyTorchis õppimise ülekandmise näites alustame oma koolitusprotsessi ajastute arvuga 25 ja hindame pärast koolitusprotsessi. Igal koolitusetapil võtab mudel sisendi ja ennustab väljundit. Pärast seda suunatakse prognoositav toodang kahjude arvutamise kriteeriumile. Seejärel teostavad kaod gradiendi arvutamiseks backprop-arvutuse ja lõpuks kaalude arvutamise ning parameetrite optimeerimise autogradiga.

Visualiseerimismudelis testitakse koolitatud võrku piltide partiiga, et sildid ennustada. Seejärel visualiseeritakse see matplotlibi abil.

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

visualize_model(vgg_based)

plt.show()

4. samm) Tulemused

Lõpptulemus on see, et saavutasite 92% täpsuse.

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

Lõpeta, siis visualiseeritakse meie mudeli väljund alloleva matplotiga:

Visualiseeriti Matplotiga
Visualiseeriti Matplotiga

kokkuvõte

Niisiis, võtame kõik kokku! Esimene tegur on see, et PyTorch on kasvav süvaõpperaamistik algajatele või uurimiseesmärkidel. See pakub pikka arvutusaega, dünaamilist graafikut, GPU-de tuge ja see on täielikult sisse kirjutatud Python. Saate hõlpsasti määratleda oma võrgumooduli ja teha koolitusprotsessi lihtsa iteratsiooniga. On selge, et PyTorch on ideaalne algajatele süvaõppe õppimiseks ning professionaalsetele teadlastele on see väga kasulik kiirema arvutusaja ja ka väga kasuliku autogradi funktsiooniga dünaamilise graafiku abistamiseks.