Neural Networks in XOR problem


본 장에서는 Neural network을 약 20년간 암흑기에 빠지게한 
XOR문제에 대해서 다뤄 보겠다.

우선 직관적으로 Hiddlen Layer를 통해서 XOR 문제를 해결 하는 방법을 알아보고
두 번째로 Backpropagation Algorithm을 이용해서 기계적으로 학습을 통해서 Weight 값을 알아내는 방법을 알아본다.
마지막으로 TensorFlow를 통해서 이를 각각 구현해 보도록 한다.

XOR using NN

아래와 같은 문제가 있다고 하자.

아래와 같은 weight들로 구성 되어져 있다고 가정 하자. 

이것을 각각 계산하면 아래와 같다.

좀 더 정리하면 아래와 같은 모습이 된다.

생각해 볼것은 여기서 주어진 wegiht들 이외에 XOR 문제를 풀수 있는 새로운 W와 b를 찾을 수 있을까?

그리고 Vectorazation을 이용해서 좀 더 간소화 시킬 수 도 있다.

이것을 TensorFlow로 구현 하면 아래와 같다.

# Our hypothesis
K = tf.sigmoid(tf.matmul(X, W1) + b1)
hypothesis = tf.sigmoid(tf.matmul(K, W2) + b2)

Backpropagation

MIT AI Lab의 창시자 Marvin Minsky가 말했던

No one on earth had found a viable way to train MLPs good enough to learn such simple functions.

Forwarding 방식으로는 Derivation을 계산하기가 너무 어렵다.
따라서 제안된 방식이 Backpropagation이다.

기본적으로 Back propagation은 미분학의 chain rule을 사용하는 방식이다.
여기서 chain rule이란 아래의 미분 공식을 말한다.
함수 $f(g(x))$의 미분값은 아래의 방식으로 계산 할 수 있다.
$$\frac{\partial f}{\partial x}=\frac{\partial f}{\partial g}\frac{\partial g}{\partial x}$$

이제 아래와 같은 간단한 함수를 생각해 보자.
$$f=Wx+b, g=Wx, f=g+b$$
그리고 이것을 chain rule을 통해서 모두 계산 할 수 있게 된다. 즉 결과 f에 미치는 각각의 term들의 영향을 계산할 수 있는 것이다.

  • forward (w=-2, x=5, b=3)
  • backward

이제 각각의 계산하면
w = -2
x = 5
b = 3
g = -10
f = -7

그리고 계산의 편의를 위해서 각각의 partial derivative를 모두 계산해 보자.

$$\frac{\partial g}{\partial w}=x$$
$$\frac{\partial g}{\partial x}=w$$
$$\frac{\partial f}{\partial g}=1$$
$$\frac{\partial f}{\partial b}=1$$

이제 편미분 값을 이용해서 f에 미치는 영향을 각각 계산하면 아래와 같다.

위 값을 해석해보면 결국 1이라는 것은 1:1 영향 관계를 나타내고
5는 5배 만큼 영향을 미친다는 것이다.
즉 b=3에서 b=4로 증가시킬 경우 f의 값은 -6이 된다. 즉 1만큼 차이가 생긴다.
반대로 w를 -3으로 변경 시키면 f는 -12되므로 -5만큼 값이 증가하게 된다. 5배의 영향을 미치는 것을 알 수 있다.

이러한 방법을 이용해서 아무리 복잡해서 모두 계산 할 수 있다.

Neural network implementation

How can we learn W1, W2, B1, B2 from training data ?

구현 방법에 대해서 알아 보겠다.
지난번 logistic regression code에서 약간만 더 수정하면 된다.

아래의 코드는 아래의 그림을 표현한 것이다.

W1 = tf.Variable(tf.random_uniform([2, 2], -1.0, 1.0))
W2 = tf.Variable(tf.random_uniform([2, 1], -1.0, 1.0))

b1 = tf.Variable(tf.zeros([2]), name="Bias1")
b2 = tf.Variable(tf.zeros([1]), name="Bias1")


# Our hypothesis
L2 = tf.sigmoid(tf.matmul(X, W1) + b1)
hypothesis = tf.sigmoid(tf.matmul(L2, W2) + b2)

위와 같이 구현하면 쉽게 두개의 layer가 존재하는 neural network을 구성한 것이 된다.

전체소스코드는 아래와 같다.
기본적으로 변경된 것은 아래와 같다.

1) hypothesis를 위와 같이 변경 했다.

2) 입력 데이터 형테를 변경 했다.
변경전 
[[ 0, 0, 1, 1],
[ 0, 1, 0, 1]]
변경후
[[0, 0],
[0, 1],
[1, 0],
[1, 1]]

3) Learning rate과 interation을 조정했다. converge하는데 시간이 너무 오래 걸린다.

import tensorflow as tf
import numpy as np

xy = np.loadtxt('train.txt', unpack=True)

#x_data = xy[0:-1]
x_data = np.transpose(xy[0:-1])
#y_data = xy[-1]
y_data = np.reshape(xy[-1], (4, 1))

X = tf.placeholder(tf.float32)
Y = tf.placeholder(tf.float32)

W1 = tf.Variable(tf.random_uniform([2, 2], -1.0, 1.0))
W2 = tf.Variable(tf.random_uniform([2, 1], -1.0, 1.0))

b1 = tf.Variable(tf.zeros([2]), name="Bias1")
b2 = tf.Variable(tf.zeros([1]), name="Bias1")


# Our hypothesis
L2 = tf.sigmoid(tf.matmul(X, W1) + b1)
hypothesis = tf.sigmoid(tf.matmul(L2, W2) + b2)

# Cost function
cost = -tf.reduce_mean(Y*tf.log(hypothesis) + (1-Y)*tf.log(1-hypothesis))

# Minimize
a = tf.Variable(0.1) # Learning rate, alpha
optimizer = tf.train.GradientDescentOptimizer(a)
train = optimizer.minimize(cost)

# Before starting, initialize the variables. We will `run` this first.
init = tf.initialize_all_variables()

# Launch the graph,
with tf.Session() as sess:
    sess.run(init)

    # Fit the line.
    for step in xrange(10000):
        sess.run(train, feed_dict={X:x_data, Y:y_data})
        if step % 200 == 0:
            print step, sess.run(cost, feed_dict={X:x_data, Y:y_data}), sess.run(W1), sess.run(W2)

    # Test model
    correct_prediction = tf.equal(tf.floor(hypothesis+0.5), Y)
    # Calculate accuracy
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
    print sess.run([hypothesis, tf.floor(hypothesis+0.5), correct_prediction, accuracy], feed_dict={X:x_data, Y:y_data})
    print "Accuracy:", accuracy.eval({X:x_data, Y:y_data})

재치환 오류 계산 코드 설명

# Test model
correct_prediction = tf.equal(tf.floor(hypothesis+0.5), Y)
# Calculate accuracy
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
print sess.run([hypothesis, tf.floor(hypothesis+0.5), correct_prediction, accuracy], feed_dict={X:x_data, Y:y_data})
print "Accuracy:", accuracy.eval({X:x_data, Y:y_data})

tf.floor(hypothesis+0.5)는 0~1 사이의 값을 나오게 한다.
그리고 Y의 실제 값과 비교를 한다.
이러한 기능을 하는 함수 correct_prediction를 디자인 한것이다.

accuracy는 평균을 구하는 것이다.

[hypothesis, tf.floor(hypothesis+0.5), correct_prediction, accuracy], 
feed_dict={X:x_data_testing, Y:y_data_testing}

print "Accuracy:", accuracy.eval({X:x_data_testing, Y:y_data_testing})

실행결과

9800 0.0402879 [[-6.13605404 -4.11170053]
 [-6.11376047 -4.1088109 ]] [[-8.83549595]
 [ 8.12334061]]
[array([[ 0.02604489],
       [ 0.96690428],
       [ 0.96695912],
       [ 0.05478531]], dtype=float32), array([[ 0.],
       [ 1.],
       [ 1.],
       [ 0.]], dtype=float32), array([[ True],
       [ True],
       [ True],
       [ True]], dtype=bool), 1.0]
Accuracy: 1.0

cost가 0.04로 0에 근접하는 것을 알 수 있다.


+ Recent posts