Computer_Language/TensorFlow _Python

[TensorFlow] Linear Regression - 선형 회귀에 대하여

Joo-Topia 2019. 8. 29. 15:27

 

 

In [1]:
import tensorflow as tf
import matplotlib.pyplot as plt
 

선형 회귀의 결과와 원본 그래프를 비교하기 위해
tensorflow 외에도 matplotlib.pyplot를 추가한다.

In [2]:
x_data = [0,1,2,3,4,5]
y_data = [1,3,5,7,9,11]
 

x_data 와 y_data를 입력해주고 plot함수로 먼저 함수를 그려본다.

In [3]:
plt.plot(x_data,y_data,'ys--', label = 'original_func')
plt.xlabel('x_data')
plt.ylabel('y_data')
plt.legend()
plt.grid(True)
plt.show
Out[3]:
<function matplotlib.pyplot.show(*args, **kw)>
 
 
 
 

이제 텐서플로우로 선형회귀를 구현해보자.

선형 회귀의 시작은 선형이라는 가설이다.
다음은 기울기(W)와 절편(b)를 정의하고 선형 함수를 정의하는 코드이다.

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

#hypothesis
hypo =W * x_data + b
 
 
 

이제 비용함수를 정의해야 한다.

아래 수식은 선형 회귀의 비용 함수이다.
$$cost(W,b) = {1\over m} \sum_{i=1}^m (H(x_i) - y_i)^2$$

선형 회귀에서 비용 함수는 "차(diff)의 제곱의 평균" 이라고 풀어서 말할 수 있다.
두 값의 "차" 가 아닌 "차의 제곱" 인 이유는

  1. 음수 값 처리
  2. diff가 증가할수록 cost는 제곱으로 증가하여 더 높은 penalty 부여

라고 한다.

수식은 복잡했지만, 한 줄 코드로 간단하게 cost함수를 정의할 수 있다.

In [5]:
#cost function
cost = tf.reduce_mean(tf.square(hypo - y_data))
 
 
 

다음은 cost함수를 최소화하는 node를 생성하는 코드이다.

In [6]:
#Minimize code
optimizer = tf.train.GradientDescentOptimizer(learning_rate = 0.01)
train = optimizer.minimize(cost)
 

경사 하강법으로 가장 작은 비용을 찾겠다는 코드이다.
경사 하강법을 풀어서 적기에는 너무 오래 거릴 것 같아서 나만의 언어로 다시 정리를 해 보았다.

차의 제곱의 평균은 아래로 볼록한 2차 함수꼴이다.
고등학교 수학시간에 배웠던 미분을 아래로 볼록한 2차 함수에 적용했을때
미분 값이 '0'이되는 지점(기울기가 '0')은 2차 함수의 최소값 이라는 것을 배웠던 기억이 난다.

그래서 경사 하강법은 아래로 볼록한 2차 함수의 특정 지점에서 점점 내려 오면서 미분 값이 '0'이 되는 지점을, 혹은 0에 가장 근접한 지점을 찾겠다는 분석 방법 이라고 내 마음대로 정리하고 머리에 넣었다.

위 코드에서 "GradientDescentOptimizer"의 "minimize"는 바로 위에서 언급한 과정이 수행되는 과정이고, train이 한번 실행될 때 마다, cost가 조금 더 0에 가까운 W와 b로 값이 변하게 된다.

이제 지금까지 만든 그래프로 학습을 시킨 후 맨 처음 함수와 비교 해보자!

In [7]:
#구현한 그래프를 실행시키기 위한 세션을 정의
sess = tf.Session()
#미리 정의했던 Variable인'W'와 'b'를 초기화 하기위한 과정 수행
sess.run(tf.global_variables_initializer())
In [8]:
#학습 결과 확인
train_cnt = 5001
for step in range(train_cnt):
    sess.run(train)
    #50번의 트레이닝 마다 학습결과 출력
    if step % 200 == 0:
        print('cnt : ',step,' 비용 : ', sess.run(cost), ' W: ',sess.run(W), ' b: ', sess.run(b))
 
cnt :  0  비용 :  103.15629  W:  [-0.8090303]  b:  [-0.9296248]
cnt :  200  비용 :  0.033112887  W:  [2.0908036]  b:  [0.6777854]
cnt :  400  비용 :  0.0030929528  W:  [2.027752]  b:  [0.90152335]
cnt :  600  비용 :  0.0002888993  W:  [2.0084817]  b:  [0.96990323]
cnt :  800  비용 :  2.6984022e-05  W:  [2.002592]  b:  [0.9908019]
cnt :  1000  비용 :  2.5210902e-06  W:  [2.0007925]  b:  [0.9971885]
cnt :  1200  비용 :  2.3597367e-07  W:  [2.0002427]  b:  [0.99913985]
cnt :  1400  비용 :  2.2168045e-08  W:  [2.0000744]  b:  [0.9997362]
cnt :  1600  비용 :  2.0751092e-09  W:  [2.0000226]  b:  [0.9999193]
cnt :  1800  비용 :  2.1784292e-10  W:  [2.0000076]  b:  [0.999974]
cnt :  2000  비용 :  3.6701902e-11  W:  [2.0000033]  b:  [0.99998975]
cnt :  2200  비용 :  2.800545e-11  W:  [2.000003]  b:  [0.9999909]
cnt :  2400  비용 :  2.800545e-11  W:  [2.000003]  b:  [0.9999909]
cnt :  2600  비용 :  2.800545e-11  W:  [2.000003]  b:  [0.9999909]
cnt :  2800  비용 :  2.800545e-11  W:  [2.000003]  b:  [0.9999909]
cnt :  3000  비용 :  2.800545e-11  W:  [2.000003]  b:  [0.9999909]
cnt :  3200  비용 :  2.800545e-11  W:  [2.000003]  b:  [0.9999909]
cnt :  3400  비용 :  2.800545e-11  W:  [2.000003]  b:  [0.9999909]
cnt :  3600  비용 :  2.800545e-11  W:  [2.000003]  b:  [0.9999909]
cnt :  3800  비용 :  2.800545e-11  W:  [2.000003]  b:  [0.9999909]
cnt :  4000  비용 :  2.800545e-11  W:  [2.000003]  b:  [0.9999909]
cnt :  4200  비용 :  2.800545e-11  W:  [2.000003]  b:  [0.9999909]
cnt :  4400  비용 :  2.800545e-11  W:  [2.000003]  b:  [0.9999909]
cnt :  4600  비용 :  2.800545e-11  W:  [2.000003]  b:  [0.9999909]
cnt :  4800  비용 :  2.800545e-11  W:  [2.000003]  b:  [0.9999909]
cnt :  5000  비용 :  2.800545e-11  W:  [2.000003]  b:  [0.9999909]
 

간단한 모델이여서 그런지 2200번 정도의 학습을 하니 그 뒤로는 비용과 W, b의 값이 변하지 않는다. (그래도 어느정도 여유를 주고 학습을 시키는 것이 좋다고 한다.)

학습한 모델을 처음 그래프와 비교 해보자.

In [9]:
#tensor객체에서 값을 빼오기위해 변수 선언
W_v, b_v = sess.run([W,b])


plt.plot(x_data,y_data,'ys--', label = 'original_func')
plt.plot(x_data,list(map(lambda x : W_v*x + b_v,x_data)),'rs', label = 'hypo_func')
#lambda 와 map을 사용하여 학습 결과를 출력

plt.xlabel('x_data')
plt.ylabel('y_data')
plt.legend()
plt.grid(True)

plt.show
Out[9]:
<function matplotlib.pyplot.show(*args, **kw)>
 
 

정말 간단한 모델이여서 그런지 정확하게 학습 된 결과를 볼 수 있다.
하지만 선형 회귀는 실 생활에 많이 적용 할 수가 없다고 한다.
앞으로 더 열심히, 많이 공부 해야겠다.

오늘 공부 끝~