<목차> 1. torch.nn.Module => 기본적으로 PyTorch에 구현되어있는 네트워크 텐서 모듈을 살펴보자! nn.Parameter : Tensor VS Parameter => nn.Parameter이 Module 내부에서 어떤 역할을 하는 지 알아보자! backward 작동 방식 2. AutoGrad for Linear Regression [code] 3. AutoGrad 없이 LR[code]
하나의 딥러닝은 수 많은 Layer (= Block)의 반복
torch.nn.Module
Layer의 base class
input, output, forward, backward를 정의함
backward는 autograd 이용 -> weight가 학습의 대상이 되는 데, 이를 parameter(tensor)로 정의
가장 일반적인 모듈 구성
nn.Parameter
- Tensor 객체의 상속 객체
- nn.Module 내에 attribute가 될 때는 required_grad=True 로 지정되어 학습 대상이 되는 Tensor
- 우리가 직접 지정할 일은 잘 없음 : 대부분의 layer에는 weights 값들이 지정되어 있음
# low level API
import torch
from torch import nn
from torch import Tensor
class MyLiner(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 # y hat이라고 생각
for value in layer.parameters():
print(value)
# 아무것도 출력 안됨
# parameter은 미분의 대상이 되는 것만
Backward
- Layer에 있는 Parameter들의 미분을 수행 - Forward의 결과값 (model의 output = 예측치 = y hat)과 실제값간의 차이(loss) 에 대해 미분을 수행 - 해당 값으로 Parameter 업데이트
Autograd를 할 때 Backward라는 함수가 호출됨
for epoch in range(epochs):
… …
#Clear gradientbuffers becausewe don'twant anygradient fromprevious epoch tocarry forward
optimizer.zero_grad() # *이전의 gradient값이 영향을 주지 않도록
#get output from the model, given thei nputs
outputs = model(inputs) # *y hat 값이 나옴
#get loss for the predicted output
loss = criterion(outputs,labels) # labels는 y임
print(loss)
#get gradients w.r.t to parameters
loss.backward()
# update parameters optimize
optimizer.step()
optimizer.zero_grad() : 이전 step에서 각 layer 별로 계산된 gradient 값을 모두 0으로 초기화 시키는 작업입니다. 0으로 초기화 하지 않으면 이전 step의 결과에 현재 step의 gradient가 누적으로 합해져서 계산
loss.backward() : 각 layer의 파라미터에 대하여 back-propagation을 통해 gradient를 계산
optimizer.step() : 각 layer의 파라미터와 같이 저장된 gradient 값을 이용하여 파라미터를 업데이트. 이 명령어를 통해 파라미터가 업데이트되어 모델의 성능이 개선.
AutoGrad for Linear Regression 최종 코드
y = 2*x+1
import numpy as np
# create dummy data for training
x_values = [i for i in range(11)]
x_train = np.array(x_values, dtype=np.float32)
x_train = x_train.reshape(-1, 1)
y_values = [2*i + 1 for i in x_values]
y_train = np.array(y_values, dtype=np.float32)
y_train = y_train.reshape(-1, 1)
import torch
from torch.autograd import Variable
class LinearRegression(torch.nn.Module):
def __init__(self, inputSize, outputSize):
super(LinearRegression, self).__init__()
self.linear = torch.nn.Linear(inputSize, outputSize)
def forward(self, x):
out = self.linear(x)
return out
inputDim = 1 # takes variable 'x'
outputDim = 1 # takes variable 'y'
learningRate = 0.01
epochs = 100
model = LinearRegression(inputDim, outputDim)
##### For GPU #######
if torch.cuda.is_available():
model.cuda()
criterion = torch.nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=learningRate) # 대상이 되는 parameter
for epoch in range(epochs):
# *모든 값을 한 번에 넣고 돌림(보통은 dataloader을 가지고 잘라서 넣음)
# Converting inputs and labels to Variable
if torch.cuda.is_available():
inputs = Variable(torch.from_numpy(x_train).cuda())
labels = Variable(torch.from_numpy(y_train).cuda())
else:
inputs = Variable(torch.from_numpy(x_train))
labels = Variable(torch.from_numpy(y_train))
# Clear gradient buffers because we don't want any gradient from previous epoch
# to carry forward, dont want to cummulate gradients
optimizer.zero_grad()
# get output from the model, given the inputs
outputs = model(inputs)
# get loss for the predicted output
loss = criterion(outputs, labels)
print(loss)
# get gradients w.r.t to parameters
loss.backward() # *위에 작성한 SGD로 미분
# update parameters
optimizer.step()
print('epoch {}, loss {}'.format(epoch, loss.item()))
<순서> 1. loss 계산 2. loss.backward()로 gradient 계산 3. optimizer.step()으로 weight 갱신
가중치 갱신 순서 : 뉴럴네트워크의 출력값과 라벨 값을 loss 함수를 이용하여 계산을 하고 그 loss 함수의 backward() 연산을 한 뒤에 optimizer.step()을 통해 weight를 업데이트
Q. loss와 optimizer은 어떤 관계로 연결되어있어서 loss를 통해 계산한 gradient를 optimizer로 가중치 갱신을 할 수 있을까?
A. optimizer와 loss.backward()는 같은 model 객체를 사용함. 그리고 loss.backward()의 출력값이 각 model의 layer의 grad 멤버 변수에 저장되고 이 값을 optimizer의 입력값으로 사용함으로써 두 연산이 연결됨.
ex) loss.backward()가 실행되면 gradient는 model.layer1.weight.grad에 저장된다. 그리고 optimizer 객체는 model.parameter()를 통해 생성됐기 때문에 model.layer1.weight.grad에 저장된 gradient에 바로 접근하여 사용 가능.
with torch.no_grad(): # we don't need gradients in the testing phase
if torch.cuda.is_available():
predicted = model(Variable(torch.from_numpy(x_train).cuda())).cpu().data.numpy()
else:
predicted = model(Variable(torch.from_numpy(x_train))).data.numpy()
print(predicted)
for p in model.parameters():
if p.requires_grad:
print(p.name, p.data)
'''
None tensor([[2.0985]])
None tensor([0.3158])
'''
실제 backward는 module 단계에서 직접 지정 가능하나 Autograd가 있어서 굳이 그럴 필요 없음
직접 지정하려면 backward와 optimizer 오버라이딩해야함
Logistic Regulation
logistic regulation은 sigmoid의 g 대신 x, 세타, weight, x의 linear combination을 넣어준 것임