Home [BoostCamp AI Tech / PyTorch] Day7 - AutoGrad & Optimizer
Post
Cancel

[BoostCamp AI Tech / PyTorch] Day7 - AutoGrad & Optimizer

PyTorch : AutoGrad & Optimizer


Introduction

  • 다양한 논문들이 제공하고 있는 모델들은 레이어들의 연속체이다.
  • 이런 레이어들은 일종의 블록이랑 같다고 생각하면 편하다.

  • ResNet이나 transformer처럼 여러개의 레이어를 합쳐서 큰 규모의 레이어를 구성할 수도 있다.
  • 이렇게 모델을 구현할 때 pytorch의 torch.nn.Module을 사용한다.

Model 만들기

torch.nn.Module

  • 딥러닝을 구성하는 Layer의 base class이다.
  • input, output은 선택적으로 정의하는 경우가 많지만 forward, backward는 직접 정의하는 경우가 많다.
    • backward에서 AutoGrad를 통해 weight에 대한 미분을 진행한다.
  • 학습의 대상이 되는 weight나 bias같은 파라미터들도 정의한다.

  • 모델에서 사용한 그래프는 forwar에서는 연산을 위한 공식에 입력값들을 적용시킨다.
  • backward에서는 loss 값을 계산하여 각 parameter에 맞춰 편미분을 진행해서 parameter update를 진행한다.

nn.Parameter

  • Tensor 객체의 상속 객체이다. 실제로 torch.nn.Parameter의 소스코드 링크에 들어가면 torch.Tensor를 상속하고 있다.
  • 일반적으로 nn.Module내에서 attribute가 되면 required_grad=True로 지정되어 학습의 대상이 되는 Tensor이다.
  • 직접 Parameter를 지정할 일은 잘 없다. Linear, Conv같은 구현된 레이어들에 이미 Parameter로 정의된 변수들이 있기 때문에 직접 정의할 일은 없다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class MyLinear(nn.Module):
    def __init__(self, in_features, out_features, bias=True):
        super().__init__()
        
        self.in_features = in_features
        self.out_features = out_features

        self.weights = nn.Parameter(
            torch.randn(in_features, out_features)
        )
        self.bias = nn.Parameter(torch.randn(out_features))
    
    def forward(self, x : Tensor):
        return x @ self.weights + self.bias

x = torch.randn(3, 4)
fc = MyLinear(4, 12)
fc(x)

'''
tensor([[ 1.0335, -2.9261,  0.1745,  3.4936, -0.1151,  2.7729,  1.3236, -0.8619,
         -2.3663,  1.0498, -3.7553,  2.7351],
        [ 1.9231, -0.9690,  0.5683,  2.5309,  2.3729,  0.3830, -3.4628,  1.4042,
         -3.5674, -3.6533, -0.6249,  1.2501],
        [ 4.5484, -1.5726,  5.9213,  0.3171, -1.4282,  0.9741, -2.0159, -1.4090,
         -2.4930, -1.4857, -1.5419, -0.2907]], grad_fn=<AddBackward0>)
'''
  • 이 코드는 간단한 선형식인 $XW+b$를 구현한 모델이다.
  • 여기서 nn.Parameter의 역할은 torch.Tensor와 출력자체는 동일하게 나타난다.
    1
    2
    3
    4
    5
    6
    7
    8
    
      print(torch.nn.Parameter(torch.Tensor([1, 2, 3])))
      print(torch.Tensor([1, 2, 3]))
      '''
      Parameter containing:
      tensor([1., 2., 3.], requires_grad=True)
    
      tensor([1., 2., 3.])
      '''
    

    근데 우리가 구현한 모델의 메소드 중 parameters()라는 메소드가 있는데, 이 메소드를 수행하면 Parameter로 선언된 변수의 학습된 파라미터들 값을 볼 수 있다.
    하지만 Tensor로 구현하면 torch.nn.Module에 있는 파라미터 리스트에 등록되지 않아 확인할 수 없다.

  • 또 한가지 특이한 점은 단순히 객체를 호출했는데 값을 보내주는 forward가 수행된 것을 알 수 있다.
    이는 torch.nn.Module의 내부 코드원리 때문인데 nn.Module의 공식문서에서 _call_impl부분을 보면 self.forward를 호출하는 것을 알 수 있다.
    참고로 _call_imp은 함수 호출시 동작하는 함수인 __call__의 구현부이다.

Backward

  • lyaer에 있는 Parameter들의 미분을 수행한다.
  • forward의 결과인 predict 값($\hat{y}$)과 실제 값 $y$의 차이인 loss function의 값을 활용하여 미분을 수행한다. 이 과정에서는 AutoGrad를 통해 미분을 진행한다.
  • 계산된 값으로 Parameter의 업데이트를 진행한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import torch
from torch.autograd import Variable

class LinearReg(torch.nn.Module):
    def __init__(self, inputSize, outputSize):
        super(LinearReg, self).__init__()
        self.linear = torch.nn.Linear(inputSize, outputSize)

    def forward(self, x):
        out = self.linear(x)
        return out

input_size = 1        # takes variable 'x' 
output_size = 1       # takes variable 'y'
lr = 0.01 
epochs = 100

model = LinearReg(input_size, output_size)

criterion = torch.nn.MSELoss() 
optimizer = torch.optim.SGD(model.parameters(), lr=lr)

for epoch in range(epochs):
    inputs = Variable(torch.from_numpy(x_train))
    labels = Variable(torch.from_numpy(y_train))

    optimizer.zero_grad()

    outputs = model(inputs)
    loss = criterion(outputs, labels)

    loss.backward()
    optimizer.step()

    print(f'epoch {epoch}, loss { loss.item() }')
  • optimizer.zero_grad()는 기존의 gradient를 학습에 영향이 가지 않게 초기화하는 과정이다.
  • outputs = model(inputs)forward가 호출되므로 $\hat{y}$을 계산하는 과정이다.
  • loss = criterion(outputs, labels)는 오차값을 계산하는 loss function 처리구간이다. 여기서는 Mean Squared Error를 사용했다.
  • loss.backward()optimizer.step()부분이 중요하다.
    loss.backward()는 backward에서 미리 선언한 optimizer로 AutoGrad 과정을 통해 미분을 진행한다.
    그리고 optimizer.step()은 weight를 update하는 부분이다.
  • backward도 Module단계에서 직접 지정이 가능한데 잘 그러지는 않는다.
    • 보통 backwardoptimizer는 오버라이딩으로 진행된다.
This post is licensed under CC BY 4.0 by the author.

[BoostCamp AI Tech / PyTorch] Day6 - PyTorch 프로젝트 구조 이해하기

[BoostCamp AI Tech / PyTorch] Day7 - Datasets & Dataloaders

Comments powered by Disqus.