본문 바로가기

인공지능/ML

인공지능 4. Simple Cost Function / Gradient Descent

이 글은 edwith - [부스트코스] 텐서플로우로 시작하는 딥러닝 기초의 개인적인 공부기록이므로 오류가 있을 수 있습니다!

 

3번 글의 가설에서 b(y절편)을 빼고 간단하게 만든 후 Python으로 직접 Cost Function과 Gradient Descent를 구현해보자.

 

  • 기존 가설

 

  • 간단 가설

 

다음과 같이 진행된다.

 

Cost Function

# Cost Function in pure Python

X = np.array([1, 2, 3])
Y = np.array([1, 2, 3])

def cost_func(W, X, Y):
    c = 0
    for i in range(len(X)):
        c += (W * X[i] - Y[i]) ** 2 # cost function과 동일
    return c / len(X)

print("   W   |     cost")
for feed_W in np.linspace(-3, 5, num=15):
    curr_cost = cost_func(feed_W, X, Y)
    print("{:6.3f} | {:10.5f}".format(feed_W, curr_cost))

X는 [1, 2, 3], Y도 [1, 2, 3]이다.

 

cost_func 함수는 W, X, Y 3개의 인자를 받고 cost(w)의 시그마를 for loop를 이용해 시행한 후 return에서 X의 개수만큼 나눠 평균을 return 하고 있다.

 

feed_W의 for loop에서는 -3과 5 사이를 15개의 구간으로 나눠서(linspace) 돌고 있다.

W가 -3일때부터 cost를 구하기 시작, 5까지 연산을 돈 뒤 멈출 것이다.

curr_cost는 cost_func의 결과이며 w값에 따라 cost가 어떻게 변화하는지 보여줄 것이다.

우리가 기대하는 W의 값은 1이고 당연히 이때 cost는 0을 기대한다.

 

   W   |     cost
-3.000 |   74.66667
-2.429 |   54.85714
-1.857 |   38.09524
-1.286 |   24.38095
-0.714 |   13.71429
-0.143 |    6.09524
 0.429 |    1.52381
 1.000 |    0.00000
 1.571 |    1.52381
 2.143 |    6.09524
 2.714 |   13.71429
 3.286 |   24.38095
 3.857 |   38.09524
 4.429 |   54.85714
 5.000 |   74.66667

 

위 Python 코드의 연산은 다음과 같은 결과를 보여준다.

기대했던 대로 W가 1일때 cost는 0이 되는 것을 볼 수 있다.

 

 

Gradient Descent

Gradient Descent는 cost의 최솟값(1차 근삿값)을 찾아주는 방법 중 하나다.

  1. 랜덤한 x값 / y값에서 출발한다. (0, 0)일 수도 (1, 1)일 수도 있다.
  2. 함수의 기울기가 낮은 쪽으로 W값과 b값을 조금씩 이동시킨다.
  3. 극값에 이를때까지 반복.

함수의 극값은 미분값을 이용해 구할 수 있다.

사실 tensorflow에서 Gradient Descent를 위한 함수를 이미 제공하고 있지만(3번 글의 GradientTape, Gradient 함수) 직접 구현하면 다음과 같다.

cost function
미분과정 1
미분과정 2
최종

미분의 과정을 통해 w값을 최종과 같은 형태로 갱신해나갈 수 있다.

알파는 learning rate이며 초기에 임의의 값으로 설정할 수 있다.

learning rate는 보통 0.1 ~ 0.001 사이에서 시작하는데, 너무 작으면 반영이 많이 되지 않아 효율성이 떨어지고 너무 커지면 변하는 범위가 너무 커져서 극값에 도달하지 못할 수 있기 때문에 적당한 범위를 설정하도록 한다. 연산의 결과에 따라 learning rate를 가변적으로 설정하기도 한다.

 

Python으로 Gradient Descent를 구현해보면 다음과 같다.

tf.random.set_seed(0)

x_data = [1., 2., 3., 4.]
y_data = [1., 2., 3., 4.]

W = tf.Variable(tf.random.normal([1], -100., 100.)) # (차원, start, end)

for step in range(300):
    hypothesis = W * x_data
    cost = tf.reduce_mean(tf.square(hypothesis - y_data))

    alpha = 0.02 # learning rate
    gradient = tf.reduce_mean(tf.multiply(tf.multiply(W, x_data) - y_data, x_data))
    descent = W - tf.multiply(alpha, gradient)
    W.assign(descent)

x_data와 y_data는 같기 때문에 위와 같이 W값은 1을 기대한다.

W는 -100과 100 사이의 숫자 하나를 랜덤으로 설정한다.

300번의 학습을 시행하며 hypothesis와 cost는 위의 간단 가설과 동일하나 cost의 시그마를 reduce_mean 함수로 시행했다는 점이 다르다.

learning rate는 0.02로 초기값을 설정한다. 먼저 기울기를 구한다. 미분 과정 최종 중 1/m부터 끝까지의 수식을 코드로 구현했다.

descent는 설정한 learning rate를 반영한 gradient값이며 assign 메서드를 이용해 W에 이를 반영시킨다.

 

연산 10번 단위로 cost와 W를 출력해보면 다음과 같다.

step |      cost        |    W

    0 | 18829.7812 |  43.590324
   10 |   729.8335 |   9.384944
   20 |    28.2880 |   2.650781
   30 |     1.0964 |   1.324997
   40 |     0.0425 |   1.063983
   50 |     0.0016 |   1.012597
   60 |     0.0001 |   1.002480
   70 |     0.0000 |   1.000488
   80 |     0.0000 |   1.000096
   90 |     0.0000 |   1.000019
  100 |     0.0000 |   1.000004
  110 |     0.0000 |   1.000001
  120 |     0.0000 |   1.000000
  130 |     0.0000 |   1.000000
  140 |     0.0000 |   1.000000
  150 |     0.0000 |   1.000000
  160 |     0.0000 |   1.000000
  170 |     0.0000 |   1.000000
  180 |     0.0000 |   1.000000
  190 |     0.0000 |   1.000000
  200 |     0.0000 |   1.000000
  210 |     0.0000 |   1.000000
  220 |     0.0000 |   1.000000
  230 |     0.0000 |   1.000000
  240 |     0.0000 |   1.000000
  250 |     0.0000 |   1.000000
  260 |     0.0000 |   1.000000
  270 |     0.0000 |   1.000000
  280 |     0.0000 |   1.000000
  290 |     0.0000 |   1.000000

 

cost는 0에, W는 1에 수렴하는 것을 볼 수 있다.