Seeyong's Blog

Minimize It!

Hypothesis and Cost Function

우리가 가지고 있는 X 값과 Y라는 결과값을 가지고서 최적의 기울기(W)절편(b)을 구할 수 있다면, 우리가 가지고 있지 않은 미지의 새로운 X 값에 따른 Y를 추정해볼 수 있다.

X Y
1 1
2 2
3 3

우리가 가지고 있는 데이터가 위 표와 같다면 우리는 독립변수 X종속변수 Y가 어떤 관계를 가지고 있는지 좌표평면에 찍어보며 추정해볼 수 있다. 물론 위의 사례는 너무 명확해서 직관적으로 판별할 수 있지만 앞으로 우리가 분석할 데이터는 전혀 그런 친절함이 없다.

Hypothesis and Cost Function

\(H(x) = Wx + b\) \(cost(W, b) = \frac{1}{m}\sum_{i=1}^m (H(x^i) - y^i)^2\)

말그대로 가설(Hypothesis)을 찾아보고 검증하여 오차를 줄이려는 것이 우리의 목표다. 앞서 언급했듯이 기울기(W)절편(b)을 추정해보려 한다. 그리고 각 가설마다 실제 Y와의 차이를 구한 후, 제곱의 평균을 해서 cost / loss를 구할 수 있다.

제곱을 하는 이유는 두 가지.
1. 오차가 음수일 경우 양수로 통일
2. 오차가 클 수록 더 많은 페널티 부여

1 Build Graph(tensor) using TensorFlow operations

# H(x) = Wx + b
# X and Y data
x_train = [1, 2, 3]
y_train = [1, 2, 3]

# variable in TF (= trainable variable)
W = tf.Variable(tf.random_normal([1]), name='weight')
b = tf.Variable(tf.random_normal([1]), name='bias')

#Our Hypothesis WX + b(node)
hypothesis = W * x_train + b

먼저 x_trainy_train을 각각 설정한다. 그리고 우리의 node를 하나씩 만들어 전체 그래프(tensor)를 완성해보자.

기울기(W)는 1차원의 무작위 숫자로, 이름은 weight(가중치)이고 tf.Variablenode를 지정한다. TensorFlow에서의 variable은 일반적인 프로그래밍의 변수가 아니라 train 가능한 변수 정도로 이해하면 된다. 절편(b) 역시 같은 방식으로 node를 만든다.

이후 우리의 가설식에 두 변수를 대입한다. \(H(x) = Wx + b\)

hypothesis = W * x_train + b

이제 hypothesis라는 새로운 가설 node가 생성됐다.

# cost/loss function
cost = tf.reduce_mean(tf.square(hypothesis - y_train))

#reduce_mean
'''
t = [1., 2., 3., 4.]
tf.reduce_mean(t) == 2.5
'''

이제 cost를 측정하는 node를 작성할 차례다. hypothesis와 마찬가지로 수식을 코드로 옮기면 된다. \(cost(W, b) = \frac{1}{m}\sum_{i=1}^m (H(x^i) - y^i)^2\)

cost = tf.reduce_mean(tf.square(hypothesis - y_train))

reduce_mean은 일단 일반적인 평균을 구하는 방식으로 이해하면 된다.

GradientDescent

#Minimize cost
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)
train = optimizer.minimize(cost)

현재 시점에서 이 부분에 대한 자세한 설명은 건너뛰자. 다음 포스팅에서 다룰 내용인데, 우리가 설정한 cost를 최소화해주는 마법 공식이라는 정로로 이해하자. 최종적으로 train이라는 node를 만들어 사용할 것이다.

2,3 Run/Update Graph and get Result

# Launch the graph in a session
sess = tf.Session()

# Initializes global variables in the graph
sess.run(tf.global_variables_initializer())

전체 그래프(tensor)를 만들기 위해 session을 지정하고서, global_variables_initializer를 실행한다. 앞서 우리가 만들었던 Wbtf.Variable(tf.random_normal())을 확정적으로 선언하기 위한 작업이다.

# Fit the line
for step in range(2001):
    sess.run(train)
    if step % 100 == 0:
        print(step, sess.run(cost), sess.run(W), sess.run(b))

이제 train을 2,000번 실행시켜 가장 cost / loss가 적은 Wb를 찾아낼 것이다. 모든 스텝마다 출력할 경우 부담스러우니 100번 마다 출력할 것이다.

0 0.18124902 [0.54359144] [0.70696163]
100 0.051277865 [0.736996] [0.59786755]
200 0.0316866 [0.79325557] [0.46997872]
300 0.01958041 [0.83747995] [0.3694462]
400 0.012099485 [0.8722445] [0.2904183]
500 0.0074767545 [0.89957255] [0.22829522]
600 0.0046201865 [0.92105484] [0.17946094]
700 0.0028549908 [0.93794185] [0.1410727]
800 0.0017642155 [0.95121664] [0.11089599]
900 0.001090174 [0.96165186] [0.08717432]
1000 0.00067366054 [0.96985495] [0.06852694]
1100 0.00041627904 [0.9763032] [0.05386832]
1200 0.0002572355 [0.9813722] [0.04234548]
1300 0.00015895742 [0.9853568] [0.03328738]
1400 9.8226825e-05 [0.9884891] [0.02616697]
1500 6.069679e-05 [0.9909515] [0.02056947]
1600 3.7507194e-05 [0.992887] [0.01616953]
1700 2.3177143e-05 [0.99440855] [0.01271076]
1800 1.4321881e-05 [0.9956046] [0.00999186]
1900 8.850558e-06 [0.9965448] [0.00785452]
2000 5.469174e-06 [0.9972839] [0.00617441]

결과는 다음과 같다. 우리가 직관적으로 예상한 바와 같이 W(세번째 column)는 1.0에 수렴하고, b(네번째 column)는 0.0에 수렴한다.

# Now we can use X and Y in place of x_data and y_data
# placeholders for a tensor that will be always fed using feed_dict
x = tf.placeholder(tf.float32)
y = tf.placeholder(tf.float32)

for step in range(2001):
    cost_val, W_val, b_val, _ = sess.run([cost, W, b, train],
                feed_dict={x: [1, 2, 3], y: [1, 2, 3]})
    if step % 100 == 0:
        print(step, cost_val, W_val, b_val)

placeholder를 사용해 node에 나중에 값을 넣어줄 수도 있다. tf.placeholderxy라는 node를 생성한 후, 다시 2,000번 반복해서 train을 실행한다.

0 3.0695446e-12 [0.99999785] [4.350787e-06]
100 3.0695446e-12 [0.99999785] [4.350787e-06]
200 3.0695446e-12 [0.99999785] [4.350787e-06]
300 3.0695446e-12 [0.99999785] [4.350787e-06]
400 3.0695446e-12 [0.99999785] [4.350787e-06]
500 3.0695446e-12 [0.99999785] [4.350787e-06]
600 3.0695446e-12 [0.99999785] [4.350787e-06]
700 3.0695446e-12 [0.99999785] [4.350787e-06]
800 3.0695446e-12 [0.99999785] [4.350787e-06]
900 3.0695446e-12 [0.99999785] [4.350787e-06]
1000 3.0695446e-12 [0.99999785] [4.350787e-06]
1100 3.0695446e-12 [0.99999785] [4.350787e-06]
1200 3.0695446e-12 [0.99999785] [4.350787e-06]
1300 3.0695446e-12 [0.99999785] [4.350787e-06]
1400 3.0695446e-12 [0.99999785] [4.350787e-06]
1500 3.0695446e-12 [0.99999785] [4.350787e-06]
1600 3.0695446e-12 [0.99999785] [4.350787e-06]
1700 3.0695446e-12 [0.99999785] [4.350787e-06]
1800 3.0695446e-12 [0.99999785] [4.350787e-06]
1900 3.0695446e-12 [0.99999785] [4.350787e-06]
2000 3.0695446e-12 [0.99999785] [4.350787e-06]

역시나 W(세번째 column)는 1.0에 수렴하고, b(네번째 column)는 0.0에 수렴한다. 이런 과정을 거쳐 우리는 하나의 선형회귀분석모델(Linear Regression Model)TensorFlow로 만들어냈다.