PyTorch Урок за трансферно обучение с примери

Какво е трансферно обучение?

Прехвърляне на обучение е техника за използване на обучен модел за решаване на друга свързана задача. Това е изследователски метод на машинно обучение, който съхранява знанията, придобити при решаването на определен проблем, и използва същите знания за решаване на друг различен, но свързан проблем. Това подобрява ефективността чрез повторно използване на информацията, събрана от предварително научената задача.

Популярно е да използвате друго тегло на мрежов модел, за да намалите времето си за обучение, тъй като имате нужда от много данни, за да обучите мрежов модел. За да намалите времето за обучение, вие използвате други мрежи и тяхното тегло и модифицирате последния слой, за да решите нашия проблем. Предимството е, че можете да използвате малък набор от данни, за да обучите последния слой.

Следващо в този PyTorch Урок за трансферно обучение, ще научим как да използваме трансферно обучение с PyTorгл.

Зареждане на набор от данни

Зареждане на набор от данни

Източник: Alien vs. Predator Kaggle

Преди да започнете да използвате Transfer Learning PyTorch, трябва да разберете набора от данни, който ще използвате. В този Transfer Learning PyTorНапример, ще класифицирате извънземен и хищник от близо 700 изображения. За тази техника не е необходимо голямо количество данни за обучение. Можете да изтеглите набора от данни от Kaggle: Извънземно срещу Хищник.

Как да използваме трансферното обучение?

Ето стъпка по стъпка процес за това как да използвате трансферно обучение за дълбоко обучение с PyTorch:

Стъпка 1) Заредете данните

Първата стъпка е да заредим нашите данни и да направим известна трансформация на изображенията, така че да отговарят на мрежовите изисквания.

Ще заредите данните от папка с torchvision.dataset. Модулът ще повтори в папката, за да раздели данните за обучение и валидиране. Процесът на трансформация ще изреже изображенията от центъра, ще извърши хоризонтално обръщане, ще нормализира и накрая ще ги преобразува в тензор с помощта на 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")

Нека визуализираме нашия набор от данни за PyTorch Трансфер на обучение. Процесът на визуализация ще получи следващата партида изображения от устройствата за зареждане на данни и етикетите на влака и ще ги покаже с 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()
Партида от изображения
Партида от изображения

Стъпка 2) Дефиниране на модел

В този Дълбоко обучение процес, ще използвате ResNet18 от модула torchvision.

Ще използвате torchvision.models, за да заредите resnet18 с предварително обученото тегло, зададено на True. След това ще замразите слоевете, така че те да не могат да се обучават. Също така ще модифицирате последния слой с линеен слой, за да отговаря на нашите нужди, т.е. 2 класа. Ще използвате и CrossEntropyLoss за функция на загуба с множество класове, а за оптимизатора ще използвате SGD със скорост на обучение 0.0001 и импулс 0.9, както е показано на диаграмата Py по-долу.Torch Пример за трансферно обучение.

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

Структурата на изходния модел

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) Обучете и тествайте модела

Ще използваме някои от функциите на Transfer Learning PyTorch Урок за да ни помогне да обучим и оценим нашия модел.

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)

Накрая в това трансферно обучение в PyTorНапример, нека започнем нашия процес на обучение с броя епохи, зададен на 25, и да го оценим след края на процеса на обучение. На всяка стъпка от обучението моделът ще приема входните данни и ще предсказва изхода. След това прогнозираният изход ще бъде предаден на критерия за изчисляване на загубите. След това загубите ще извършат обратно изчисление, за да изчислят градиента и накрая ще изчислят теглата и да оптимизират параметрите с autograd.

При модела за визуализиране обучената мрежа ще бъде тествана с партида изображения, за да се предвидят етикетите. След това ще се визуализира с помощта на matplotlib.

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

visualize_model(vgg_based)

plt.show()

Стъпка 4) Резултати

Крайният резултат е, че сте постигнали точност от 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

Край, тогава изходът от нашия модел ще бъде визуализиран с matplot по-долу:

Визуализира се с Matplot
Визуализира се с Matplot

Oбобщение

И така, нека обобщим всичко! Първият фактор е Py.Torch е развиваща се рамка за дълбоко обучение, подходяща за начинаещи или за изследователски цели. Тя предлага високо време за изчисление, динамична графика, поддръжка на графични процесори и е изцяло написана на... PythonМожете лесно да дефинирате свой собствен мрежов модул и да извършите процеса на обучение с лесна итерация. Ясно е, че PyTorch е идеален за начинаещи, за да се запознаят с дълбокото обучение, а за професионални изследователи е много полезен с по-бързото време за изчисление, както и с много полезната функция за автоматично градиране, която подпомага динамичната графика.

Обобщете тази публикация с: