728x90

모델에 대한 평가는 함수와 모듈을 이용하는 두 가지 방법이 있다.

1. 함수를 이용하여 모델을 평가하는 방법

import torch
import torchmetrics

preds = torch.randn(10, 5).softmax(dim=-1)
target = torch.randint(5, (10,))

acc = torchmetrics.functional.accuracy(preds, target) # 모델을 평가하기 위해 torchmetrics.functional.accuracy 이용

2. 모듈을 이용하여 모델을 평가하는 방법

import torch
import torchmetrics
metric = torchmetrics.Accuracy()

n_batchs = 10
for i in range(n_batchs):
    preds = torch.randn(10, 5).softmax(dim=-1)
    target = torch.randint(5, (10,))
    
    acc = torchmetrics.functional.accuracy(preds, target)
    print(f'accuracy on batch {i}: {acc}') # 현재 배치에서 모델 정확도
    
acc = metric.compute()
print(f'accuracy no all data: {acc}') # 모든 배치에서 모델 평가

 

혹은 사이킷런에서 제공하는 confusion metrix를 이용하는 방법도 고려해 볼 수 있다.

728x90

'딥러닝 > Pytorch' 카테고리의 다른 글

Pytorch nn.ModuleList  (0) 2022.05.30
Pytorch nn.Embedding()  (0) 2022.05.30
Pytorch 기본 문법 - 모델 훈련  (0) 2022.05.23
Pytorch 기본 문법 - 파라미터 정의  (0) 2022.05.23
Pytorch 기본 문법 - 모델 정의  (0) 2022.05.23
728x90

구체적인 훈련 방법에 대해 알아보자. 가장 먼저 필요한 절차가 optimizer.zero_grad() 메서드를 이용하여 기울기를 초기화하는 것이다. 파이토치는 기울기 값을 계산하기 위해 loss.backward() 메서드를 이용하는데, 이것을 사용하면 새로운 기울기 값이 이전 기울기 값에 누적하여 계산된다. 

이 방법은 순환 신경망 모델을 구현할 때 효과적이지만 누적 계산이 필요하지 않은 모델에 대해서는 불필요하다. 따라서 기울기 값에 대해 누적 계산이 필요하지 않을 때는 입력 값을 모델에 적용하기 전에 optimizer.zero_grad() 메서드를 호출하여 미분 값이 누적되지 않게 초기화해 주어야 한다.

 

딥러닝 학습 절차 파이토치 학습 절차
모델, 손실 함수, 옵티마이저 정의 모델, 손실 함수, 옵티마이저 정의
optimizer.zero_grad( ):
전방향 학습, 기울기 초기화
전방향 학습 (입력 -> 출력 계산) output = model(input) : 출력 계산
손실 함수로 출력과 정답의 차이 계산 loss = loss_fn(output, target) : 오차 계산
역전파 학습 loss.backward( ) : 역전파 학습
기울기 업데이트 optimizer.step( ) : 기울기 업데이트

 

다음은 loss.backward() 메서드를 이용하여 기울기를 자동 계산한다. loss_backward()는 배치가 반복될 때마다 오차가 중첩적으로 쌓이게 되므로 매번 zero_grad()를 사용하여 미분 값을 0으로 초기화한다.

다음은 모델을 훈련시키는 예시 코드이다.

for epoch in range(100):
    yhat = model(x_train)
    loss = criterion(yhat, y_train)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
728x90
728x90

모델을 학습하기 전에 필요한 파라미터들을 정의한다. 사전에 정의할 파라미터는 다음과 같다.

  • 손실 함수 : 학습하는 동안 출력과 실제 값 사이의 오차를 측정한다. 손실 함수로 많이 사용되는 것은 다음과 같다.
    • BCELoss : 이진 분류를 위해 사용
    • CrossEntropyloss : 다중 클래스 분류를 위해 사용
    • MSELoss : 회귀 모델에서 사용
  • 옵티마이저 : 데이터와 손실 함수를 바탕으로 모델의 업데이트 방법을 결정한다. 다음은 옵티마이저의 주요 특성이다.
    • optimizer는 step() 메서드를 통해 전달받은 파라미터를 업데이트한다.
    • 모델의 파라미터별로 다른 기준을 적용시킬 수 있다.
    • torch.optim.Optimizer (params, defaults)는 모든 옵티마이저의 기본이 되는 클래스이다.
    • zero_grad() 메서드는 옵티마이저에 사용된 파라미터들의 기울기를 0으로 만든다.
    • torch.optim.lr_scheduler는 에포크에 따라 학습률을 조절할 수 있다.
  • 학습률 스케줄러 : 미리 지정한 횟수의 에포크를 지날 때마다 학습률을 감소시켜 준다. 학습률 스케줄러를 이용하면 학습 초기에는 빠른 학습을 진행하다가 전역 최소점ㅇ 근처에 다다르면 학습률을 줄여서 최적점을 찾아갈 수 있도록 해준다. 학습률 스케줄러의 종류는 다음과 같다.
    • optim.lr_scheduler.StepLR : 람다 함수를 이용하여 그 함수의 결과를 학습률로 설정한다.
    • optim.lr_scheduler.MultiStepLR : StepLR과 비슷하지만 특정 단계가 아닌 지정된 에포크에만 감마 바율로 감소시킨다.
    • optim.lr_scheduler.ExponentialLR : 에포크마다 이전 학습률에 감마만큼 곱한다.
    • optim.lr_scheduler.CosineAnnealingLR : 학습률을 코사인함수의 형태처럼 변화시킨다. 따라서 학습률이 커지기도 작아지기도 한다.
    • optim.lr_scheduler.ReduceLROnPlateau : 학습이 잘되고 있는지 아닌지에 따라 동적으로 학습률을 변화시킬 수 있다.

 

다음은 모델의 파라미터를 정의하는 예시 코드이다.

from torch.optim import optimizer

criterion = torch.nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer=optimizer, 
                                              lr_lambda=lambda eopch: 0.95 ** epoch)

for eopch in range(1, 100+1): # 에포크 수만큼 데이터를 반복하여 처리
    for x, y in dataloader: # 배치 크기만큼 데이터를 가져와서 학습 진행
        optimizer.zero_grad()

loss_fn(model(x), y).backward()
optimizer.step()
scheduler.step()
728x90
728x90

파이토치에서 모델을 정의하기 위해서는 Module을 상속한 클래스를 사용한다. 모델과 모듈의 차이는 무엇일까?

  • 계층(layer) : 모듈 또는 모듈을 구성하는 한 개의 계층으로 합성곱층, 선형계층 등이 있다.
  • 모듈(module) : 한 개 이상의 계층이 모여서 구성된 것으로, 모듈이 모여 새로운 모듈을 만들 수도 있다.
  • 모델(model) : 최종적으로 원하는 네트워크로, 한 개의 모듈이 모델이 될 수도 있다.

1. 단순 신경망을 정의하는 방법

nn.Module을 상속받지 않는 매우 단순한 모델을 만들 때 사용한다. 구현이 쉽고 단순하다는 장점이 있다.

model = nn.Linear(in_features=1, out_features=1, bias=True)

2. nn.Module()을 상속하여 정의하는 방법

파이토치에서 nn.Module을 상속받는 모델은 기본적으로 __init__()과 forward() 함수를 포함한다. __init__()에서는 모델에서 사용될 모듈, 활성화 함수 등을 정의하고, forward() 함수에서는 모델에서 실행되어야 하는 연산을 정의한다.

다음은 파이토치에서 모델을 정의하는 코드이다.

class MLP(Module):
    def __init__(self, inputs):
        super(MLP, self).__init__()
        self.layer = Linear(inputs, 1) # 계층 정의
        self.activation = Sigmoid() # 활성화 함수 정의
        
    def forward(self, X):
        X = self.layer(X)
        X = self.activation(X)
        return X

3. Sequential 신경망을 정의하는 방법

nn.Sequential을 사용하면 __init__()에서 사용할 네트워크 모델들을 정의해 줄 뿐만 아니라 forward() 함수에서는 모델에서 실행되어야 할 계산을 좀 더 가독성이 뛰어나게 코드로 작성할 수 있다.

또한, Sequential 객체는 그 안에 포함된 각 모듈을 순차적으로 실행해 주는데 다음과 같이 코드를 작성할 수 있다.

import torch.nn as nn

class MLP(nn.Module):
    def __init__(self):
        super(MLP, self).__init__()
        self.layer1 = nn.Sequential(
            nn.Conv2d(in_channels=3, out_channels=64, kernel_size=5),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(2))
        
        self.layer2 = nn.Sequential(
            nn.Conv2d(in_channels=3, out_channels=64, kernel_size=5),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(2))
        
        self.layer3 = nn.Sequential(
            nn.Linear(in_features=30*5*5, out_features=10, bias=True),
            nn.ReLU(inplace=True))
        
        
        def forward(self, x):
            x = self.layer1(x)
            x = self.layer2(x)
            x = x.view(x.shape[0], -1)
            x = self.layer3(x)
            
            return x
        
model = MLP()

print('printing children \n-------------------------')
print(list(model.children()))
print('\n\nprinting Modules\n-------------------------')
print(list(model.modules()))
printing children 
-------------------------
[Sequential(
  (0): Conv2d(3, 64, kernel_size=(5, 5), stride=(1, 1))
  (1): ReLU(inplace=True)
  (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
), Sequential(
  (0): Conv2d(3, 64, kernel_size=(5, 5), stride=(1, 1))
  (1): ReLU(inplace=True)
  (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
), Sequential(
  (0): Linear(in_features=750, out_features=10, bias=True)
  (1): ReLU(inplace=True)
)]


printing Modules
-------------------------
[MLP(
  (layer1): Sequential(
    (0): Conv2d(3, 64, kernel_size=(5, 5), stride=(1, 1))
    (1): ReLU(inplace=True)
    (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (layer2): Sequential(
    (0): Conv2d(3, 64, kernel_size=(5, 5), stride=(1, 1))
    (1): ReLU(inplace=True)
    (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (layer3): Sequential(
    (0): Linear(in_features=750, out_features=10, bias=True)
    (1): ReLU(inplace=True)
  )
), Sequential(
  (0): Conv2d(3, 64, kernel_size=(5, 5), stride=(1, 1))
  (1): ReLU(inplace=True)
  (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
), Conv2d(3, 64, kernel_size=(5, 5), stride=(1, 1)), ReLU(inplace=True), MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False), Sequential(
  (0): Conv2d(3, 64, kernel_size=(5, 5), stride=(1, 1))
  (1): ReLU(inplace=True)
  (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
), Conv2d(3, 64, kernel_size=(5, 5), stride=(1, 1)), ReLU(inplace=True), MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False), Sequential(
  (0): Linear(in_features=750, out_features=10, bias=True)
  (1): ReLU(inplace=True)
), Linear(in_features=750, out_features=10, bias=True), ReLU(inplace=True)]

 

Note. model.modules() & model.children()

model.modules()는 모델의 네트워크에 대한 모든 노드를 반환하며, model.children()은 같은 수준의 하위 노드를 반환한다.

728x90

'딥러닝 > Pytorch' 카테고리의 다른 글

Pytorch 기본 문법 - 모델 훈련  (0) 2022.05.23
Pytorch 기본 문법 - 파라미터 정의  (0) 2022.05.23
Pytorch 기본 문법 - 데이터 준비  (1) 2022.05.18
Pytorch 기본 문법 - 텐서  (0) 2022.05.18
Pytorch 개요  (0) 2022.05.18
728x90

1. 커스텀 데이터셋을 만들어서 이용

딥러닝은 기본적으로 대량의 데이터를 이용하여 모델을 학습시킨다. 하지만 데이터를 한 번에 메모리에 불러와서 훈련시키면 시간과 비용 측면에서 비효율적이다. 따라서 데이터를 한 번에 다 부르지 않고 조금씩 나누어 불러서 사용하는 방식이 커스텀 데이터셋(custom dataset)이다.

먼저 CustomDataset 클래스를 구현하기 위해서는 다음 형태를 취해야 한다.

class CustomDataset(torch.utils.data.Dataset):
    def __init__(self): # 필요한 변수를 선언하고, 데이터셋의 전처리를 해 주는 함수
    def __len__(self): # 데이터셋의 길이. 즉, 총 샘플의 수를 가져오는 함수
    def __getitem__(self, index): # 데이터셋에서 특정 데이터를 가져오는 함수 (index번째 데이터를 반환하는 함수이며, 이때 반환되는 값은 텐서의 형태를 취해야 함)

커스텀 데이터셋 구현 방법에 대해 예제를 통해 구체적으로 알아보자.

import pandas as pd
import torch
from torch.utils.data import Dataset
from torch.utils.data import DataLoader

class CustomDataset(Dataset):
    def __init__(self, csv_file): # csv_file 파라미터를 통해 데이터셋을 불러온다.
        self.label = pd.read_csv(csv_file)
        
    def __len__(self): # 전체 데이터셋의 크기를 반환한다.
        return len(self.label)
    
    def __getitem__(self, idx): # 전체 x와 y 데이터 중에 해당 idx번째의 데이터를 가져온다.
        sample = torch.tensor(self.label.iloc[idx, 0:3]).int()
        label = torch.tensor(self.label.iloc[idx, 3]).int()
        return sample, label
    
tensor_dataset = CustomDataset('../covtype.csv') # 데이터셋으로 covtype.csv를 사용한다.
dataset = DataLoader(tensor_dataset, batch_size=4, shuffle=True)

Note. torch.utils.data.DataLoader

DataLoader 객체는 학습에 사용될 데이터 전체를 보관했다가 모델 학습을 할 때 배치 크기만큼 데이터를 꺼내서 사용한다. 이때 주의할 것은 데이터를 미리 잘라 놓는 것이 아니라 내부적으로 iterator에 포함된 인덱스를 이용하여 배치 크기만큼 데이터를 반환한다는 것이다.

출처 :http://bit.ly/PyTorchZeroAll

 

 

 

728x90

'딥러닝 > Pytorch' 카테고리의 다른 글

Pytorch 기본 문법 - 모델 훈련  (0) 2022.05.23
Pytorch 기본 문법 - 파라미터 정의  (0) 2022.05.23
Pytorch 기본 문법 - 모델 정의  (0) 2022.05.23
Pytorch 기본 문법 - 텐서  (0) 2022.05.18
Pytorch 개요  (0) 2022.05.18

+ Recent posts