PyTorch Transfer Learning Tutorial mit Beispielen

Was ist Transferlernen?

Lernen übertragen ist eine Technik, bei der ein trainiertes Modell verwendet wird, um eine andere verwandte Aufgabe zu lösen. Es handelt sich um eine Forschungsmethode des maschinellen Lernens, die das bei der Lösung eines bestimmten Problems gewonnene Wissen speichert und dasselbe Wissen zur Lösung eines anderen, aber verwandten Problems verwendet. Dies verbessert die Effizienz, indem die aus der zuvor erlernten Aufgabe gesammelten Informationen wiederverwendet werden.

Es ist beliebt, eine andere Netzwerkmodellgewichtung zu verwenden, um die Trainingszeit zu verkürzen, da Sie zum Trainieren eines Netzwerkmodells viele Daten benötigen. Um die Trainingszeit zu verkürzen, nutzen Sie andere Netzwerke und deren Gewicht und modifizieren die letzte Schicht, um unser Problem zu lösen. Der Vorteil besteht darin, dass Sie einen kleinen Datensatz verwenden können, um die letzte Ebene zu trainieren.

Als nächstes lernen wir in diesem PyTorch Transfer-Lerntutorial, wie man Transfer Learning mit PyTorch verwendet.

Datensatz laden

Datensatz laden

Quelle: Alien vs. Predator Kaggle

Bevor Sie Transfer Learning PyTorch verwenden, müssen Sie den Datensatz verstehen, den Sie verwenden möchten. In diesem Transfer Learning PyTorch-Beispiel klassifizieren Sie einen Außerirdischen und einen Raubtier aus fast 700 Bildern. Für diese Technik benötigen Sie nicht unbedingt eine große Datenmenge zum Trainieren. Sie können den Datensatz herunterladen unter Kaggle: Alien vs. Predator.

Wie nutzt man Transferlernen?

Hier ist ein Schritt-für-Schritt-Prozess zur Verwendung von Transfer Learning für Deep Learning mit PyTorch:

Schritt 1) ​​Laden Sie die Daten

Der erste Schritt besteht darin, unsere Daten zu laden und die Bilder so umzuwandeln, dass sie den Netzwerkanforderungen entsprechen.

Sie laden die Daten aus einem Ordner mit Torchvision.dataset. Das Modul durchläuft den Ordner, um die Daten für Training und Validierung aufzuteilen. Der Transformationsprozess schneidet die Bilder von der Mitte aus zu, führt eine horizontale Spiegelung durch, normalisiert sie und wandelt sie schließlich mithilfe von Deep Learning in einen Tensor um.

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

Lassen Sie uns unseren Datensatz für PyTorch Transfer Learning visualisieren. Der Visualisierungsprozess ruft den nächsten Bilderstapel von den Zugdatenladern und Etiketten ab und zeigt ihn mit Matplot an.

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()
Stapel von Bildern
Stapel von Bildern

Schritt 2) Modell definieren

In diesem Tiefes Lernen Im Prozess verwenden Sie ResNet18 aus dem Torchvision-Modul.

Sie verwenden torchvision.models, um resnet18 mit dem vorab trainierten Gewicht auf True zu laden. Danach frieren Sie die Schichten ein, damit diese Schichten nicht trainiert werden können. Sie ändern auch die letzte Schicht mit einer linearen Schicht, um sie unseren Anforderungen anzupassen, d. h. mit 2 Klassen. Sie verwenden auch CrossEntropyLoss für die Verlustfunktion mehrerer Klassen und für den Optimierer verwenden Sie SGD mit einer Lernrate von 0.0001 und einem Momentum von 0.9, wie im folgenden PyTorch Transfer Learning-Beispiel gezeigt.

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

Die Struktur des Ausgabemodells

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

Schritt 3) Modell trainieren und testen

Wir werden einige der Funktionen von Transfer Learning nutzen PyTorch-Tutorial um uns beim Trainieren und Bewerten unseres Modells zu helfen.

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)

Abschließend beginnen wir in diesem Beispiel zum Transferlernen in PyTorch unseren Trainingsprozess mit einer auf 25 eingestellten Anzahl von Epochen und werten ihn nach dem Trainingsprozess aus. Bei jedem Trainingsschritt übernimmt das Modell die Eingabe und prognostiziert die Ausgabe. Danach wird die vorhergesagte Leistung an das Kriterium zur Berechnung der Verluste übergeben. Anschließend führen die Verluste eine Backprop-Berechnung durch, um den Gradienten zu berechnen und schließlich die Gewichte zu berechnen und die Parameter mit Autograd zu optimieren.

Beim Visualisierungsmodell wird das trainierte Netzwerk mit einer Reihe von Bildern getestet, um die Beschriftungen vorherzusagen. Anschließend wird es mit Hilfe von Matplotlib visualisiert.

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

visualize_model(vgg_based)

plt.show()

Schritt 4) Ergebnisse

Das Endergebnis ist, dass Sie eine Genauigkeit von 92 % erreicht haben.

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

Am Ende wird die Ausgabe unseres Modells mit Matplot unten visualisiert:

Visualisiert mit Matplot
Visualisiert mit Matplot

Zusammenfassung

Fassen wir also alles zusammen! Der erste Faktor ist, dass PyTorch ein wachsendes Deep-Learning-Framework für Anfänger oder für Forschungszwecke ist. Es bietet hohe Rechenzeiten, dynamische Graphen, GPU-Unterstützung und ist vollständig in Python. Sie können ganz einfach Ihr eigenes Netzwerkmodul definieren und den Trainingsprozess mit einer einfachen Iteration durchführen. Es ist klar, dass PyTorch ideal für Anfänger zum Erlernen von Deep Learning ist und für professionelle Forscher mit schnellerer Rechenzeit und der sehr hilfreichen Autograd-Funktion zur Unterstützung dynamischer Diagramme sehr nützlich ist.