2.공부 목적으로 PyTorch 튜토리얼 홈페이지를 변역해보았습니다.
이전 포스팅에서 PyTorch module 없이 표준 python만을 사용하여 MNIST 데이터 셋에 대한 간단한 신경망을 구축했습니다.
이번에는 PyTorch의 torch.nn 을 사용해서 신경망을 구축해보겠습니다.
torch.nn.functional 사용하기
이제 코드를 재구성하겠습니다. 그럼으로써, 이전과 동일한 기능을 수행하고 모델을 더욱 정확하고 유연성있게 만드는 PyTorch의 nn 클래스의 이점을 활용할 것입니다.
여기서부터 매 단계에서, 코드를 더 짧고 이해하기 쉽고 유연하게 만들어야 합니다.
처음이면서 가장 쉬운 단계는 torch.nn.functional 의 함수(관례에 따라, 일반적으로 F 네임스페이스로 임포트합니다.)로 직접 작성한 활성화 함수, 손실함수를 대체하여 코드를 더 짧게 만들것 입니다.
이 모듈은 torch.nn 라이브러리(라이브러리의 다른 부분에는 클래스가 포함되어 있습니다.) 안에 있는 모든 함수를 포함합니다.
광범위한 손실, 활성화 함수뿐만 아니라 신경망을 생성하기 위한 풀링 함수와 같은 편리한 함수도 찾을 수 있습니다.
(합성곱, 신경망 등등을 하기위한 함수들이 있습니다. 하지만 이것들은 라이브러리의 다른 부분을 사용하여 더 잘 다룰 수 있습니다.)
만약 음의 우도 손실과 로그 소프트맥스 활성화함수를 사용한다면, Pytorch는 두 개를 결합한 F.croos_entropy 단일 함수를 제공합니다.
import torch.nn.functional as F
loss_func = F.cross_entropy
def model(xb):
return xb @ weights + bias
더이상 model 함수에 있는 log_softmax를 호출하지 않습니다.
손실과 정확도가 이전과 동일한지 확인하겠습니다.
print(loss_func(model(xb), yb), accuracy(model(xb), yb))
Out :
tensor(0.0827, grad_fn=<NllLossBackward>) tensor(1.)
nn.Module을 사용하여 코드를 재구성하기
다음으로, 명확하고 간결한 훈련 루프를 위해 nn.Module과 nn.Parameter를 사용하겠습니다.
nn.Module (이거 자체가 클래스이고 상태를 추적할 수 있는) 하위 클래스를 만듭니다.
이 경우에, 순전파 단계를 위한 가중치, 편향, 메소드를 갖고 있는 클래스를 생성해야 합니다.
nn.Module은 우리가 사용할 수 많은 속성과 메소드(.parameters()와 .zero_grad()와 같은)를 갖고 있습니다.
nn.Module (대문자 M)은 PyTorch의 특정 개념이고 많이 사용될 클래스입니다.
nn.Module은 임포트하기 위한 Python 코드 파일인 (소문자 m) module의 Python 개념과 헷갈리면 안됩니다.
from torch import nn
class Mnist_Logistic(nn.Module):
def __init__(self):
super().__init__()
self.weights = nn.Parameter(torch.randn(784, 10) / math.sqrt(784))
self.bias = nn.Parameter(torch.zeros(10))
def forward(self, xb):
return xb @ self.weights + self.bias
단지 함수를 사용하기보다 객체를 사용하기 때문에 모델을 인스턴스화 해야 합니다.
model = Mnist_Logistic()
이제 이전과 같은 방법으로 손실을 계산하겠습니다.
nn.Module 객체는 마치 함수처럼 사용되지만 배후에서 PyTorch는 forward 매소드를 자동으로 호출합니다.
print(loss_func(model(xb), yb))
Out :
tensor(2.3054, grad_fn=<NllLossBackward>)
이전에는 훈련 루프를 위해 이름 별로 각 매개변수의 값을 갱신해야 했고 각각의 매개변수에 대한 기울기를 개별적으로 수동으로 0으로 제거해야 했습니다.
with torch.no_grad():
weights -= weights.grad * lr
bias -= bias.grad * lr
weights.grad.zero_()
bias.grad.zero_()
만약 복잡한 모델을 갖고 있는 경우, 특히 매개변수를 잊어버리는 오류를 줄이고 각 단계를 더 정확하게 만들기 위해 model.parameters() 와 model.zero_grad() (둘 다 nn.Module에 대해 PyTorch에 의해 정의되었습니다.) 의 장점을 취하겠습니다.
with torch.no_grad():
for p in model.parameters(): p -= p.grad * lr
model.zero_grad()
이것을 나중에 다시 실행할 수 있도록 fit 함수 안에 작은 훈련 루프를 감쌀것입니다.
def fit():
for epoch in range(epochs):
for i in range((n - 1) // bs + 1):
start_i = i * bs
end_i = start_i + bs
xb = x_train[start_i:end_i]
yb = y_train[start_i:end_i]
pred = model(xb)
loss = loss_func(pred, yb)
loss.backward()
with torch.no_grad():
for p in model.parameters():
p -= p.grad * lr
model.zero_grad()
fit()
손실이 감소했는지 다시 한번 확인하겠습니다.
print(loss_func(model(xb), yb))
Out :
tensor(0.0801, grad_fn=<NllLossBackward>)
nn.Linear을 사용해서 재구성하기
계속해서 코드를 재구성하겠습니다.
수동으로 self.weights 와 self.bias 를 정의하고 초기화하고 xb @ self.weights + self.bias를 계산하는 대신에 이것들을 해내는 PyTorch 클래스인 nn.Linear를 선형 계층으로 사용하겠습니다.
PyTorch는 코드를 훨씬 간단히 할 수 있는 미리 정의된 계층의 많은 종류를 갖고 있습니다.
그리고 종종 코드를 더 빠르게 합니다.
class Mnist_Logistic(nn.Module):
def __init__(self):
super().__init__()
self.lin = nn.Linear(784, 10)
def forward(self, xb):
return self.lin(xb)
모델을 인스턴스화하고 이전과 동일한 방법으로 손실을 계산하겠습니다.
model = Mnist_Logistic()
print(loss_func(model(xb), yb))
Out :
tensor(2.3514, grad_fn=<NllLossBackward>)
여전히 이전과 동일한 fit 메서드를 사용할 수 있습니다.
fit()
print(loss_func(model(xb), yb))
Out :
tensor(0.0810, grad_fn=<NllLossBackward>)
optim 을 사용하여 재구성하기
PyTorch는 다양한 최적화 알고리즘을 가진 패키지, torch.optim 을 갖고 있습니다.
수동으로 각각의 매개변수를 갱신하는 대신에 optimizer의 step 메서드를 사용하여 순전파를 진행할 수 있습니다.
이것은 이전 수동으로 작성된 최적화 단계를 대체합니다.
with torch.no_grad():
for p in model.parameters(): p -= p.grad * lr
model.zero_grad()
또는 이렇게 사용해도 됩니다.
opt.step()
opt.zero_grad()
optim.zero_grad() 는 기울기를 0으로 재설정 합니다.
다음 미니배치에 대한 기울기를 계산하기전에 호출해야 합니다.
from torch import optim
추후에 재사용 할 수 있도록 모델과 optimizer를 생성하기 위한 작은 함수를 정의합니다.
def get_model():
model = Mnist_Logistic()
return model, optim,SGD(model.parameters(), lr=lr)
model, opt = get_model()
print(loss_func(model(xb), yb))
for epoch in range(epochs):
for i in range((n - 1) // bs + 1):
start_i = i * bs
end_i = start_i + bs
xb = x_train[start_i:end_i]
yb = y_train[start_i:end_i]
pred = model(xb)
loss = loss_func(pred, yb)
loss.backward()
opt.step()
opt.zero_grad()
print(loss_func(model(xb), yb))
Out :
tensor(2.3365, grad_fn=<NllLossBackward>)
tensor(0.0810, grad_fn=<NllLossBackward>)
'Python > PyTorch 공부' 카테고리의 다른 글
[PyTorch] 4. 검증(validation) 추가하고 fit() 와 get_data() 생성하기 (0) | 2020.12.09 |
---|---|
[PyTorch] 3. 파이토치 Dataset, DataLoader 를 사용하여 깔끔한 코드 작성하기 (0) | 2020.12.08 |
[Pytorch] 1. MNIST 데이터를 불러오고 파이토치 없이 신경망 구현하기 (0) | 2020.12.07 |
[PyTorch] 3. 예제로 배우는 파이토치 - nn 모듈, 가중치 공유, 제어 흐름, 사용자 정의 nn 모듈 (0) | 2020.12.07 |
[PyTorch] 2. 예제로 배우는 파이토치 - 자동미분(Autograd) (0) | 2020.12.07 |