안녕하세요 이번 포스트는 Pytorch를 다루도록 하겠습니다. Pytorch는 최근 들어 떠오르고 있는 딥러닝 API입니다. 텐서플로우가 2.0버전으로 업데이트하면서 케라스 기반으로의 변환을 시도하여 기존의 static한 특징에서 벗어나려는 모습을 보입니다. Pytorch는 텐서플로우와 달리 dynamic한 구조를 가지고 있는데요, 지금까지는 pytorch에 대해 잘 몰랐지만 방학도 한 기념으로! 한번 공부를 시작해보려 합니다.
저는 텐서플로우 공부의 시작을 유투브에 있는 Sung Kim님의 강좌로 시작하였는데요, 오랜만에 다시 그 분의 채널에 들어가보니 파이토치를 다룬 강좌도 생겼더라구요. 따라서 본 포스트는 Sung Kim님의 유투브 강좌 PytorchZeroToAll을 제 식대로 다시 정리한 글이라고 보시면 되겠습니다. 제 나름대의 정리이다보니 체계적이진 않다는 점을 유의하시기 바랍니다. 본 포스트에서 사용된 코드는 Sung Kim님이 작성하신 코드를 그대로 가져왔습니다.
Deep learning에서 가장 중요한 것은 정확한 학습을 통해 가중치를 구하는 것입니다. 대표적인 방법으로 Gradient descent 방식이 사용됩니다. 기울기 변화를 통해서 global한 최소의 loss로의 수렴을 기대하는 방식이지요.
Pytorch가 gradient descent 방식을 적용한 back propagation을 진행하는 방식은 아래와 같습니다. 핵심은 back propagation을 진행하는 l.backward() 와 그 값을 저장하는 w.grad가 되겠습니다
import torch
from torch.autograd import Variable
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
w = Variable(torch.Tensor([1.0]), requires_grad=True) # Any random value
# our model forward pass
def forward(x):
return x * w
# Loss function
def loss(x, y):
y_pred = forward(x)
return (y_pred - y) * (y_pred - y)
# Before training
print("predict (before training)", 4, forward(4).data[0])
# Training loop
for epoch in range(10):
for x_val, y_val in zip(x_data, y_data):
l = loss(x_val, y_val)
# backward operation을 진행시키는 함수
l.backward()
print("\tgrad: ", x_val, y_val, w.grad.data[0])
w.data = w.data - 0.01 * w.grad.data
# Manually zero the gradients after updating weights
w.grad.data.zero_()
print("progress:", epoch, l.data[0])
# After training
print("predict (after training)", 4, forward(4).data[0])
파이토치를 사용한 모델 활용은 아래와 같은 세 단계로 진행됩니다.
initializer 부분과 forward 부분으로 구성된 class를 구축합니다. Initializer에서는 모델에 맞는 구조를 생성하는데 본 예제에서는 단순 선형모델을 사용하기에 linear 모델만을 사용했습니다. torch.nn.Linear(1,1) 에서 앞에 1은 Input size를, 뒤의 1은 Output size를 의미합니다. forward 부분에서는 x를 요소로 하여 예측값 y_pred를 출력할 수 있도록 initializer부분에서 정의한 self.Linear 함수를 사용하게됩니다.
import torch
from torch.autograd import Variable
x_data = Variable(torch.Tensor([[1.0], [2.0], [3.0]]))
y_data = Variable(torch.Tensor([[2.0], [4.0], [6.0]]))
class Model(torch.nn.Module):
def __init__(self):
"""
In the constructor we instantiate two nn.Linear module
"""
super(Model, self).__init__()
self.linear = torch.nn.Linear(1, 1) # One in and one out
def forward(self, x):
"""
In the forward function we accept a Variable of input data and we must return
a Variable of output data. We can use Modules defined in the constructor as
well as arbitrary operators on Variables.
"""
y_pred = self.linear(x)
return y_pred
# our model
model = Model()
criterion과 optimizer로 대표되는 부분입니다. torch의 API에서 해당하는 loss function과 optimizer를 선정합니다. 본 예제에서는 MSE loss와 SGD optimizer를 사용하였고 optimizer에서 최적화될 대상으로 모델의 파라미터인 model.parameter를 선정하였습니다.
# Construct our loss function and an Optimizer. The call to model.parameters()
# in the SGD constructor will contain the learnable parameters of the two
# nn.Linear modules which are members of the model.
criterion = torch.nn.MSELoss(size_average=False)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
학습 단계를 의미합니다. forward, backward 단계를 거쳐 epoch만큼 횟수로 파라미터의 최적화가 진행됩니다.
# Training loop
for epoch in range(500):
# Forward pass: Compute predicted y by passing x to the model
y_pred = model(x_data)
# Compute and print loss
loss = criterion(y_pred, y_data)
print(epoch, loss.data)
# Zero gradients, perform a backward pass, and update the weights.
optimizer.zero_grad()
loss.backward()
optimizer.step()
Testing Model
학습이 끝난 후 모델의 성능을 알기 위해 Test를 해야합니다.
# After training
hour_var = Variable(torch.Tensor([[4.0]]))
y_pred = model(hour_var)
print("predict (after training)", 4, model.forward(hour_var).data[0][0])
기본적으로 위와 같은 단계로 진행이 되며 더 복잡한 구조를 구축할 경우에도 첫번째 단계에서 복잡한 모델을 잘 구축한다면 pytorch를 잘 활용할 수 있겠습니다.