Учебное пособие по переносу обучения PyTorch с примерами

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

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

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

Далее в этом руководстве по обучению переносу PyTorch мы узнаем, как использовать перенос обучения с PyTorch.

Загрузка набора данных

Загрузка набора данных

Источник: Чужой против Хищника Кэггл.

Прежде чем начать использовать Transfer Learning PyTorch, вам необходимо понять, какой набор данных вы собираетесь использовать. В этом примере PyTorch для трансферного обучения вы классифицируете Чужого и Хищника по почти 700 изображениям. Для этого метода вам не нужен большой объем данных для обучения. Вы можете скачать набор данных с Kaggle: Чужой против Хищника.

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

Вот пошаговый процесс использования трансферного обучения для глубокого обучения с PyTorch:

Шаг 1) Загрузите данные

Первый шаг — загрузить наши данные и выполнить некоторые преобразования изображений, чтобы они соответствовали требованиям сети.

Вы загрузите данные из папки torchvision.dataset. Модуль будет перебирать папку, чтобы разделить данные для обучения и проверки. Процесс преобразования обрежет изображения из центра, выполнит горизонтальное переворот, нормализует и, наконец, преобразует их в тензор с помощью глубокого обучения.

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 Transfer Learning. Процесс визуализации получит следующую партию изображений из загрузчиков данных поезда и меток и отобразит ее с помощью 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. После этого вы заморозите слои, чтобы эти слои не поддавались обучению. Вы также модифицируете последний слой с помощью линейного слоя, чтобы он соответствовал нашим потребностям, то есть двух классов. Вы также используете CrossEntropyLoss для функции потерь нескольких классов, а для оптимизатора вы будете использовать SGD со скоростью обучения 2 и импульсом 0.0001, как показано в приведенном ниже примере переноса обучения PyTorch.

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

Наконец, в этом примере переноса обучения в PyTorch давайте начнем процесс обучения с числом эпох, равным 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

Выводы

Итак, подведем все итоги! Первый фактор: PyTorch — этоwing структура глубокого обучения для начинающих или для исследовательских целей. Он предлагает большое время вычислений, динамический график, поддержку графических процессоров и полностью написан на Питон. Вы можете легко определить свой собственный сетевой модуль и выполнить процесс обучения с помощью простой итерации. Понятно, что PyTorch идеально подходит для новичков, желающих изучить глубокое обучение, а для профессиональных исследователей он очень полезен благодаря более быстрому времени вычислений, а также очень полезной функции автоградации для поддержки динамического графика.