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단계에서 직접 지정이 가능한데 잘 그러지는 않는다.- 보통
backward
와optimizer
는 오버라이딩으로 진행된다.
- 보통
Comments powered by Disqus.