บทช่วยสอนการถ่ายโอน PyTorch พร้อมตัวอย่าง

Transfer Learning คืออะไร?

ถ่ายทอดการเรียนรู้ เป็นเทคนิคการใช้แบบจำลองที่ผ่านการฝึกอบรมเพื่อแก้ไขงานอื่นที่เกี่ยวข้อง เป็นวิธีการวิจัย Machine Learning ที่เก็บความรู้ที่ได้รับขณะแก้ไขปัญหาเฉพาะ และใช้ความรู้เดียวกันเพื่อแก้ปัญหาอื่นที่แตกต่างกันแต่เกี่ยวข้องกัน สิ่งนี้ช่วยปรับปรุงประสิทธิภาพโดยการนำข้อมูลที่รวบรวมจากงานที่เรียนรู้ก่อนหน้านี้กลับมาใช้ใหม่

นิยมใช้น้ำหนักโมเดลเครือข่ายอื่นๆ เพื่อลดเวลาการฝึก เนื่องจากคุณต้องการข้อมูลจำนวนมากเพื่อฝึกโมเดลเครือข่าย เพื่อลดเวลาการฝึกอบรม คุณใช้เครือข่ายอื่นและน้ำหนักของมัน และแก้ไขเลเยอร์สุดท้ายเพื่อแก้ไขปัญหาของเรา ข้อดีคือคุณสามารถใช้ชุดข้อมูลขนาดเล็กเพื่อฝึกเลเยอร์สุดท้ายได้

ต่อไปในบทช่วยสอนการเรียนรู้ PyTorch Transfer นี้ เราจะได้เรียนรู้วิธีใช้ Transfer Learning กับ PyTorch

กำลังโหลดชุดข้อมูล

กำลังโหลดชุดข้อมูล

ที่มา: Alien vs. Predator Kaggle

ก่อนที่คุณจะเริ่มใช้ Transfer Learning PyTorch คุณต้องเข้าใจชุดข้อมูลที่คุณจะใช้ ในตัวอย่าง Transfer Learning PyTorch นี้ คุณจะจำแนกเอเลี่ยนและนักล่าจากรูปภาพเกือบ 700 รูป สำหรับเทคนิคนี้ คุณไม่จำเป็นต้องมีข้อมูลจำนวนมากในการฝึก คุณสามารถดาวน์โหลดชุดข้อมูลได้จาก Kaggle: เอเลี่ยนกับพรีเดเตอร์

วิธีใช้การถ่ายโอนการเรียนรู้

ต่อไปนี้เป็นกระบวนการทีละขั้นตอนเกี่ยวกับวิธีใช้ Transfer Learning เพื่อการเรียนรู้เชิงลึกด้วย 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 หลังจากนั้น คุณจะตรึงเลเยอร์เหล่านี้เพื่อไม่ให้สามารถฝึกได้ นอกจากนี้ คุณยังแก้ไขเลเยอร์สุดท้ายด้วยเลเยอร์เชิงเส้นเพื่อให้เหมาะกับความต้องการของเรา ซึ่งก็คือ 2 คลาส นอกจากนี้ คุณยังใช้ CrossEntropyLoss สำหรับฟังก์ชันการสูญเสียหลายคลาส และสำหรับตัวเพิ่มประสิทธิภาพ คุณจะใช้ SGD ด้วยอัตราการเรียนรู้ 0.0001 และโมเมนตัม 0.9 ดังที่แสดงในตัวอย่าง PyTorch Transfer Learning ด้านล่าง

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

สุดท้ายนี้ในตัวอย่าง Transfer Learning ใน PyTorch เราจะมาเริ่มกระบวนการฝึกอบรมโดยกำหนดจำนวนยุคไว้ที่ 25 และประเมินหลังกระบวนการฝึกอบรม ในแต่ละขั้นตอนการฝึก แบบจำลองจะรับข้อมูลเข้าและคาดการณ์ผลลัพธ์ หลังจากนั้นผลลัพธ์ที่คาดการณ์ไว้จะถูกส่งไปยังเกณฑ์เพื่อคำนวณการสูญเสีย จากนั้นส่วนที่สูญเสียจะทำการคำนวณ backprop เพื่อคำนวณการไล่ระดับสี และสุดท้ายคือคำนวณน้ำหนักและปรับพารามิเตอร์ให้เหมาะสมด้วยระบบออโต้กราด

ที่โมเดลการแสดงภาพ เครือข่ายที่ได้รับการฝึกอบรมจะได้รับการทดสอบด้วยชุดรูปภาพเพื่อทำนายป้ายกำกับ จากนั้นมันจะเห็นภาพด้วยความช่วยเหลือของ 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

สรุป

มาสรุปกันก่อนดีกว่า ปัจจัยแรกก็คือ PyTorch เป็นเฟรมเวิร์กการเรียนรู้เชิงลึกที่กำลังเติบโตสำหรับผู้เริ่มต้นหรือเพื่อวัตถุประสงค์ในการวิจัย มันมีเวลาการคำนวณสูง กราฟแบบไดนามิก รองรับ GPU และเขียนขึ้นทั้งหมดด้วย Python- คุณสามารถกำหนดโมดูลเครือข่ายของคุณเองได้อย่างง่ายดาย และดำเนินกระบวนการฝึกอบรมด้วยการวนซ้ำที่ง่ายดาย เห็นได้ชัดว่า PyTorch เหมาะสำหรับผู้เริ่มต้นในการค้นหาการเรียนรู้เชิงลึก และสำหรับนักวิจัยมืออาชีพ มันมีประโยชน์มากด้วยเวลาในการคำนวณที่เร็วขึ้น และยังมีฟังก์ชัน Autograd ที่มีประโยชน์มากในการช่วยกราฟแบบไดนามิก