제정신은코딩에해로워 2020. 12. 29. 00:21

TensorFlow를 적당히 듣다가, 이제와서 Pytorch로 다시 듣기 시작했다. 참으로 게으른 사람일 수가 없지만

어쩌겠나, 지금부터라도 열심히 해야지

 

여러가지를 배우면서 Linear Regression model을 class 형태로 작성해보았다. 

Linear Regression은 y = x * w + b 의 선형 함수를 찾아가는 과정이라고 볼 수 있다.

import torch
from torch import nn
import matplotlib.pyplot as plt
import numpy as np

# y = 0.5x + 1 를 얻기위함
x_np = np.arange(0, 10, 1)
y_np = []
for x_val in x_np:
    noise = np.random.normal(0.5, 0.5)
    new_x = x_val + noise
    y_np = np.append(y_np, 0.5*new_x + 1)

먼저 라이브러리들을 부르고, numpy를 사용해서 noise가 포함된 10개의 데이터를 생성했다. y = 0.5x + 1의 그래프를 만들기 위함이다. 

x = torch.from_numpy(x_np).float()
y = torch.from_numpy(y_np).float()
x = x.unsqueeze(1)
y = y.unsqueeze(1)

데이터는 1차원 배열로 되어있는데, [[1. ],[2. ],[3. ],[4. ]...]의 2차원 형태로 바꾸어주어야 한다. 정확히는 1차원 텐서를 늘어뜨린 모양으로 바꿔주어야 하기 때문에 unsqueeze를 사용한다.

plt.xlim(0, 11); plt.ylim(0, 8)
plt.title('Linear Regression Model')
plt.scatter(x,y)

다음과 같은 데이터가 만들어졌다. 노이즈를 평균 0.5, 표준편차 0.5인 normal distribution으로 설정하였기에, 아무래도 노이즈가 커보인다.

class Model(nn.Module):
    def __init__(self):
        super(Model, self).__init__()
        self.linear = torch.nn.Linear(1,1, bias=True)
        self.weight = self.linear.weight
        self.bias = self.linear.bias
        
    def forward(self, x):
        return self.linear(x)

실제로 이제 모델을 만들었다. weight와 bias를 사용하기 위해서 따로 저장했으며, forward는 원래는 x*w + b의 꼴일 것이다. 이를 PyTorch에 있는 Linear를 사용하였다. (아직 정확한 의미 파악 못했음)

model = Model()
criterion = torch.nn.MSELoss(reduction='sum')
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)

for epoch in range(500):
    y_pred = model(x)
    loss = criterion(y_pred, y)
    if epoch % 10 == 0:
        print(f'Epoch: {epoch} | Loss: {loss.item()}')
        
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

loss function을 설정하고, optimizer로 adam을 사용했다. SGD를 사용하는 경우 loss가 INF가 되는데, 수렴되지 못하고 진동이 커져서 그런가 싶다. (2변수 이상일 때는 SGD가 효과적이지 않을까)

 

  • optimizer.zero_grad(): PyTorch는 parameter의 gradient 계신 시 grad를 계속 누적해서 더한다. 그렇기 때문에 매 계산에서 초기화 해주어야한다.
  • loss.backward(): gradient 계산을 back propagation한다. 
  • optimizer.step(): 계산한 gradient로 param을 업데이트 한다. ( w <- w + αΔw, b <- b +  αΔb)
print(4, model(torch.tensor([[4.0]])).data[0][0].item())

 

x가 4일 때 값을 확인해보면 3.14 정도 나오게 된다. (실제 값은 3.39)

def display_results(model, x, y):
    prediction = model(x)
    loss = criterion(input=prediction, target=y)
    
    plt.clf()
    plt.xlim(0, 11); plt.ylim(0, 8)
    plt.scatter(x.data.numpy(), y.data.numpy())
    plt.plot(x.data.numpy(), prediction.data.numpy(), 'b--')
    plt.title('loss={:.4}, w={:.4}, b={:.4}'.format(loss.data.item(), model.weight.data.item(), model.bias.data.item()))
    plt.show()
    
display_results(model, x, y)

최종적으로 결과를 출력해보면 다음과 같다.