.box_article .article_cont p code

상세 컨텐츠

본문 제목

[알쓸쿠잡] Pytorch 사용법2 - 신경망 모델 구성 및 사용하기

알쓸쿠잡/프레임워크

by 현지인포스 2021. 11. 24. 14:20

본문

작성자: 13기 김현지

 

Pytorch로 신경망 모델 정의하고 사용하기

 

Reference:

 

Contents

  1. 신경망 모델 구성하기
  2. 모델 매개변수 최적화하기
  3. 모델 저장하고 불러오기

 


1. 신경망 모델 구성하기

FashionMNST 데이터셋의 이미지들을 분류하는 신경망을 구성해보자.

import os
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets, transforms

 

학습을 위한 장치 얻기

가능한 경우 GPU와 같은 하드웨어 가속기에서 모델을 학습하려고 한다. torch.cuda를 사용할 수 있는지 확인하고 그렇지 않으면 CPU를 계속 사용한다.

device = 'cuda' if torch.cuda.is_available() else 'cpu'
print('Using {} device'.format(device))

 

클래스 정의하기

신경망 모델을 nn.Module의 하위클래스로 정의하고, __init__에서 신경망 계층들을 초기화한다. nn.Module을 상속받은 모든 클래스는 forward 메소드에서 입력 데이터에 대한 연산들을 구현한다.

class NeuralNetwork(nn.Module):
    def __init__(self):
        super(NeuralNetwork, self).__init__()
        self.flatten = nn.Flatten()
        self.linear_relu_stack = nn.Sequential(
            nn.Linear(28*28, 512),
            nn.ReLU(),
            nn.Linear(512, 512),
            nn.ReLU(),
            nn.Linear(512, 10),
            nn.ReLU()
        )

    def forward(self, x):
        x = self.flatten(x)
        logits = self.linear_relu_stack(x)
        return logits
        
model = NeuralNetwork().to(device)

PyTorch 모델로 쓰기 위해서는 다음 두가지 조건을 따라야 한다. 내장된 모델(nn.Linear등)도 이를 만족한다.

1. torch.nn.Moduled을 상속해야 한다.

  • 상속(interitance): 어떤 클래스를 만들 때 다른 클래스의 기능을 그대로 가지고 오는 것.

2. __init()__과 forward()를 오버라이드(override)해야 한다.

  • 오버라이드(override): 부모 클래스(torch.nn.Module)에서 정의한 메서드를 자식 클래스에서 변경하는 것
  • __init()__에서는 모델에서 사용될 모듈(nn.Linear, nn.Conv2d 등)과 활성화 함수(nn.ReLU, nn.Sigmoid 등) 등을 정의한다.
  • forward()에서는 모델에서 실행되어야하는 계산을 정의한다. 즉 input을 넣어서 어떤 계산을 진행해 어떤 output이 나올지 정의해준다.
  • backward 계산은 backward()를 이용하면 PyTorch에서 알아서 실행해주기 때문에 forward()만 정의해주면 된다.

 

nn.Module

PyTorch의 nn라이브러리는 Neural Network의 모든 것을 포괄하는 모든 신경망 모델의 Base Class이다. 다른 말로, 모든 신경망 모델읜 nn.Module의 subclass라고 할 수 있다.

nn.Module을 상속한 subclass가 신경망 모델로 사용되기 위해서는 앞서 소개한 두 메서드를 override해야 한다.

  • __init__(self): 내가 사용하고 싶은, 내 신경망 모델에 사용될 요소들을 정의 및 초기화하는 메서드
  • forward(self, x): __init__에서 정의된 구성품들을 연결하는 메서드이다.

 

모델 계층(Layer)

아주 많다! 아래 참고하기~

https://pytorch.org/docs/stable/nn.html#module

 

torch.nn — PyTorch 1.10.0 documentation

Shortcuts

pytorch.org

 


2. 모델 매개변수 최적화하기

모델과 데이터가 준비되었으면, 데이터에 매개변수를 최적화하여 모델을 학습하고, 검증하고, 테스트할 차례이다. 모델을 학습하는 과정은 반복을 거친다. 에폭(epoch)이라고 부르는 각 반복 단계에서 모델을 출력을 추측하고, 추측과 정답 사이의 오류(손실)를 계산하고, 매개변수에 대한 오류의 도함수를 수집한 뒤, 경사하강법을 사용하여 파라미터들을 최적화한다.

 

기본(pre-requisite)코드

import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor, Lambda

training_data = datasets.FashionMNIST(
    root="data",
    train=True,
    download=True,
    transform=ToTensor()
)

test_data = datasets.FashionMNIST(
    root="data",
    train=False,
    download=True,
    transform=ToTensor()
)

train_dataloader = DataLoader(training_data, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)

class NeuralNetwork(nn.Module):
    def __init__(self):
        super(NeuralNetwork, self).__init__()
        self.flatten = nn.Flatten()
        self.linear_relu_stack = nn.Sequential(
            nn.Linear(28*28, 512),
            nn.ReLU(),
            nn.Linear(512, 512),
            nn.ReLU(),
            nn.Linear(512, 10),
            nn.ReLU()
        )

    def forward(self, x):
        x = self.flatten(x)
        logits = self.linear_relu_stack(x)
        return logits

model = NeuralNetwork()

 

하이퍼파라미터(Hyperparameter)

하이퍼파라미터는 모델 최적화 과정을 제어할 수 있는 조절 가능한 매개변수이다.

학습 시에는 다음과 같은 하이퍼파라미터를 정의한다.

  • 에폭(epoch) 수 - 데이터셋을 반복하는 횟수
  • 배치 크기(batch size) - 매개변수가 갱신되기 전 신경망을 통해 전파된 데이터 샘플의 수
  • 학습률(learning rate) - 각 배치/에폭에서 모델의 매개변수를 조절하는 비율. 값이 작을수록 학습 속도가 느려지고, 값이 크면 학습 중 예측할 수 없는 동작이 발생할 수 있다.

 

최적화 단계(Optimization Loop)

하이퍼파라미터를 설정한 뒤에는 최적화 단계를 통해 모델을 학습하고 최적화할 수 있다. 최적화 단계의 각 반복(iteration)을 에폭이라고 부른다.

하나의 에폭은 다음 두 부분으로 구성된다.

  • 학습 단계(train loop) - 학습용 데이터셋을 반복(iterate)하고 최적의 매개변수로 수렴한다.
  • 검증/테스트 단계(validation/test loop) - 모델 성능이 개선되고 있는지를 확인하기 위해 테스트 데이터셋을 반복(iterate)한다.

 

손실 함수(loss function)

일반적인 손실함수에는 회귀 문제에 사용하는 nn.MSELoss나 분류에 사용하는 nn.NLLLoss, 그리고 nn.CrossEntropyLoss등이 있다.

# 손실 함수 초기화
loss_fn = nn.CrossEntropyLoss()

 

옵티마이저(Optimizer)

학습하려는 모델의 매개변수와 학습률(learning rate) 하이퍼파라미터를 등록하여 옵티마이저를 초기화한다.

optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)

 

학습 단계(loop)에서 최적화는 세 단계로 이루어진다.

  • optimizer.zero_grad()를 호출하여 모델 매개변수의 변화도를 재설정한다. 기본적으로 변화도는 더해지기(add up) 때문에 중복 계산을 막기 위해 반복할 때마다 명시적으로 0으로 설정한다.
  • loss.backward()를 호출하여 예측 손실(prediction loss)을 역전파한다. PyTorch는 각 매개변수에 대한 손실의 변화도를 저장한다.
  • 변화도를 계산한 뒤에는 optimizer.step()을 호출하여 역전파 단계에서 수집된 변화도로 매개변수를 조정한다.

 

전체 구현

최적화 코드를 반복하여 수행하는 train_loop와 테스트 데이터로 모델의 성능을 측정하는 test_loop가 정의되었다.

def train_loop(dataloader, model, loss_fn, optimizer):
    size = len(dataloader.dataset)
    for batch, (X, y) in enumerate(dataloader):
        # 예측(prediction)과 손실(loss) 계산
        pred = model(X)
        loss = loss_fn(pred, y)

        # 역전파
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        if batch % 100 == 0:
            loss, current = loss.item(), batch * len(X)
            print(f"loss: {loss:>7f}  [{current:>5d}/{size:>5d}]")


def test_loop(dataloader, model, loss_fn):
    size = len(dataloader.dataset)
    num_batches = len(dataloader)
    test_loss, correct = 0, 0

    with torch.no_grad():
        for X, y in dataloader:
            pred = model(X)
            test_loss += loss_fn(pred, y).item()
            correct += (pred.argmax(1) == y).type(torch.float).sum().item()

    test_loss /= num_batches
    correct /= size
    print(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")

손실 함수와 옵티마이저를 초기화하고 train_loop test_loop에 전달한다. 모델의 성능 향상을 알아보기 위해 자유롭게 에폭(epoch) 수를 증가시켜 볼 수 있다.

loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)

epochs = 10
for t in range(epochs):
    print(f"Epoch {t+1}\n-------------------------------")
    train_loop(train_dataloader, model, loss_fn, optimizer)
    test_loop(test_dataloader, model, loss_fn)
print("Done!")

 


3. 모델 저장하고 불러오기

import torch
import torch.onnx as onnx
import torchvision.models as models

 

모델 가중치 저장하고 불러오기

PyTorch 모델은 학습한 매개변수를 state_dict라고 불리는 내부 상태 사전(internal state dictionary)에 저장한다. 이 상태 값들은 torch.save 메서드를 사용하여 저장(persist)할 수 있다.

model = models.vgg16(pretrained=True)
torch.save(model.state_dict(), 'model_weights.pth')

모델 가중치를 불러오기 위해서는, 먼저 동일한 모델의 인스턴스(instance)를 생성한 다음에 load_state_dict() 메서드를 사용하여 매개변수들을 불러온다.

model = models.vgg16() # 기본 가중치를 불러오지 않으므로 pretrained=True를 지정하지 않는다.
model.load_state_dict(torch.load('model_weights.pth'))
model.eval()

 

모델의 형태를 포함하여 저장하고 불러오기

모델의 가중치를 불러올 때, 신경망의 구조를 정의하기 위해 모델의 클래스를 먼저 생성(instantiate)해야 했다. 이 클래스의 구조를 모델과 함께 저장하고 싶으면, (model.state_dict()가 아닌) model을 저장 함수에 전달한다.

torch.save(model, 'model.pth')

다음과 같이 모델을 불러올 수 있다.

model = torch.load('model.pth')

 

관련글 더보기

댓글 영역