인공지능/파이토치

파이토치 - 전이 학습

해피밀세트 2020. 7. 22. 00:01
반응형

 

 

 

 

1. 데이터 준비

 

1) DataLoader 작성

 

# 구글 드라이브와 구글 코랩을 연동

from google.colab import drive

drive.mount('/content/gdrive')

# 라이브러리 불러오기

import torch

from torch import nn, optim

from torch.utils.data import (Dataset,

                              DataLoader,

                              TensorDataset)

import tqdm

# DataLoader 작성

from torchvision.datasets import ImageFolder

from torchvision import transforms

# ImageFolder 함수를 사용해서 Dataset 작성

train_imgs = ImageFolder("/content/gdrive/My Drive/taco_and_burrito/train/",

                         transform=transforms.Compose([transforms.RandomCrop(224),

                                                       transforms.ToTensor()]))

test_imgs = ImageFolder("/content/gdrive/My Drive/taco_and_burrito/test/",

                         transform=transforms.Compose([transforms.RandomCrop(224),

                                                       transforms.ToTensor()]))

# DataLoader 작성

train_loader = DataLoader(

    train_imgs, batch_size=32, shuffle=True)

test_loader = DataLoader(

    test_imgs, batch_size=32, shuffle=False)

 

 

 

2) 분류명과 분류 인덱스 대응 관계 확인

 

# 클래스 확인

print(train_imgs.classes)

# 클래스의 인덱스 확인

print(train_imgs.class_to_idx)

 

 

 

2. 파이토치를 사용한 전이 학습

 

1) 사전 학습이 끝난(Pre-trained) 모델 불러오기 및 정의

 

# 라이브러리 불러오기

from torchvision import models

# 사전 학습이 완료된 resnet18 불러오기

net = models.resnet18(pretrained=True)

# 모든 파라미터를 미분 대상에서 제외한다.

for p in net.parameters():

  p.requires_grad = False

# 마지막 선형 계층을 변경한다.

fc_input_dim = net.fc.in_features

net.fc = nn.Linear(fc_input_dim, 2)

 

 

 

2) 모델의 훈련 함수 작성

 

# eval_net 만들기

def eval_net(netdata_loaderdevice="cpu"):

  # Dropout 및 BatchNorm을 무효화

  net.eval()

  ys = []

  ypreds = []

  for x, y in data_loader:

    # to 메서드로 계산을 실행할 디바이스 전송

    x = x.to(device)

    y = y.to(device)

    # 확률이 가장 큰 분류를 예측

    # 여기선 forward(추론) 계산이 전부이므로 자동 미분에 필요한 처리는 off로 설정해서 불필요한 계산을 제한다.

    with torch.no_grad():

      _, y_pred = net(x).max(1)

    ys.append(y)

    ypreds.append(y_pred)

 

  # 미니 배치 단위의 예측 결과 등을 하나로 묶는다

  ys = torch.cat(ys)

  ypreds = torch.cat(ypreds)

  # 예측 정확도 계산

  acc = (ys == ypreds).float().sum() / len(ys)

  return acc.item()

# train_net 만들기

def train_net(nettrain_loadertest_loaderonly_fc=True,

              optimizer_cls=optim.Adam,

              loss_fn=nn.CrossEntropyLoss(),

              n_iter=10, device="cpu"):

  train_losses = []

  train_acc = []

  val_acc = []

  if only_fc:

    # 마지막 선형 계층의 파라미터만 optimizer에 전달

    optimizer = optimizer_cls(net.fc.parameters())

  else:

    optimizer = optimizer_cls(net.parameters())

  for epoch in range(n_iter):

    running_loss = 0.0

    # 신경망을 훈련 모드로 설정

    net.train()

    n = 0

    n_acc = 0

    # 시간이 많이 걸리므로 tqdm을 사용해서 진행 바를 표시

    for i, (xx, yy) in tqdm.tqdm(enumerate(train_loader),

                                 total=len(train_loader)):

      xx = xx.to(device)

      yy = yy.to(device)

      h = net(xx)

      loss = loss_fn(h, yy)

      optimizer.zero_grad()

      loss.backward()

      optimizer.step()

      running_loss += loss.item()

      n += len(xx)

      _, y_pred = h.max(1)

      n_acc += (yy == y_pred).float().sum().item()

    train_losses.append(running_loss/i)

    # 훈련 데이터의 예측 정확도

    train_acc.append(n_acc / n)

 

    # 검증 데이터의 예측 정확도

    val_acc.append(eval_net(net, test_loader, device))

    # epoch의 결과 표시

    print(epoch, train_losses[-1], train_acc[-1],

          val_acc[-1], flush=True)

 

 

 

3) 모든 파라미터를 GPU로 전송해서 훈련 실행

 

# 신경망의 모든 파라미터를 GPU로 전송

net.to("cuda:0")

# 훈련 실행

train_net(net, train_loader, test_loader, n_iter=20, device="cuda:0")

 

 

 

4) 입력을 그대로 출력하면 더미 계층을 만들어 fc를 변경

 

# 마지막층 만들기

class FlattenLayer(nn.Module):

  def forward(selfx):

    sizes = x.size()

    return x.view(sizes[0], -1)

 

class IdentityLayer(nn.Module):

  def forward(selfx):

    return x

 

net = models.resnet18(pretrained=True)

for p in net.parameters():

  p.requires_grad=False

net.fc = IdentityLayer()

 

 

 

5) 새로운 CNN 모델 실행

 

# CNN 모델

conv_net = nn.Sequential(

    nn.Conv2d(3325),

    nn.MaxPool2d(2),

    nn.ReLU(),

    nn.BatchNorm2d(32),

    nn.Conv2d(32645),

    nn.MaxPool2d(2),

    nn.ReLU(),

    nn.BatchNorm2d(64),

    nn.Conv2d(641285),

    nn.MaxPool2d(2),

    nn.ReLU(),

    nn.BatchNorm2d(128),

    FlattenLayer()

)

 

# 합성곱에 의해 최종적으로 어떤 크기인지 실제로 데이터를 넣어서 확인

test_input = torch.ones(13224224)

conv_output_size = conv_net(test_input).size()[-1]

 

# 최종 CNN

net = nn.Sequential(

    conv_net,

    nn.Linear(conv_output_size, 2)

)

 

# 신경망의 모든 파라민터를 GPU로 전송

net.to("cuda:0")

# 훈련 실행

train_net(net, train_loader, test_loader, n_iter=10, only_fc=False,

          device="cuda:0")

 

반응형