Linear Regression의 Hypothesis와 cost의 개념 연습

Hypothesis와 cost(loss) 함수

  • 가설(hypothesis) : 주어진 \(x\)에 대해서 예측(\(H(x)\))을 어떻게 할 것인가?
    • weight \(W\)와 bias \(b\)로 표현된다.
$$H(x) = Wx + b$$

  • cost(loss) 함수 : 예측을 얼마나 잘 했는가?를 표현한 것으로 차이의 제곱에 대한 평균
    • \(H(x_i)\) : 예측값
    • \(b_i\) : 실제값
$$\textrm{cost(loss)}(W,b)=\frac{1}{m}\sum_{i=1}^{m}(H(x_i)-b_i)^2$$


  • 학습을 한다는 것
    • \(W\)와 \(b\)를 조절해서 cost(loss) 함수의 가장 작은 값을 찾아내는 것



cost(loss) 함수를 TensorFlow로 구현하는 방법

  1. TensorFlow의 연산을 사용하여 그래프를 만든다.
  2. Session() 함수로 세션을 만들고, sess.run() 함수에 데이터를 주고 계산 그래프를 실행하여 연산을 한다.
  3. 결과값이 나와 그래프에 있는 변수들이 업데이트되거나 값을 반환한다.


1. TensorFlow의 연산을 이용하여 그래프 만들기

  • 예측값에 대한 함수 \(H(x)=Wx+b\)를 TensorFlow로 작성해보자.
  • TensorFlow에서는 weight \(W\)와 bias \(b\)의 값을 변수(variable) node로 정의
    • 기존 프로그래밍의 변수와는 다른 개념
    • TensorFlow가 사용하는 변수
      • 프로그램을 실행하면 TensorFlow가 자체적으로 변경시키는 값을 의미
      • 학습을 위해 TensorFlow가 변경을 하면서 최적의 값을 찾아낸다.
    • TensorFlow 변수를 만들 때에는 변수의 shape을 정의하고 값을 주어야 한다.
      • 보통 \(W\)와 \(b\)의 값을 모르기 때문에 random한 값을 준다.
      • tf.random_normal(shape)
    • 예측값 함수를 TensorFlow의 한 점(node)으로 정의
      • tensor 또는 node \(W\)와 \(b\)로 표현
import tensorflow as tf

# 학습용 X와 Y 데이터를 준다.
x_train = [1, 2, 3]
y_train = [1, 2, 3]

# TensorFlow 변수를 1차원 배열로 정의
w = tf.Variable(tf.random_normal([1]), name = 'weight')
b = tf.Variable(tf.random_normal([1]), name = 'bias')

# 예측값 함수(hypothesis)
hypothesis = w * x_train + b


  • cost(loss) 함수 \(\textrm{cost(loss)}(W,b)=\frac{1}{m}\sum_{i=1}^{m}(H(x_i)-b_i)^2\)를 TensorFlow 함수를 이용해 표현해보자.
    • tf.reduce_mean() 함수 : tensor가 주어졌을 때 평균을 구하는 함수
    • cost(loss) 함수의 평균을 내는 부분 \(\frac{1}{m}\sum_{i+1}^{m}\)을 구현하는 것
>>> import tensorflow as tf
>>> t = [1., 2., 3., 4.]
>>> r_mean = tf.reduce_mean(t)
>>> sess = tf.Session()
>>> print("sess.run(r_mean) = ", sess.run(r_mean))
sess.run(r_mean) =  2.5
 

    • cost(loss) 함수 \(\textrm{cost(loss)}(W,b)=\frac{1}{m}\sum_{i=1}^{m}(H(x_i)-b_i)^2\)는 다음과 같이 작성할 수 있다.

# cost(loss) 함수
cost = tf.reduce_mean(tf.square(hypothesis - y_train))


    • 이제 cost(loss) 함수를 최소화(minimization)해야 한다.
      • TensorFlow에서는  GradientDescentOptimizer() 함수를 사용한다
      • 학습 최적화를 위해 minimize() 함수를 사용해 cost 함수의 최소값을 찾도록 한다.
      • 이 부분이 magic이 되는 부분이다.
# GradientDescentOptimizer() 함수로 학습에 Gradient Descent 최적화 방법을 사용
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)
train = optimizer.minimize(cost)

  • TensoFlow 세션을 만들고 실행해야 한다.
    • tf.session() 함수를 만든다.
    • 그래프에 있는 전역 변수를 초기화한다.
    • weight $W$와 bias $b$는 앞에서 선언했다.
    • 변수를 사용하기 위해서는 반드시 초기화를 해주어야만 한다.
      • tf.global_variables_initializer() 함수로 변수를 초기화할 수 있다.
# 세션을 만든다.
sess = tf.Session()
# 그래프에 있는 모든 전역 변수를 초기화한다.
sess.run(tf.global_variables_initializer())


  • training 점 : cost 함수를 최소화시킬 수 있다.
    • train을 실행시켜야 cost를 최소화시킬 수 있다.
      • cost를 최소화시킨다는 것은 예측값과 실제값의 차이를 최쇠화시킨다는 것이다.
  • 세션을 통해 train 점을 실행시킬 수 있다.
    • sess.run(train) 함수를 통해 학습이 이루어진다.
    • 예제에서는 2만번 학습을 한다.
    • 매번 결과를 출력하지 않고, 2000번째 마다 학습한 값을 출력한다.
for step in range(20001):
    sess.run(train)
    if step % 2000 == 0:
        # sess.run(train) 실행을 통해 그래프 상의 모든 연산이 수행되어
        # 그래프 상의 변수의 값들이 업데이트된다.
        print(f"STEP = {step:>5}, cost = {sess.run(cost):>.10}, "
              f"weight = {sess.run(W)}, bias = {sess.run(b)}")


2.3. 그래프의 변수들이 업데이트 된다.

  • 프로그램의 실행 결과는 다음과 같다.
  • 예제 학습 데이터를 통해 우리가 예측할 수 있는 것은 weight \(W=1\)이고, bias \(b=0\)이다.
    • 실제 학습을 시킨 후의 결과는  \(W\approx 1\), \(b\approx 0\)이다.
STEP =     0, cost = 2.450398445, weight = [ 0.52071428], bias = [-0.55709851]
STEP =  2000, cost = 7.966009434e-07, weight = [ 1.00103676], bias = [-0.00235626]
STEP =  4000, cost = 6.939634284e-11, weight = [ 1.00001001], bias = [ -2.18230052e-05]
STEP =  6000, cost = 1.227817847e-11, weight = [ 1.00000429], bias = [ -8.61254284e-06]
STEP =  8000, cost = 1.227817847e-11, weight = [ 1.00000429], bias = [ -8.61254284e-06]
STEP = 10000, cost = 1.227817847e-11, weight = [ 1.00000429], bias = [ -8.61254284e-06]
STEP = 12000, cost = 1.227817847e-11, weight = [ 1.00000429], bias = [ -8.61254284e-06]
STEP = 14000, cost = 1.227817847e-11, weight = [ 1.00000429], bias = [ -8.61254284e-06]
STEP = 16000, cost = 1.227817847e-11, weight = [ 1.00000429], bias = [ -8.61254284e-06]
STEP = 18000, cost = 1.227817847e-11, weight = [ 1.00000429], bias = [ -8.61254284e-06]
STEP = 20000, cost = 1.227817847e-11, weight = [ 1.00000429], bias = [ -8.61254284e-06]


TensorFlow의 전체적인 구조

  • train() 함수는 cost() 함수와 연결되어 있다.
  • cost() 함수는 hypothesis \(H(x)\)와 연결되어 있다.
  • \(H(x)\)는 weight \(W\)와 bias \(b\)의 형태로 연결되어 있다.
  • train()을 실행시킨다는 것은
    • 아래 그림과 같은 그래프를 만든 다음에 training을 한다.
  • train() 함수 실행 : 학습을 시킨다는 것
    • 그래프를 따라 들어가 \(W\)와 \(b\)에 값을 저장한다는 것을 의미
    • 학습을 통해 cost(loss) 함수의 값과 weight \(W), bias \(b)의 값을 보게된다.

  • 예제의 전체 소스코드

import tensorflow as tf

# 학습용 X와 Y 데이터를 준다.
x_train = [1, 2, 3]
y_train = [1, 2, 3]

# TensorFlow 연산에서는 weight와 bias를 variable로 정
W = tf.Variable(tf.random_normal([1]), name = 'weight')
b = tf.Variable(tf.random_normal([1]), name = 'bias')

# 예측값 함수(hypothesis)
hypothesis = W * x_train + b

# cost(loss) 함수
cost = tf.reduce_mean(tf.square(hypothesis - y_train))

# GradientDescentOptimizer() 함수로 학습에 Gradient Descent 최적화 방법을 사용
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)
train = optimizer.minimize(cost)

# 세션을 만든다.
sess = tf.Session()
# 그래프에 있는 모든 전역 변수를 초기화한다.
sess.run(tf.global_variables_initializer())


for step in range(20001):
    sess.run(train)
    if step % 2000 == 0:
        # sess.run(train) 실행을 통해 그래프 상의 모든 연산이 수행되어
        # 그래프 상의 변수의 값들이 업데이트된다.
        print(f"STEP = {step:>5}, cost = {sess.run(cost):>.10}, "
              f"weight = {sess.run(W)}, bias = {sess.run(b)}")


placeholder() 함수로 실행할 때 변수의 값을 줄 수 있다.

  • 그래프를 미리 만들어 놓고, 실행하는 단계에서 값을 주고 싶다.

  • placeholder() 함수로 점을 만들어 놓으면 된다.

    1. placeholder() 함수로 변수형 점을 만든다.
    2. run() 함수로 그래프를 실행할 때, feed_dict 변수로 데이터를 입력한다.
  • placeholde() 함수를 사용해 변수를 선언

# 프로그램을 실행할 때 변수의 값을 넣기위해 placeholde() 함수를 사용
X = tf.placeholder(tf.float32)
Y = tf.placeholder(tf.float32)


  • 실행 단계에서 feed_dict 옵션을 사용하여 데이터를 입력
    • X = [1, 2, 3, 4, 5]
    • Y = [2.1, 3.1, 4.1, 5.1, 6.1]
    • \(W=1\), \(b=1.1\)
for step in range(20001):
    cost_val, W_val, b_val, _ = \
        sess.run([cost, W, b, train],
                 feed_dict = {X: [1, 2, 3, 4, 5], 
                              Y: [2.1, 3.1, 4.1, 5.1, 6.1]})
    if step % 2000 == 0:
        print(f"STEP = {step:>5}, cost = {cost_val:>.15}, "
              f"weight = {W_val}, bias = {b_val}")


  • placeholde() 함수를 사용하는 전체 코드
import tensorflow as tf

# 프로그램을 실행할 때 변수의 값을 넣기위해 placeholde() 함수를 사용
X = tf.placeholder(tf.float32)
Y = tf.placeholder(tf.float32)

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

hypothesis = W * X + b

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

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

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

for step in range(20001):
    cost_val, W_val, b_val, _ = \
        sess.run([cost, W, b, train],
                 feed_dict = {X: [1, 2, 3, 4, 5],
                              Y: [2.1, 3.1, 4.1, 5.1, 6.1]})
    if step % 2000 == 0:
        print(f"STEP = {step:>5}, cost = {cost_val:>.15}, "
              f"weight = {W_val}, bias = {b_val}")


  • 실행 결과
    • \(W\approx1\), \(b\approx1.1\)
STEP =     0, cost = 121.828224182129, weight = [-1.6607039], bias = [ 1.53716469]
STEP =  2000, cost = 2.85170699498849e-07, weight = [ 0.99965453], bias = [ 1.10124719]
STEP =  4000, cost = 6.18001622099129e-11, weight = [ 0.99999481], bias = [ 1.10001838]
STEP =  6000, cost = 6.18001622099129e-11, weight = [ 0.99999481], bias = [ 1.10001838]
STEP =  8000, cost = 6.18001622099129e-11, weight = [ 0.99999481], bias = [ 1.10001838]
STEP = 10000, cost = 6.18001622099129e-11, weight = [ 0.99999481], bias = [ 1.10001838]
STEP = 12000, cost = 6.18001622099129e-11, weight = [ 0.99999481], bias = [ 1.10001838]
STEP = 14000, cost = 6.18001622099129e-11, weight = [ 0.99999481], bias = [ 1.10001838]
STEP = 16000, cost = 6.18001622099129e-11, weight = [ 0.99999481], bias = [ 1.10001838]
STEP = 18000, cost = 6.18001622099129e-11, weight = [ 0.99999481], bias = [ 1.10001838]
STEP = 20000, cost = 6.18001622099129e-11, weight = [ 0.99999481], bias = [ 1.10001838]


  • 훈련시킨 모델로 값을 예측해보자.
    • 전체 소스 코드 뒤에 모델로 다른 값에 대한 예측값을 계산하는 코드를 추가한다.
print("X = {:4}일 때의 예측값은 {}입니다.".format(5, sess.run(hypothesis, feed_dict={X: [5]})))
print("X = {:4}일 때의 예측값은 {}입니다.".format(2.5, sess.run(hypothesis, feed_dict={X: [2.5]})))
print("X = [ {}, {} ]일 때의 예측값은 {}입니다.".format(1.5, 3.5, sess.run(hypothesis, feed_dict={X: [1.5, 3.5]})))


  • 예측값은 다음과 같이 실제 데이터와 거의 같게 나온다.
    • \(x=5\)일 때, \(H(5)\approx6.1\)
    • \(x=2.5\)일 때, \(H(2.5)\approx3.6\)
    • \(x=[1.5, 3.5]\)일 때, \(H(x)\approx[2.6, 4.6]\)
X =    5일 때의 예측값은 [ 6.09999275]입니다.
X =  2.5일 때의 예측값은 [ 3.60000563]입니다.
X = [ 1.5, 3.5 ]일 때의 예측값은 [ 2.60001063  4.60000038]입니다.


예제 모델에 대한 TensorFlow 역학 구조


cost(loss) 함수의 그래프 그리기

  • matplotlib 모듈을 이용하여 $W$에 대한 cost(loss) 함수의 그래프 그리기

import tensorflow as tf
import matplotlib.pyplot as plt

# 학습용 데이터 X와 Y
X = [1, 2, 3]
Y = [1, 2, 3]

W = tf.placeholder(tf.float32)

# 우리의 가설은 bias b를 생략했다. 즉 H(W) = W * X
hypothesis = W * X

# cost(또는 loss) 함수는 가설과 y 값과의 차의 제곱에 대한 평균
cost = tf.reduce_mean(tf.square(hypothesis - Y))

# 세션에서 그래프 활성화
sess = tf.Session()

# 변수 초기화
sess.run(tf.global_variables_initializer())

# cost(loss) 함수를 그래프로 출력하기 위한 변수설정
W_val = []
cost_val = []

# W 범위 -30부터 50까지에 대하여 cost(loss) 함수의 값을 구하여 저장
for i in range(-30, 50):
    feed_W = i * 0.1
    curr_cost, curr_W = sess.run([cost, W], feed_dict={W: feed_W})
    W_val.append(curr_W)
    cost_val.append(curr_cost)

# matplotlib 모듈을 이용하여 cost(loss) 함수 그리기
plt.plot(W_val, cost_val)
plt.show()


  • 위 코드 실행 결과는 아래 그래프 처럼 볼록 함수의 그래프로 표시된다.
    • 이제 아래 그래프에서 극소값을 찾아야 한다.



cost(loss) 함수의 극소값 찾기

  • 기울기(경사도)는 미분을 이용하여 찾는다.
    • 오른쪽은 기울기가 양(+, positive)이고, 왼쪽은 음(-, negative)
    • 기울기가 양이면 왼쪽으로 움직여야 하기 때문에 기울기를 빼준다.
    • 기울기가 음이면 오른쪽을 움직여야 하기 때문에 기울기를 더해준다.
  • 아래 식 (1)을 코드로 구현
    • \(\alpha\) : learning rate = 0.1
    • \(\nabla=\frac{1}{m}\sum(Wx_i-y_y)x_i\) : gradient
    • 경사 하강법 : descent = W - learning_rate * gradient

\begin{equation}W = W - \alpha\frac{1}{m}\sum_{i=1}^m(W x_i - y_i) x_i\tag{1}\end{equation}


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)

# 가설은 H(W) = W * X
hypothesis = W * X

# cost(loss) 함수
cost = tf.reduce_mean(tf.square(hypothesis - Y))

# 미분계수(기울기=경사도)로 경사 하강법을 사용
# W = W - learning_rate * 미분계수(gradient)
learning_rate = 0.1
gradient = tf.reduce_mean((W * X - Y) * X)
descent = W - learning_rate * gradient
update = W.assign(descent)

# 세션에서 그래프 활성
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})
    print(f"STEP = {step:02}, cost(loss) 함수값 = {sess.run(cost, feed_dict={X: x_data, Y: y_data}):>.5},"
          f"기울기 = {sess.run(W)} ")


  • 실행 결과

STEP = 00, cost(loss) 함수값 = 0.604494512081146240234375,기울기 = [ 1.35990906] 
STEP = 00, cost(loss) 함수값 = 15.124,기울기 = [-0.80024123] 
STEP = 01, cost(loss) 함수값 = 4.302,기울기 = [ 0.03987139] 
STEP = 02, cost(loss) 함수값 = 1.2237,기울기 = [ 0.4879314] 
STEP = 03, cost(loss) 함수값 = 0.34807,기울기 = [ 0.72689676] 
STEP = 04, cost(loss) 함수값 = 0.099005,기울기 = [ 0.85434496] 
STEP = 05, cost(loss) 함수값 = 0.028161,기울기 = [ 0.92231733] 
STEP = 06, cost(loss) 함수값 = 0.0080104,기울기 = [ 0.95856923] 
STEP = 07, cost(loss) 함수값 = 0.0022785,기울기 = [ 0.9779036] 
STEP = 08, cost(loss) 함수값 = 0.0006481,기울기 = [ 0.98821527] 
STEP = 09, cost(loss) 함수값 = 0.00018435,기울기 = [ 0.99371481] 
STEP = 10, cost(loss) 함수값 = 5.2437e-05,기울기 = [ 0.99664789] 
STEP = 11, cost(loss) 함수값 = 1.4916e-05,기울기 = [ 0.99821222] 
STEP = 12, cost(loss) 함수값 = 4.2428e-06,기울기 = [ 0.9990465] 
STEP = 13, cost(loss) 함수값 = 1.2069e-06,기울기 = [ 0.99949145] 
STEP = 14, cost(loss) 함수값 = 3.4317e-07,기울기 = [ 0.9997288] 
STEP = 15, cost(loss) 함수값 = 9.764e-08,기울기 = [ 0.99985534] 
STEP = 16, cost(loss) 함수값 = 2.7743e-08,기울기 = [ 0.99992287] 
STEP = 17, cost(loss) 함수값 = 7.9032e-09,기울기 = [ 0.99995887] 
STEP = 18, cost(loss) 함수값 = 2.2452e-09,기울기 = [ 0.99997807] 
STEP = 19, cost(loss) 함수값 = 6.3691e-10,기울기 = [ 0.99998832] 
STEP = 20, cost(loss) 함수값 = 1.8353e-10,기울기 = [ 0.99999374] 



TensofFlow를 이용하여 cost(loss) 함수의 극소값 찾기

  • 텐서플로우를 이용하면 cost(loss) 함수를 미분하지 않아도 된다.
  • 다음과 같이 2줄로 코딩할 수 있다.
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.1)
train = optimizer.minimize(cost) 
  • \(W\)의 값을 초기에 5로 설정하고 위의 코드로 실행하는 코드

import tensorflow as tf

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

# W의 값을 5로 설정하고 학습 시킨다
W = tf.Variable(5.0)

# 학습 모델의 가설
hypothesis = W * X

# cost(loss) 함수
cost = tf.reduce_mean(tf.square(hypothesis - Y))

# 텐서플로우에서 제공하는 경사 하강법 메서드(이것이 매직이다!!!)
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(20):
    print(f"STEP = {step:03}, 기울기 = {sess.run(W):>.5}")
    sess.run(train)


  • 초기값 5.0으로 실행한 결과

    • 초기값 5.0으로 시작해서 빠르게 1로 수렴한다.
    • 미분해서 구한 결과보다 더 정확하게 나온다.
STEP = 000, 기울기 = 5.0
STEP = 001, 기울기 = 1.2667
STEP = 002, 기울기 = 1.0178
STEP = 003, 기울기 = 1.0012
STEP = 004, 기울기 = 1.0001
STEP = 005, 기울기 = 1.0
STEP = 006, 기울기 = 1.0
STEP = 007, 기울기 = 1.0
STEP = 008, 기울기 = 1.0
STEP = 009, 기울기 = 1.0
STEP = 010, 기울기 = 1.0
STEP = 011, 기울기 = 1.0
STEP = 012, 기울기 = 1.0
STEP = 013, 기울기 = 1.0
STEP = 014, 기울기 = 1.0
STEP = 015, 기울기 = 1.0
STEP = 016, 기울기 = 1.0
STEP = 017, 기울기 = 1.0
STEP = 018, 기울기 = 1.0
STEP = 019, 기울기 = 1.0


  • 초기값 -3.0으로 실행한 결과

STEP = 000, 기울기 = -3.0
STEP = 001, 기울기 = 0.73333
STEP = 002, 기울기 = 0.98222
STEP = 003, 기울기 = 0.99881
STEP = 004, 기울기 = 0.99992
STEP = 005, 기울기 = 0.99999
STEP = 006, 기울기 = 1.0
STEP = 007, 기울기 = 1.0
STEP = 008, 기울기 = 1.0
STEP = 009, 기울기 = 1.0
STEP = 010, 기울기 = 1.0
STEP = 011, 기울기 = 1.0
STEP = 012, 기울기 = 1.0
STEP = 013, 기울기 = 1.0
STEP = 014, 기울기 = 1.0
STEP = 015, 기울기 = 1.0
STEP = 016, 기울기 = 1.0
STEP = 017, 기울기 = 1.0
STEP = 018, 기울기 = 1.0
STEP = 019, 기울기 = 1.0




+ Recent posts