Regression using Multilayer Perceptron

독립변수와 실수인 종속변수의 관계를 찾는 회귀분석(regression) 문제를 Multilayer perceptron(MLP) 모델을 통해서 해결해보자.

Perceptron과 MLP

Perceptron 이란 neuron을 구성하는 하나의 단위를 의미하며 다음과 같다.

입력변수 \(X=(x_1,\cdots,x_n)\), weight \(W = \left(\begin{array}{cc} w_{1}\\ \vdots \\ w_{n} \end{array}\right)\), bias \(b\), activation function(활성함수) \(f\) 및 출력

\[H(X)=f(XW+b) = f\left(\sum_{i=1}^n w_i x_i +b \right )\]

으로 구성되어있고 주어진 데이터를 잘 설명하는 \(W\)와 \(b\)를 찾는 것이 학습의 목적이다.

이전에 다루었던 선형회귀분석(linear regression)은 activation function이 항등함수 \(f(z)=z\)인 perceptron이었고 이진분류(binary classificaion)에서는 activation function이 sigmoid \(f(z)=\frac{1}{1+e^{-z}}\)인 perceptron이었다. Multilayer perceptron, MLP는 이 perceptron을 여러 겹 쌓아놓은 형태의 모델이라고 할 수 있다(combination of deep and wide perceptrons). Input layer와 Output layer 사이에 있는 층을 은닉층(hidden layer)라고 부른다. MLP는 최소한 1개의 은닉층(hidden layer)을 가지는 모델이다.

Activation function

Activation function으로 주로 쓰이는 함수들은 다음과 같다.

  • Step function: \(\, f(z):= \begin{cases} 1 \quad \text{if } z\geq 0\\ 0 \quad \text{otherwise} \end{cases}\) 또는 \(\, f(z):= \begin{cases} 1 \quad \text{if } z\geq 0\\ -1 \quad \text{otherwise} \end{cases}\)
  • Identity function(without activation): \(\, f(z):= z\)
  • Sigmoid, tf.sigmoid: \(\, f(z):= \frac{1}{1+e^{-z}}\)
  • Hyperbolic tangent, tf.tanh: \(\, f(z):= \tanh(z)\)
  • Relu, Rectified Linear Unit, tf.nn.relu: \(\, f(z):= \max(0,z)\)

Rule of activation functions

Final layer의 activation function은 임의로 선택하면 안되고 모델의 목적에 맞게 선택되어야 한다. 예를 들면 다음과 같다.

  • 회귀분석(regression): identity function
  • 이진분류(binary classification): sigmoid, hyperbolic tangent, 또는 softmax
  • 다중분류(multiclass classification): softmax

Hidden layer에서는 linear function을 제외한 비선형(non-linear) 함수를 자유롭게 activation function으로 사용할 수 있다. 선형함수의 합성함수는 다시 선형함수이기 때문에 activation function으로 비선형 함수를 사용하여 layer 사이의 관계에 비선형성을 주는 것이다.

다음 데이터셋을 살펴보자.

독립변수 \(x\)와 종속변수\(y\) 500개의 1차원 실수값이고 두 변수 사이의 관계는 선형함수(직선)으로 설명하기 어려워 보인다. 실제로 2차함수(quadratic function)으로 생성된 데이터이다. Input layer와 Output layer 사이에 두개의 hidden layer를 추가하였고 각각의 hidden layer의 노드의 수는 10으로 설정하였다. Hidden layer의 activation function은 sigmoid이고 output에는 identity function으로 activation function을 설정하였다.

500개의 데이터 중에서 학습데이터와 테스트데이터의 비율은 7:3으로 설정하여 학습을 진행하였다. 다음 그림은 테스트데이터의 실제값(파란색)과 예측값(빨간색)을 보여준다.

참고로 선형회귀분석(linear regression)으로 독립변수와 종속변수를 분석한 결과는 다음과 같고 두 모델을 평가하기 위해서 MSE와 MAE를 비교하면 다음과 같다.

MSE와 MAE 모두 MLP model이 더 작은 값이 나오는 것을 확인할 수 있다.

참고

위 문제를 Neural network의 Multilayer perceptron으로 이용하지 않고 다중회귀분석(multiple linear regression)으로도 해결을 할 수 있다. \(x\)와 \(y\)의 산포도를 보고 선형모델이 아닌 \(x^2\)을 독립변수에 추가하여 2차식으로 regression model을 구성하는 것이다. 즉, 두개의 독립변수 \(x\), \(x^2\)으로 종속변수 \(y\)를 예측하는 regression model

\[H(x)=w_1x^2 +w_2x +b\]

을 찾는 것이다. 하지만 실제 산업문제는 위의 예처럼 간단하지 않다. 보통 독립변수의 갯수가 많고 고려할 사항들이 많아서 각각의 독립변수마다 그래프를 그려서 종속변수와 어떤 관계가 있는지 찾기 쉽지 않다.


Regression with MLP의 TensorFlow code는 다음과 같다.

import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np

from sklearn.model_selection import train_test_split
from sklearn.metrics import *
from sklearn.linear_model import LinearRegression

%matplotlib inline


# 데이터셋 구성
np.random.seed(20)
x_data = np.reshape(np.linspace(-3, 10, 500), [-1,1])
y_data = (x_data +0.5 *np.random.normal(size=[500,1]))**2- 0.1 * np.random.normal(size=[500,1])

plt.figure(figsize=(16,12))
plt.ylim(-20,120)
_ = plt.plot(x_data, y_data, "o", alpha=0.7)

# 학습데이터와 테스트데이터 구분(비율 7:3)

x_train, x_test, y_train, y_test = \
train_test_split(x_data, y_data, test_size= 0.3, random_state=10)

# MLP 모델 구성
X = tf.placeholder(tf.float32, shape=[None,1])
Y = tf.placeholder(tf.float32, shape=[None,1])

W0 = tf.Variable(tf.random_normal([1,10]), dtype=tf.float32)
b0 = tf.Variable(tf.random_normal([10]), dtype=tf.float32)

H0 = tf.sigmoid(tf.matmul(X,W0)+b0)

W1 = tf.Variable(tf.random_normal([10,10]), dtype=tf.float32)
b1 = tf.Variable(tf.random_normal([10]), dtype=tf.float32)

H1 = tf.sigmoid(tf.matmul(H0,W1)+b1)

W2 = tf.Variable(tf.random_normal([10,1]), dtype=tf.float32)
b2 = tf.Variable(tf.random_normal([1]), dtype=tf.float32)

H = tf.matmul(H1,W2)+b2


loss = tf.reduce_mean(tf.square(H-Y))

train = tf.train.GradientDescentOptimizer(learning_rate = 0.01).minimize(loss)

sess = tf.Session()
sess.run(tf.global_variables_initializer())

# 학습횟수: 50,000번

l_cost = []
iteration = 50000
for step in range(iteration):
    _, cost = sess.run([train, loss], feed_dict={X: x_train, Y: y_train})
    l_cost.append(cost)
    if (step+1) % (iteration//10) ==0 :
        print("Step : %i, Cost : %s" %((step+1), cost))


plt.figure(figsize=(12,6))
plt.xlabel("Steps")
_ = plt.plot(l_cost, "k--", label='Cost of Training data')
plt.legend(fontsize=20)

# 학습한 모델을 테스트 데이터에 적용

y_pred = sess.run(H, feed_dict={X: x_test})
plt.figure(figsize=(16,12))
plt.ylim(-20,120)
_ = plt.plot(x_test, y_test, "o", alpha=0.7)
_ = plt.plot(x_test, y_pred, "ro")

mse_mlp = mean_squared_error(y_test, y_pred)
mae_mlp = mean_absolute_error(y_test, y_pred)
print ('MSE: ', mse_mlp)
print ('MAE: ', mae_mlp)

# 선형회귀분석(linear regression) 결과 확인 및 비교

H = LinearRegression().fit(x_train, y_train)
y_pred = H.predict(x_test)

plt.figure(figsize=(16,12))
plt.ylim(-20,120)
_ = plt.plot(x_test, y_test, "o", alpha=0.7)
_ = plt.plot(x_test, y_pred, "ro")

mse_lin = mean_squared_error(y_test, y_pred)
mae_lin = mean_absolute_error(y_test, y_pred)
print ('R2: ', r2_score(y_test, y_pred))
print ('MSE: ', mse_lin)
print ('MAE: ', mae_lin)

x = ["MLP model","Linear regression"]
y = [round(mse_mlp, 2),round(mse_lin, 2)]


plt.figure(figsize=(12,9))
plt.subplot(221)
plt.title("MSE")
plt.bar(x,y, alpha=0.5, color="r")
for a,b in zip(x, y):
    plt.text(a, b, str(b),horizontalalignment='center', fontsize=20, fontweight='bold')

x = ["MLP model","Linear regression"]
y = [round(mae_mlp, 2), round(mae_lin, 2)]

plt.subplot(222)
plt.title("MAE")
plt.bar(x,y, alpha=0.5, color="k")
for a,b in zip(x, y):
    plt.text(a, b, str(b),horizontalalignment='center', fontsize=20, fontweight='bold')