[Standalone DL] #5 - 03 Regression with Pytorch

Data Generation

이번에는 x 2차원, y 1차원으로 가보자. 다음 함수를 따르는 x와 y를 생각해보자

\(e \sim \mathcal{N} (0, 0.5)\) \(y = \ 2 sin(x_1) + log({1 \over 2}x_2^2) + e\)

를 따르는 데이터셋 2400개를 수집했다고 생각해보자.

Data Set
\(X_{train} \in \mathcal{R}^{1600 \times 2}, Y_{train} \in \mathcal{R}^{1600}\)
\(X_{val} \in \mathcal{R}^{400 \times 2}, Y_{val} \in \mathcal{R}^{400}\)
\(X_{test} \in \mathcal{R}^{400 \times 2}, Y_{test} \in \mathcal{R}^{400}\)

%matplotlib inline

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d

# ====== Generating Dataset ====== #
num_data = 2400
x1 = np.random.rand(num_data) * 10 # 0~1 unif에서 num_data 개수만큼 뽑는 함수 
x2 = np.random.rand(num_data) * 10
e = np.random.normal(0, 0.5, num_data) # µ=0, sd=0,5인 gaussian dist 
X = np.array([x1, x2]).T
y = 2*np.sin(x1) + np.log(0.5*x2**2) + e

# ====== Split Dataset into Train, Validation, Test ======#
train_X, train_y = X[:1600, :], y[:1600]
val_X, val_y = X[1600:2000, :], y[1600:2000]
test_X, test_y = X[2000:, :], y[2000:]

# ====== Visualize Each Dataset ====== #
fig = plt.figure(figsize=(12,5))
ax1 = fig.add_subplot(1, 3, 1, projection='3d')
ax1.scatter(train_X[:, 0], train_X[:, 1], train_y, c=train_y, cmap='jet')

ax1.set_xlabel('x1')
ax1.set_ylabel('x2')
ax1.set_zlabel('y')
ax1.set_title('Train Set Distribution')
ax1.set_zlim(-10, 6)
ax1.view_init(40, -60)
ax1.invert_xaxis()

ax2 = fig.add_subplot(1, 3, 2, projection='3d')
ax2.scatter(val_X[:, 0], val_X[:, 1], val_y, c=val_y, cmap='jet')

ax2.set_xlabel('x1')
ax2.set_ylabel('x2')
ax2.set_zlabel('y')
ax2.set_title('Validation Set Distribution')
ax2.set_zlim(-10, 6)
ax2.view_init(40, -60)
ax2.invert_xaxis()

ax3 = fig.add_subplot(1, 3, 3, projection='3d')
ax3.scatter(test_X[:, 0], test_X[:, 1], test_y, c=test_y, cmap='jet')

ax3.set_xlabel('x1')
ax3.set_ylabel('x2')
ax3.set_zlabel('y')
ax3.set_title('Test Set Distribution')
ax3.set_zlim(-10, 6)
ax3.view_init(40, -60)
ax3.invert_xaxis()

plt.show()

Image

train set : 학습할 때 사용하는 데이터셋 (업데이트까지 완료)

validation set : train set의 loss가 줄다 보면 validation set의 loss는 증가하게 될 수도 있음. 즉, validation에서는 잘 못하게 되는 순간이 발생할 수 있음 (=overfitting) - 이를 체크하기 위해 사용

  • train 한 번 당 validation 한 번 , train 10번 당 validation 한 번 이렇게 마음대로 진행할 수 있음

test set : 평가용 데이터셋


Hypothesis Define

2차원짜리 input에 W를 곱하고 bias를 더해서 1차원으로 변경해주는 작업 진행 !

Linear Model

\[H = XW + b \quad \left( W \in \mathbb{R}^{2 \times 1},\ b \in \mathbb{R}^{1},\ H \in \mathbb{R}^{N \times 1} \right)\]

Let ( \text{ReLU}(X) = \max(X, 0) )

\[h = \text{ReLU}(X W_1 + b_1) \quad \left( W_1 \in \mathbb{R}^{2 \times 200},\ b_1 \in \mathbb{R}^{200},\ h \in \mathbb{R}^{N \times 200} \right)\] \[H = h W_2 + b_2 \quad \left( W_2 \in \mathbb{R}^{200 \times 1},\ b_2 \in \mathbb{R}^{1},\ H \in \mathbb{R}^{N \times 1} \right)\]

Mean Absolute Error

\[\text{MAE}(Y_{\text{true}}, Y_{\text{predict}}) = \sum_{i} \left| y_{\text{true}}^{(i)} - y_{\text{predict}}^{(i)} \right|\]
import torch
import torch.nn as nn

class LinearModel(nn.Module): # nn.Module 안에 더티한 작업들이 다 있고, 우린 그걸 그냥 상속해오겠다 
    def __init__(self):
        super(LinearModel, self).__init__() # 클래스 쓰는 규칙 
        self.linear = nn.Linear(in_features=2, out_features=1, bias=True)

    def forward(self, x):
        return self.linear(x) # x가 x 자리에 들어가서 w랑 곱해지고 b랑 더해져서 값 완성됨 

class MLPModel(nn.Module):
    def __init__(self):
        super(MLPModel, self).__init__()
        self.linear1 = nn.Linear(in_features=2, out_features=200)
        self.linear2 = nn.Linear(in_features=200, out_features=1)
        self.relu = nn.ReLU()

    def forward(self, x): # 인공신경망의 가장 기초 형태 !! 
        x = self.linear1(x) # Wx+b
        x = self.relu(x) # 선형적이지 않은 어떠한 함수 거치기 
        x = self.linear2(x) # Wx+b 
        return x

lm = LinearModel()
print(lm.linear.weight) # tensor([[-0.1405,  0.1758]], requires_grad=True)

nn.Module이 알아서 잘 처리해주고 있는 과정을 확인해볼 수 있다

인공신경망의 가장 기초적인 형태를 여기서 볼 수 있었는데,

실제로 깊은 인공신경망, deep-learning의 진행은 self.relu(x)self.linear2(x)의 반복이다


Cost Function Define

\[MAE(Y*_{true}, Y_*{predict}) = \sum*_{i} | \ y_*{true}^{(i)} - y_{predict}^{(i)} \ |\]
reg_loss = nn.MSELoss()

test_pred_y = torch.Tensor([0,0,0,0])
test_true_y = torch.Tensor([0,1,0,1])

print(reg_loss(test_pred_y, test_true_y))
print(reg_loss(test_true_y, test_true_y))


Train & Evaluation

import torch.optim as optim
from sklearn.metrics import mean_absolute_error

# ====== Construct Model ====== #
# model = LinearModel()
# print(model.linear.weight)
# print(model.linear.bias)

model = MLPModel() 
print('{} parameters'.format(sum(p.numel() for p in model.parameters() if p.requires_grad))) # 복잡해보이지만 간단히 모델 내에 학습을 당할 파라미터 수를 카운팅하는 코드입니다.

# ===== Construct Optimizer ====== #
lr = 0.005 
optimizer = optim.SGD(model.parameters(), lr=lr)

list_epoch = []
list_train_loss = []
list_val_loss = []
list_mae = []
list_mae_epoch = []

epoch = 4000 .
for i in range(epoch):

    # ====== Train ====== #
    model.train() # 모델 학습 모드 
    optimizer.zero_grad()

    input_x = torch.Tensor(train_X)
    true_y = torch.Tensor(train_y)
    pred_y = model(input_x)

    loss = reg_loss(pred_y.squeeze(), true_y)
    loss.backward() # 백워드로 그라디언트 구해주기 
    optimizer.step() # 그라디언트 바탕으로 파라미터 업뎃해주기 
    list_epoch.append(i)
    list_train_loss.append(loss.detach().numpy())

    # ====== Validation ====== #
    model.eval()
    optimizer.zero_grad()
    input_x = torch.Tensor(val_X)
    true_y = torch.Tensor(val_y)
    pred_y = model(input_x)
    loss = reg_loss(pred_y.squeeze(), true_y)
    list_val_loss.append(loss.detach().numpy())

    # ====== Evaluation ======= #
    if i % 200 == 0: # 200번에 한 번씩 평가하도록 함 

        # ====== Calculate MAE ====== #
        model.eval()
        optimizer.zero_grad()
        input_x = torch.Tensor(test_X)
        true_y = torch.Tensor(test_y)
        pred_y = model(input_x).detach().numpy()
        mae = mean_absolute_error(true_y, pred_y) 
        list_mae_epoch.append(i)

        fig = plt.figure(figsize=(15,5))

        # ====== True Y Scattering ====== #
        ax1 = fig.add_subplot(1, 3, 1, projection='3d')
        ax1.scatter(test_X[:, 0], test_X[:, 1], test_y, c=test_y, cmap='jet')

        ax1.set_xlabel('x1')
        ax1.set_ylabel('x2')
        ax1.set_zlabel('y')
        ax1.set_zlim(-10, 6)
        ax1.view_init(40, -40)
        ax1.set_title('True test y')
        ax1.invert_xaxis()

        # ====== Predicted Y Scattering ====== #
        ax2 = fig.add_subplot(1, 3, 2, projection='3d')
        ax2.scatter(test_X[:, 0], test_X[:, 1], pred_y, c=pred_y[:,0], cmap='jet')

        ax2.set_xlabel('x1')
        ax2.set_ylabel('x2')
        ax2.set_zlabel('y')
        ax2.set_zlim(-10, 6)
        ax2.view_init(40, -40)
        ax2.set_title('Predicted test y')
        ax2.invert_xaxis()

        # ====== Just for Visualizaing with High Resolution ====== #
        input_x = torch.Tensor(train_X)
        pred_y = model(input_x).detach().numpy()

        ax3 = fig.add_subplot(1, 3, 3, projection='3d')
        ax3.scatter(train_X[:, 0], train_X[:, 1], pred_y, c=pred_y[:,0], cmap='jet')

        ax3.set_xlabel('x1')
        ax3.set_ylabel('x2')
        ax3.set_zlabel('y')
        ax3.set_zlim(-10, 6)
        ax3.view_init(40, -40)
        ax3.set_title('Predicted train y')
        ax3.invert_xaxis()

        plt.show()
        print(i, loss)

그리고 evaluation을 해보자 ! Image

  • loss를 저장하고 출력해서 그래프를 그려보는 행위는 매우 중요함 ! (학습 진행 상황을 계속 파악하는 것이 중요함)