본문 바로가기

Programming

[pytorch] 전이 학습, Transfer Learning

728x90
반응형

Transfer learning

  • 다른 데이터셋으로 학습시킨 모델(pre-training learning)을 현재 데이터에 적용하는 것
  • 일반적으로 대용량 데이터셋으로 만들어진 모델의 성능이 좋기 때문에 활용하는 것
  • 현재 딥러닝에서 가장 일반적으로 사용하는 학습 기법
  • backbone architecture가 잘 학습된 모델에서 일부분만 변경하여 학습을 수행함
  • 이미지 : Torchvision에서 다양한 기본 모델을 제공하고 있음
  • 자연어 : HuggingFace가 사실상 표준으로 사용되고 있음

 

Freezing

  • pre-trained model 활용 시 모델 일부분을 학습하지 않도록 frozen 시킴
  • 최근에는 stepping frozen 기법이 사용되기도 함 (중간중간 frozen 시켜 그 부분을 학습시키지 않고 성능을 비교)

from torchvision import datasets
import torchvision.transforms as transforms
import torch
from torch import nn
from torchvision import models

dataset = datasets.ImageFolder(root='data/',
                               transform=transforms.Compose([
                                   transforms.Resize(244),
                                   transforms.CenterCrop(244),
                                   transforms.ToTensor(),
                                   transforms.Normalize((0.5, 0.5, 0.5),
                                                        (0.5, 0.5, 0.5)),
                               ]))
dataloader = torch.utils.data.DataLoader(dataset, 
                                         batch_size=2, 
                                         shuffle=True, 
                                         num_workers=8)
 
class MyNewNet(nn.Module):
  def __init__(self):
    super(MyNewNet, self).__init__()
    # pre-trainined 모델
    self.vgg19 = models.vgg19(pretrained=True) 
    
    # 레이어 추가
    self.linear_layers = nn.Linear(1000, 1)

  def forward(self, x):
    x = self.vgg19(x)
    return self.linear_layers(x)
  
  
def binary_acc(y_pred, y_test):
  y_pred_tag = torch.round(torch.sigmoid(y_pred))
  correct_result_sum = (y_pred_tag == y_test).sum().float()
  acc = correct_result_sum / y_test.shape[0]
  acc = torch.round(acc * 100)
  return acc


EPOCH = 100
BATCH_SIZE = 64
LEARNING_RATE = 0.1

devcie = torch.device("cuda" if torch.cuda.is_available() else "cpu")

my_model = MyNewNet().to(device)
my_model.to(device)

# Freezing
for param in my_model.parameters():
  param.requires_grad = False

# 추가한 레이어의 parameter는 학습할 수 있도록 Unfreezing
for param in my_model.linear_layers.parameters():
  param.requires_grad = True


criterion = nn.BCEWithLogitsLoss()
optimizer = optim.Adam(my_model.parameters(), lr=LEARNING_RATE)

# 학습
for e in range(1, EPOCH+1):
  epoch_loss = 0
  epoch_acc = 0

  for X_batch, y_batch in dataloader:
    X_batch, y_batch = X_batch.to(device), y_batch.to(device).type(torch.cuda.FloatTensor)

    optimizer.zero_grad()
    y_pred = my_model(X_batch)
    
    loss = criterion(y_pred, y_batch.unsqueeze(1))
    acc = binary_acc(y_pred, y_batch.unsqueeze(1))

    loss.backward()
    optimizer.step()

    epoch_loss += loss.item()
    epoch_acc += acc.item()

  print(f"Epoch {e+0:03} | Loss:{epoch_loss/len(dataloader):.5f} | Acc: {epoch_acc/len(dataloader):.3f} ")
728x90
반응형