이전에는 Simple Linear Regression에 대해서 알아보았습니다. 이는 독립변수가 1개이고 hypothesis를 통해서 Label을 도출하는 방식입니다. 아래의 그림과 같이 얼마나 W와 b를 잘 학습해서, 추가로 들어오는 독립변수에 대해서 정확한 Label을 내놓는지가 중요한 문제입니다.
Simple Linear Regression에 대해서는 이전글을 참조해주시기 바랍니다.
2020/01/24 - [Tensorflow] - [Tensorflow 2.0] 03. Simple Linear Regression (1)
1. Multiple Linear Regression
그렇다면, Multiple Linear Regression는 무엇일까요?? 간단하게는 기존에 1개였던 독립변수가 Multi개 라는 것 입니다. 그만큼 hypothesis를 구하는데 있어서 여러가지 요인이 있다는 것입니다. 그렇다면 이 녀석은 몇차원으로 표현될까요?? 기존에 Simple Linear Regression은 2차원에서 표현이 되었지만 MLRA는 다차원에서 표현이 됩니다. 이를 눈으로 보기에는 힘들겠죠...
이렇게 독립변수가 여러개일 때, 각 요인별(X)로 가중치(W)를 각 각 구해서 hypothesis를 적용하는 방식입니다. 이에 대한 label은 기존과 동일하게 1개의 값으로 나오기 때문에 이하 Error, Loss, Gradiant를 구하는 방식은 동일합니다.
[Hypothesis(가설) 설정][다름]
요소 별 가중치를 각각 구합니다.
Hypothesis H = W1 * x1 + W2 * x2 + ....... + b (W는 weight 기울기, b는 bias 절편)
여기서 모양을 잘 살펴보면, W와 x는 matrix multiply모양을 띕니다.
결과는 W1 * X1 + W2 * X2 + ..... + Wn * Xn 입니다. 따라서 실제 구현시에는 Simple에서와는 약간 다르게 적용해주면 됩니다.
[Loss 오차][동일]
error = y^ - y (두개의 차)
Loss = (1/n) * 2 * (y^ - y) ^ 2
[Optimizer]
Gradient = (1/n) * (y^ - y) * x 이고,
GDA : W new = W old - LR(Learning Rate, 상수) * Gradient
그럼 이제 다양한 방식으로 MLRA을 구현해 보겠습니다.
2. MLRA with Numpy
[공통모듈 import 및 Data생성]
from sklearn.datasets import make_regression
import numpy as np
import matplotlib.pyplot as plt
X, y = make_regression(n_samples=100, n_features=3, bias=10.0, noise=10.0, random_state=1)
# 뒤에 tensorflow 및 keras는 제거 필요
X = np.insert(X, 0, 1, axis=1)
y = np.expand_dims(y, axis=1)
train_x = X[:80]
test_x = X[80:]
train_y = y[:80]
test_y = y[80:]
bias를 함께 넣어서 계산해버리기 위해서 np.insert를 통해서 X의 모든 행에 1을 추가합니다.
[전체 Class 제작]
class mlraWithNumpy():
def __init__(self):
self.epochs = 100
self.learning_rate = 0.1
self.w = np.random.rand(4,1) * 0.01
def buildModel(self, x, y):
loss_mem = []
for e in range(self.epochs):
hypothesis = np.matmul(x, self.w)
error = hypothesis - y
loss = np.mean(error * error) / 2
loss_mem.append(loss)
gradient = np.mean(x * error, axis=0, keepdims=True).T
self.w -= self.learning_rate * gradient
return loss_mem
def predictModel(self, x):
return np.matmul(x, self.w)
def evalModel(self, x, y):
hypothesis = np.matmul(x, self.w)
error = hypothesis - y
mse = np.mean(error * error)
return np.sqrt(mse)
self.w에 기존과 다르게 matrix가 변경된 것을 제외하고는 다 동일합니다.
[학습수행]
model = mlraWithNumpy()
loss_mem = model.buildModel(train_x, train_y)
x_epoch = list(range(len(loss_mem)))
plt.plot(x_epoch, loss_mem)
plt.show()
Loss가 이쁘게 줄어드는 것을 봐서는 학습이 제대로 된 것 같습니다. (초기에는 급격히 줄다가... 안정화 되는 모양새!!)
[모델평가]
print(model.evalModel(test_x, test_y))
######################################
8.001337716326091
RMSE도 적당히 좋은 값이 나왔습니다.
3. MLRA with Tensorflow
기존에 작성했던 방식과 크게 다르지 않습니다. 다만 차이는 Weight Variable의 모양이 기존에는 단일 값이였다면, 이제는 독립변수의 수만큼 shape가 변경되어야 합니다. shape = [input_cnt, 1] 과 같이 말이죠...
우선 tensorflow를 import하고 확인합니다.
import tensorflow as tf
print(tf.__version__)
이제 관련 class를 생성하고, model을 만들어 보겠습니다.
[Build Model]
class mlraWithTF():
def __init__(self):
self.epochs = 100
self.learning_rate = 0.01
#Variable setting
self.w = tf.Variable(tf.random.uniform([3,1], dtype=tf.double))
self.b = tf.Variable(tf.zeros([1], dtype=tf.double))
def buildModel(self, x, y):
with tf.GradientTape() as tape:
hypothesis = tf.matmul(x, self.w) + self.b
loss = tf.reduce_mean(tf.square(hypothesis - y))
loss_w, loss_b = tape.gradient(loss, [self.w, self.b])
self.w.assign_sub(loss_w * self.learning_rate)
self.b.assign_sub(loss_b * self.learning_rate)
return loss
위에 말한것 처럼 self.w는 모양이 [3,1]의 3행 1열 matrix로 생성합니다. 그리고, hypothesis의 경우에는 tf.matmul을 사용해서 matrix 곱 연산을 수행합니다. 나머지는 동일합니다.
[Train Model]
def trainModel(self, x, y):
data = tf.data.Dataset.from_tensor_slices((x, y))
data = data.shuffle(buffer_size=50).batch(10)
loss_mem = []
for e in range(self.epochs):
for each, (x,y) in enumerate(data):
loss = self.buildModel(x, y)
print('epoch {0}: loss is {1:.4f}'.format(e, float(loss)))
loss_mem.append(loss)
return loss_mem
train용으로 80개의 데이터에 대해서 tf.data.Dataset으로 제작하고, mini-batch로 잘라서 학습을 진행합니다.
[Evaluate Model]
def evalModel(self, x, y):
y_hat = tf.matmul(x, self.w) + self.b
mse = tf.reduce_mean(tf.square(y_hat - y))
rmse = tf.sqrt(mse)
return rmse
test용 20개의 데이터에 대해서 학습된 모델을 검증하여 RMSE (Root Mean Square Error)를 도출합니다.
[실행]
model = mlraWithTF()
loss_mem = model.trainModel(train_x, train_y)
x_epoch = list(range(len(loss_mem)))
plt.plot(x_epoch, loss_mem)
plt.xlabel('epochs')
plt.ylabel('Loss status')
plt.show()
학습을 진행하면서 변화된 loss값을 plot으로 그려보면...
진행되면서 Loss값은 초반에 급격히 줄고, 진행될수록 변화없이 안정화 되는 모습을 보여줍니다. 학습이 잘 됬다는 거겠죠?? 그럼 RMSE를 구해보겠습니다.
print(model.evalModel(test_x, test_y).numpy())
###############################################
7.991131789959619
괜찮은 값이 나왔습니다.
4. MLRA with Keras
사실 Keras는 기존과 소스가 전혀달라지지 않습니다. 왜냐하면, tf.keras.layers.Dense( ) 에서 input value의 matrix형태가 달라져도... 알아서 분석해서 적용해주기 때문입니다.
[전체 Class 제작 - build, fit, evaluate]
class mlraWithKeras():
def __init__(self):
self.epochs = 100
self.learning_rate = 0.01
def buildModel(self):
self.model = tf.keras.Sequential()
self.model.add(tf.keras.layers.Dense(1, activation='linear'))
optimizer = tf.keras.optimizers.SGD(learning_rate=self.learning_rate)
self.model.compile(loss='mse', optimizer=optimizer, metrics=['mse'])
def fitModel(self, x, y):
history = self.model.fit(x, y, batch_size=10, epochs=self.epochs, shuffle=True)
return history
def evalModel(self, x, y):
return self.model.evaluate(x, y)
[학습 수행]
model = mlraWithKeras()
model.buildModel()
history = model.fitModel(train_x, train_y)
학습을 수행하고 history를 반환받아서 Loss가 어떻게 변화했는지 확인해 보겠습니다. 나중에 기회가 되면 따로 분리해서 pandas 패키지를 다루겠습니다. 우선 해당 python 패키지는 데이터에 대한 조작의 편의성을 제공해 주는 아이라고 생각하시면 됩니다.
import pandas as pd
hist = pd.DataFrame(history.history)
print(hist)
x_epoch = list(range(len(hist)))
plt.plot(x_epoch, hist['loss'])
plt.show()
[모델 평가]
model.evalModel(test_x, test_y)
###############################
MSE : 63.945667
위를 통해서 예측해 보면 RMSE는 7 ~ 8 사이라고 생각할 수 있습니다. 잘 도출 됬네요!! 그럼 MLRA를 마치겠습니다.
-Ayotera Lab-
댓글