Binary classification using Multilayer Perceptron

종속변수 가 categorical variable이고 라벨이 0과 1 두 개인 이진분류(binary classification)문제를 Multilayer perceptron(MLP)를 이용해서 해결해보자. 이진분류 문제이기 때문에 final layer의 activation 함수는 sigmoid를 사용한다(cost 함수는 cross entropy를 사용). 다음과 같이 주어진 데이터를 분류해보자.

는 2차원이고 는 0 또는 1을 갖는 데이터로 같은 색은 같은 클래스를 나타낸다. 두 데이터셋 모두 로지스틱회귀분석으로 해결하기 어려운 구조이다(로지스틱회귀분석으로 분류를 하는 것은 주어진 데이터를 직선으로 분류(linear separation)하는 것이라고 생각하면 된다). 그래서 다음과 같이 Hidden layer가 2개 있는 MLP(Miltilayer Perceptron)로 분류 모델을 만들 것이다.

첫 번째 layer의 노드 수는 20, 두 번째 layer의 노드 수는 10으로 설정하였고 activation으로 모두 sigmoid를 사용하였다.

  • 입력 , Weight , bias 으로 첫 번째 hidden layer 을 다음과 같이 구성하였다.

여기서 는 sigmoid이다. 즉, 첫 번째 hidden layer 은 20차원의 벡터다.

  • 두 번째 hidden layer 을 입력으로하고 Weight , bias 으로 구성되고 식은 다음과 같다.

위와 같은 이유로 은 10차원 벡터가 되고 마지막 는 다음과 같다.

여기서 , bias .

학습데이터와 테스트데이터의 비율은 7:3으로 설정하여 학습을 진행하였다.

결과

다음은 학습에 사용하지 않은 테스트데이터의 산포도를 나타내며 민트색은 파란색(Class 0) 그룹이라고 판단한 점이고 녹색은 오렌지색(Class 1) 그룹이라고 판단한 점들이다. 빨간색 점은 실제 라벨 를 잘못 예측한 점들을 나타낸다.


TensorFlow code

XOR data

# 라이브러리 불러오기
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

from sklearn.datasets import make_moons
from sklearn.model_selection import train_test_split

%matplotlib inline

# XOR 데이터셋 구성
np.random.seed(20180324)

x_data = np.random.uniform(-1,1, [1000,2])
y_data = np.array([0 if x_data[i][0]*x_data[i][1] >= 0.
else 1 for i in range(len(x_data))])

plt.suptitle("Scatter Plot", fontsize=20)
plt.scatter(x_data[y_data == 0, 0], x_data[y_data == 0, 1], label="Class 0", alpha=0.7)
plt.scatter(x_data[y_data == 1, 0], x_data[y_data == 1, 1], label="Class 1", alpha=0.7)
plt.legend()

# 학습데이터와 테스트데이터 구분(비율 7:3)
x_train, x_test, y_train, y_test = \
train_test_split(x_data, y_data, test_size=0.3, random_state=777)

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

# Variables
W0 = tf.Variable(tf.random_normal([2,20]), dtype=tf.float32)
b0 = tf.Variable(tf.random_normal([20]), dtype=tf.float32)

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

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


def model(inputs):
    H0 = tf.sigmoid(tf.matmul(inputs,W0)+b0)
    H1 = tf.sigmoid(tf.matmul(H0,W1)+b1)
    H = tf.sigmoid(tf.matmul(H1,W2)+b2)

    return H

H = model(X)

loss = - tf.reduce_mean(Y * tf.log(H) + (1 - Y) * tf.log(1 - H))
train = tf.train.GradientDescentOptimizer(learning_rate=0.05).minimize(loss)

predicted = tf.cast(H > 0.5, dtype=tf.float32)
accuracy = tf.reduce_mean(tf.cast(tf.equal(predicted, Y), dtype=tf.float32))

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

cost_list = []
acc_list = []

iteration = 10000
for step in range(iteration):
    acc, cost, _, = sess.run([accuracy, loss,  train], feed_dict={X: x_train, Y: np.reshape(y_train, [-1,1])})
    cost_list.append(cost)
    acc_list.append(acc)
    if (step+1) % (iteration//10) ==0:
        print("Step : %i, Cost : %s  Accuracy : %s" %(step+1, cost, acc))

plt.figure(figsize=(12,10))
plt.subplot(221)
plt.xlabel("Steps")
plt.title("Cost", fontsize=20)
_ = plt.plot(cost_list, "c")

plt.subplot(222)
plt.xlabel("Steps")
plt.title("Accuracy", fontsize=20)
_ = plt.plot(acc_list, "k--")

# 학습한 모델을 테스트 데이터에 적용
Hypothesis = sess.run(H, feed_dict={X: x_test})

plt.subplot(223)
plt.title("Result", fontsize=20)
for i, j in enumerate(Hypothesis):
    if j > 0.5 :
        _ = plt.plot(x_test[i][0], x_test[i][1], "yo", alpha=0.7)
    else :
        _ = plt.plot(x_test[i][0], x_test[i][1], "co", alpha=0.7)
for i in range(len(Hypothesis)):
    if np.around(Hypothesis)[i] != y_test[i]:
        _ = plt.plot(x_test[i][0], x_test[i][1], "ro")

Moon data

sklearn을 이용하여 Moon 데이터셋을 만들 수 있고 동일한 MLP 모델에 적용 할 수 있다.

# Moon data
x_moon, y_moon = make_moons(n_samples=1000, shuffle=True, noise=0.15, random_state=10)

plt.suptitle("Scatter Plot", fontsize=20)
plt.scatter(x_moon[y_moon == 0, 0], x_moon[y_moon == 0, 1], label="Class 0", alpha=0.7)
plt.scatter(x_moon[y_moon == 1, 0], x_moon[y_moon == 1, 1], label="Class 1", alpha=0.7)
plt.legend(fontsize=15)

x_train, x_test, y_train, y_test = \
train_test_split(x_moon, y_moon, test_size=0.3, random_state=777)