케이스윔의 개발 블로그

[Lec03] Linear Regression의 cost 최소화 알고리즘의 원리 설명 본문

모두를 위한 딥러닝

[Lec03] Linear Regression의 cost 최소화 알고리즘의 원리 설명

kswim 2018. 4. 29. 15:29

오늘은 'cost function을 어떻게 최소화해서 학습을 시킬 것인가'를 알아보도록 하겠다. 우리가 학습시키는 Hypothesis는 H(x) = Wx+b로 주어진다. 이걸 통해서 만들어 낼 수 있는 식 cost(W,b)는 예측값과 실제값 차이의 평균이다. 


간략하게 만든 Simplified hypothesis를 통해서 계산을 해보자! 

H(x)=Wx

cost(W) = 1/m((Wx[i]-y[i])제곱의 합)


training data

 x

 1

 2

 2  

 3

위의 학습데이터를 통해서 cost(W)를 계산해보도록 하겠다.

W=1일때 cost(W)는 무엇인가?

-> 1/3((1*1-1)제곱+(1*2-2)제곱+(1*3-3)제곱) = 0

W=0일 때 cost(W)는 무엇인가?

-> 1/3((0*1-1)제곱+(0*2-2)제곱+(0*3-3)제곱)= (1+4+9)/3 = 14/3 = 4.67

W=2일 때 cost(W)는 무엇인가?

-> 1/3((2*1-1)제곱+(2*2-2)제곱+(2*3-3)제곱)= (1+4+9)/3 = 4.67


cost(w)는 어떻게 생겼을까?

W의 값에 따라 cost(W)의 함수를 그려보면 2차함수의 모습을 나타낸다. 우리가 cost(W)의 최소값을 찾는다는 것은 그래프에서 최소화하는 값을 구하는 것이다. Cost function=Cost(W)에서 최소값을 기계적으로 찾을 수 있다.


Gradient descent 알고리즘 : 경사를 따라 내려가는 알고리즘이다. cost function에서 minimize하기 위해서 사용된다. 다양한 현상에서 최소화를 시키려고 할 경우 사용한다. cost를 최소화하는 W, b를 구할 수 있다. cost(w1, w2, ...)와 같은 함수에서도 사용가능하다.

이 알고리즘은 어떻게 작용되는가?

함수에서 경사도를 따라서 움직이며 lowest point를 찾는다. 최소값에 왔을 때 경사도는 0이 되기떄문에 머무른다. 아무 시작점에서 시작할 수 있다. 미분을 적용하여 W와 b를 조금씩 바꿔가며 항상 최소점에 도착하는 것이 이 알고리즘이다. 

cost(W) = 1/2m((Wx[i]-y[i])제곱의 합)->W := W - (알파)a/aWcost(W)

알파는 0.1정도되는 상수라고 가정한다. 이 식을 통해 최소값의 오른쪽에서 최소값으로 갈 때는 기울기가 양수이므로 W가 좀 더 작은 값으로 가게되고, 최소값의 왼쪽에서 최소값으로 갈 때는 기울기가 음수이므로  W가 좀 더 큰 값으로 가게 된다( (-)+(-) -> (+)됨)

미분을 하고 정리하면 W := W - (알파)1/m(Wx[i]-y[i])x[i]의 합)으로 나온다. 

->Gradient descent 알고리즘을 기계적으로 적용시키면 cost 함수를 최소화 시키는 W를 구하고 학습과정을 통해서 모델을 만들 수 있다


Convex function이란 어느곳에서 알고리즘을 시작해도 항상 같은 최소점에 도착을 하는 함수로, cost function이 convex function이 되는지를 확인해야한다! linear function일 경우엔 convex function이 맞다. 



<Lab 3: 최소화 알고리즘 직접 사용해보기> 


import tensorflow as tf

import matplotlib.pyplot as plt


X=[1,2,3]

Y=[1,2,3]

#가지고 있는 데이터를 준다.


W = tf.placeholder(tf.float32)

#W의 값을 임의로 계속 주면서 학습시키기 위해서 placeholder로 선언한다.


hypothesis = X * W


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


sess = tf.Session()

sess.run(tf.global_variables_initializer())


W_val = []

cost_val = []

#W와 cost의 값을 저장할 리스트를 만든다.


for i in range(-30, 50):

    feed_W = i * 0.1

    #feed_W는 -3~5 사이의 값을 가지게 된다.

    curr_cost, curr_W = sess.run([cost, W], feed_dict={W:feed_W})

    W_val.append(curr_W)

    cost_val.append(curr_cost)

    #feed_W의 값에 따라 변하는 W, cost의 값을 저장하고 출력한다.

    

plt.plot(W_val, cost_val)

#W의 값이 x축이고, cost의 값이 y축인 그래프를 그린다.

plt.show()

#경사면을 따라가는 Gradient descent 알고리즘을 사용하기 좋다.


위의 그래프를 보면 1에서 최소값을 가지는 것을 알 수 있다. Gradient descent 알고리즘을 사용하면 이 1을 찾을 수 있다. 이 알고리즘을 이용해서 미분을 할 것이다! 최소값의 오른쪽에 있을 경우 W가 줄어들게 되고, 최소값의 왼쪽에 있을 경우 W가 증가하도록 계산이 된다. 이것은 기울기의 계산에 의해서 알 수 있다. -> W := W- (알파)1/m(Wx[i]-y[i])x[i]의 합)


<직접 계산과정을 통한 학습>

import tensorflow as tf

x_data = [1,2,3]

y_data = [1,2,3]


W=tf.Variable(tf.random_normal([1]), name = 'weight')

X = tf.placeholder(tf.float32)

Y = tf.placeholder(tf.float32)


hypothesis = X * W


cost = tf.reduce_sum(tf.square(hypothesis - Y))

#알파는 leanring rate이며 상수값이다.


learning_rate = 0.1


#수식을 직접 그대로 표현해서 계산하는 것이다.

gradient = tf.reduce_mean((W*X-Y)*X)


#현재의 W에 다가 descent를 해준다는 의미로 W에서 빼준다. 새로운 W를 얻는다.

descent = W - learning_rate * gradient

update = W.assign(descent)

#학습을 통해 W의 값을 업데이트 해 나가며 cost를 최소화할 수 있도록 위의 과정을 수동으로 수행한다.


sess = tf.Session()

sess.run(tf.global_variables_initializer())


for step in range(21):

    sess.run(update, feed_dict={X:x_data, Y:y_data})

    #x와 y의 data를 던져주면서 값이 잘 업데이트되고 있는지를 확인한다.

    print(step, sess.run(cost, feed_dict={X:x_data, Y:y_data}), sess.run(W))

    #step, cost, W의 값을 출력하며 확인한다. W는 1에 가까운 수가 된다.

    


<Gradient descent Algorithm을 이용한 학습>
import tensorflow as tf

X = [1,2,3]
Y = [1,2,3]

W=tf.Variable(5.0)
#W를 임의의 수인 5.0에서 시작한다.

hypothesis = X * W

cost = tf.reduce_mean(tf.square(hypothesis - Y))
    
#Minimize : Gradient Descent Magic 미분을 직접 계산하지 않고 cost의 최소값을 찾을 수 있다.
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.1)
train = optimizer.minimize(cost)

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

for step in range(10):
    print(step, sess.run(W))
    sess.run(train)

위의 코드에서 W의 임의의 수 5.0과 -3.0을 넣어줬을 때의 결과를 출력해본 것이다. 미분을 직접 계산하지 않고 cost의 최소값을 찾기 위해 Gradient descent 알고리즘을 사용했기 때문에 실제 우리가 구하려고했던 1이 아닌 다른값을 W에 넣었었지만 step을 진행하며 1.0에 가까워짐을 확인할 수 있다.



<optional: gradient 값을 조정하고 계산하고 싶을 때 사용하는 방법

import tensorflow as tf


X = [1,2,3]

Y = [1,2,3]


W=tf.Variable(5.0)


hypothesis = X * W


gradient = tf.reduce_mean((W*X - Y)*X)*2

#Gradient Descent를 통해서 cost의 최소값을 찾는 것과 직접 미분을 계산한 값이 같은지를 확인하기 위해 직접 계산을 해본다.


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

    

#Minimize : Gradient Descent Magic 미분을 직접 계산하지 않고 cost의 최소값을 찾을 수 있다.

optimizer = tf.train.GradientDescentOptimizer(learning_rate=00.1)


#optimizer에서 cost에 알맞은 Gradient 값을 구하는 것이다.

gvs = optimizer.compute_gradients(cost, [W])

#원래 성킴교수님께서 올려주신 코드는 gvs = optimizer.compute_gradients(cost) 인데 나의 경우 에러가 나서 참고글을 보고 바꿨다.


#계산해준 값을 수정해서 optimizer에 값을 적용할 수 있다. 만약 이 값을 조정하고 싶을 경우 위의 gvs를 수정하여서 적용하면 되는데 이 예시에서는 아무런 수정없이 적용한다.

apply_gradients = optimizer.apply_gradients(gvs)



#자동으로 계산된 값과, 수식으로 계산한 값이 같은지를 본다.

sess = tf.Session()

sess.run(tf.global_variables_initializer())


for step in range(100):

    print(step, sess.run([gradient, W]), sess.run(gvs))

    #이부분 또한 원래 sess.run([gradient, W,gvs])가 예시코드인데 그렇게 할 경우 Type errror가 떠서 sess를 나누어 해주었다.

    sess.run(apply_gradients)

    #이 출력을 통해서 수식적으로 계산한 값과 텐서플로에서 계산한 값이 거의 같은 값임을 확인할 수 있다.



Comments