PyTorch Transfer Learning Tutorial с примери
Какво е трансферно обучение?
Прехвърляне на обучение е техника за използване на обучен модел за решаване на друга свързана задача. Това е изследователски метод на машинно обучение, който съхранява знанията, придобити при решаването на определен проблем, и използва същите знания за решаване на друг различен, но свързан проблем. Това подобрява ефективността чрез повторно използване на информацията, събрана от предварително научената задача.
Популярно е да използвате друго тегло на мрежов модел, за да намалите времето си за обучение, тъй като имате нужда от много данни, за да обучите мрежов модел. За да намалите времето за обучение, вие използвате други мрежи и тяхното тегло и модифицирате последния слой, за да решите нашия проблем. Предимството е, че можете да използвате малък набор от данни, за да обучите последния слой.
След това в този урок за обучение по PyTorch Transfer ще научим как да използваме Transfer Learning с PyTorch.
Зареждане на набор от данни
Източник: Alien vs. Predator Kaggle
Преди да започнете да използвате Transfer Learning PyTorch, трябва да разберете набора от данни, който ще използвате. В този пример за PyTorch за обучение на трансфер ще класифицирате извънземен и хищник от близо 700 изображения. За тази техника всъщност не се нуждаете от голямо количество данни, за да тренирате. Можете да изтеглите набора от данни от Kaggle: Извънземно срещу Хищник.
Как да използваме трансферното обучение?
Ето процес стъпка по стъпка за това как да използвате Transfer Learning за Deep Learning с 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 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. След това ще замразите слоевете, така че тези слоеве да не могат да се тренират. Можете също така да модифицирате последния слой с линеен слой, за да отговаря на нашите нужди, което е 2 класа. Вие също така използвате CrossEntropyLoss за функция за многокласова загуба, а за оптимизатора ще използвате SGD със скорост на обучение от 0.0001 и импулс от 0.9, както е показано в примера за обучение на PyTorch Transfer по-долу.
## 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, и да направим оценка след процеса на обучение. На всяка стъпка на обучение моделът ще вземе входа и ще предвиди изхода. След това прогнозираният изход ще бъде предаден на критерия за изчисляване на загубите. След това загубите ще извършат изчисление на backprop за изчисляване на градиента и накрая изчисляване на теглата и оптимизиране на параметрите с 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 по-долу:
Oбобщение
И така, нека обобщим всичко! Първият фактор е, че PyTorch е нарастваща рамка за дълбоко обучение за начинаещи или за изследователски цели. Той предлага високо време за изчисление, динамична графика, поддръжка на GPU и е изцяло написан Python. Вие сте в състояние да дефинирате свой собствен мрежов модул с лекота и да извършите процеса на обучение с лесна итерация. Ясно е, че PyTorch е идеален за начинаещи, за да открият задълбочено обучение, а за професионални изследователи е много полезен с по-бързо време за изчисление, а също и с много полезна функция за автоматично надграждане за подпомагане на динамична графика.