인공지능/딥 러닝

[모두의 딥러닝] 04. 오차 수정하기: 경사 하강법

Chipmunks 2018. 5. 6.
728x90


경사 하강법(gradient decent) : 그래프에서 오차를 비교해 가장 작은 방향으로 이동 시키는 방법


1. 미분의 개념

순간 변화율 : 어느 한 점에서 x를 0에 가까운 변화를 준 것. y에 값도 0에 가까운 변화를 가짐

기울기 : 그래프에서 점 a 에서의 순간 변화율



2. 경사 하강법의 개요


x를 적절히 조절해 순간 기울기가 0인 x = m 인 지점을 찾는것이 경사 하강법의 원리다.

즉, 반복적으로 기울기 a를 변화시켜 m의 값을 찾아가는 기법이다.


3. 학습률

위 사진에서 기울기의 부호를 바꿔 이동시킨다. 이 때 적절한 거리를 찾지 못해 너무 멀리 이동시키면 a 값이 한 점으로 모이지 않게 된다. 따라서 어느 만큼 이동시킬지를 결정해야 한다. 즉 이것을 학습률(learning rate)라고 한다.

오차의 변화에 따라 이차 함수 그래프를 만들고 적절한 학습률을 설정해 미분 값이 0인 지점을 구한다. y 절편 b 의 값도 이와 같은 성질을 가지고 있다. 따라서 최적의 b 값을 구할 때 역시 경사 하강법을 사용한다.


4. 코딩으로 확인하는 경사 하강법

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 텐서플로 라이브러리 가져오기
import tensorflow as tf
 
# 데이터, x축 데이터, y축 데이터, 학습률
data = [[281], [493], [691], [897]]
x_data = [x_row[0for x_row in data]
y_data = [y_row[1for y_row in data]
 
learning_rate = 0.1
 
# 기울기 a와 절편 b의 값을 임의로 정한다. a는 0~10 사이, b는 0~100 사이
= tf.Variable(tf.random_uniform([1], 010, dtype = tf.float64, seed = 0))
= tf.Variable(tf.random_uniform([1], 0100, dtype = tf.float64, seed = 0))
 
# 일차방정식
= a * x_data + b
 
# 평균 제곱근 오차, 텐서플로 RMSE 함수
rmse = tf.sqrt(tf.reduce_mean(tf.square( y - y_data )))
 
# 경사 하강법, RMSE값을 최소로 하는 값 찾기
gradient_decent = tf.train.GradientDescentOptimizer(learning_rate).minimize(rmse)
 
# 텐서플로 실행 후 결괏값 출력
with tf.Session() as sess:
    # 변수 초기화
    sess.run(tf.global_variables_initializer())
    # 2001번 실행(0번째를 포함하므로)
    for step in range(2001):
        sess.run(gradient_decent)
        # 100번마다 결과 출력
        if step % 100 == 0:
            print("Epoch: %.f, RMSE = %.04f, 기울기 a = %.4f, y 절편 b = %.4f" % (step, sess.run(rmse), sess.run(a), sess.run(b)))
 
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Epoch: 0, RMSE = 30.2139, 기울기 a = 7.5235, y 절편 b = 80.5984
Epoch: 100, RMSE = 2.8860, 기울기 a = 2.2299, y 절편 b = 79.4181
Epoch: 200, RMSE = 2.8826, 기울기 a = 2.2601, y 절편 b = 79.2379
Epoch: 300, RMSE = 2.8815, 기울기 a = 2.2773, y 절편 b = 79.1353
Epoch: 400, RMSE = 2.8811, 기울기 a = 2.2871, y 절편 b = 79.0770
Epoch: 500, RMSE = 2.8810, 기울기 a = 2.2927, y 절편 b = 79.0438
Epoch: 600, RMSE = 2.8810, 기울기 a = 2.2958, y 절편 b = 79.0249
Epoch: 700, RMSE = 2.8810, 기울기 a = 2.2976, y 절편 b = 79.0142
Epoch: 800, RMSE = 2.8810, 기울기 a = 2.2987, y 절편 b = 79.0081
Epoch: 900, RMSE = 2.8810, 기울기 a = 2.2992, y 절편 b = 79.0046
Epoch: 1000, RMSE = 2.8810, 기울기 a = 2.2996, y 절편 b = 79.0026
Epoch: 1100, RMSE = 2.8810, 기울기 a = 2.2998, y 절편 b = 79.0015
Epoch: 1200, RMSE = 2.8810, 기울기 a = 2.2999, y 절편 b = 79.0008
Epoch: 1300, RMSE = 2.8810, 기울기 a = 2.2999, y 절편 b = 79.0005
Epoch: 1400, RMSE = 2.8810, 기울기 a = 2.3000, y 절편 b = 79.0003
Epoch: 1500, RMSE = 2.8810, 기울기 a = 2.3000, y 절편 b = 79.0002
Epoch: 1600, RMSE = 2.8810, 기울기 a = 2.3000, y 절편 b = 79.0001
Epoch: 1700, RMSE = 2.8810, 기울기 a = 2.3000, y 절편 b = 79.0001
Epoch: 1800, RMSE = 2.8810, 기울기 a = 2.3000, y 절편 b = 79.0000
Epoch: 1900, RMSE = 2.8810, 기울기 a = 2.3000, y 절편 b = 79.0000
Epoch: 2000, RMSE = 2.8810, 기울기 a = 2.3000, y 절편 b = 79.0000
cs


에포크(Epoch) : 입력 값에 대해 몇 번이나 반복하여 실험했는지를 나타냄.


=> 평균 제곱근 오차(Root Mean Square Error, RMSE)의 변화, 기울기 a가 2.3에 수렴하는 것 y 절편 b가 79에 수렴하는 과정을 볼 수 있음. 이는 최소 제곱법으로 확인한 결과와 같음


똑같은 방식으로 x가 여러 개인 다중 선형 회귀에서도 사용이 가능하다.

5. 다중 선형 회귀란?

실제 성적 사이에도 오차가 있다. 그 이유는 공부한 시간 이외의 다른 요소가 성적에 영향을 끼쳤기 때문이다.
추가로 과외 수업 횟수를 조사했다.



두 개의 독립 변수 x1과 x2가 생겼다. 이를 사용해 종속 변수 y를 만들어야 한다. 기울기를 두 개 구해야 한다.



6. 코딩으로 확인하는 다중 선형 회귀 실습

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import tensorflow as tf
 
# x1, x2, y의 데이터 값
 
data = [[2081], [4493], [6291], [8397]]
x1 = [x_row1[0for x_row1 in data]
x2 = [x_row2[1for x_row2 in data] # 새로 추가되는 값
y_data = [y_row2[2for y_row2 in data]
 
learning_rate = 0.1
 
a1 = tf.Variable(tf.random_uniform([1], 010, dtype = tf.float64, seed=0))
a2 = tf.Variable(tf.random_uniform([1], 010, dtype = tf.float64, seed=0)) # 새로 추가되는 값
= tf.Variable(tf.random_uniform([1], 0100, dtype = tf.float64, seed=0))
 
# 새로운 방정식 y = a1x1 + a2x2 + b
= a1 * x1 + a2 * x2 + b
 
# 평균 제곱근 오차, 텐서플로 RMSE 함수
rmse = tf.sqrt(tf.reduce_mean(tf.square( y - y_data )))
 
# 경사 하강법, RMSE값을 최소로 하는 값 찾기
gradient_decent = tf.train.GradientDescentOptimizer(learning_rate).minimize(rmse)
 
# 텐서플로 실행 후 결괏값 출력
with tf.Session() as sess:
    # 변수 초기화
    sess.run(tf.global_variables_initializer())
    # 2001번 실행(0번째를 포함하므로)
    for step in range(2001):
        sess.run(gradient_decent)
        # 100번마다 결과 출력
        if step % 100 == 0:
            print("Epoch: %.f, RMSE = %.04f, 기울기 a1 = %.4f, 기울기 a2 = %.4f, y 절편 b = %.4f" % (step, sess.run(rmse), sess.run(a1), sess.run(a2), sess.run(b)))
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Epoch: 0, RMSE = 49.1842, 기울기 a1 = 7.5270, 기울기 a2 = 7.8160, y 절편 b = 80.5980
Epoch: 100, RMSE = 1.8368, 기울기 a1 = 1.1306, 기울기 a2 = 2.1316, y 절편 b = 78.5119
Epoch: 200, RMSE = 1.8370, 기울기 a1 = 1.1879, 기울기 a2 = 2.1487, y 절편 b = 78.1057
Epoch: 300, RMSE = 1.8370, 기울기 a1 = 1.2122, 기울기 a2 = 2.1571, y 절편 b = 77.9352
Epoch: 400, RMSE = 1.8370, 기울기 a1 = 1.2226, 기울기 a2 = 2.1607, y 절편 b = 77.8636
Epoch: 500, RMSE = 1.8370, 기울기 a1 = 1.2269, 기울기 a2 = 2.1622, y 절편 b = 77.8335
Epoch: 600, RMSE = 1.8370, 기울기 a1 = 1.2288, 기울기 a2 = 2.1628, y 절편 b = 77.8208
Epoch: 700, RMSE = 1.8370, 기울기 a1 = 1.2295, 기울기 a2 = 2.1631, y 절편 b = 77.8155
Epoch: 800, RMSE = 1.8370, 기울기 a1 = 1.2299, 기울기 a2 = 2.1632, y 절편 b = 77.8133
Epoch: 900, RMSE = 1.8370, 기울기 a1 = 1.2300, 기울기 a2 = 2.1632, y 절편 b = 77.8124
Epoch: 1000, RMSE = 1.8370, 기울기 a1 = 1.2301, 기울기 a2 = 2.1633, y 절편 b = 77.8120
Epoch: 1100, RMSE = 1.8370, 기울기 a1 = 1.2301, 기울기 a2 = 2.1633, y 절편 b = 77.8118
Epoch: 1200, RMSE = 1.8370, 기울기 a1 = 1.2301, 기울기 a2 = 2.1633, y 절편 b = 77.8117
Epoch: 1300, RMSE = 1.8370, 기울기 a1 = 1.2301, 기울기 a2 = 2.1633, y 절편 b = 77.8117
Epoch: 1400, RMSE = 1.8370, 기울기 a1 = 1.2301, 기울기 a2 = 2.1633, y 절편 b = 77.8117
Epoch: 1500, RMSE = 1.8370, 기울기 a1 = 1.2301, 기울기 a2 = 2.1633, y 절편 b = 77.8117
Epoch: 1600, RMSE = 1.8370, 기울기 a1 = 1.2301, 기울기 a2 = 2.1633, y 절편 b = 77.8117
Epoch: 1700, RMSE = 1.8370, 기울기 a1 = 1.2301, 기울기 a2 = 2.1633, y 절편 b = 77.8117
Epoch: 1800, RMSE = 1.8370, 기울기 a1 = 1.2301, 기울기 a2 = 2.1633, y 절편 b = 77.8117
Epoch: 1900, RMSE = 1.8370, 기울기 a1 = 1.2301, 기울기 a2 = 2.1633, y 절편 b = 77.8117
Epoch: 2000, RMSE = 1.8370, 기울기 a1 = 1.2301, 기울기 a2 = 2.1633, y 절편 b = 77.8117
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import numpy as np
import statsmodels.api as statm
import statsmodels.formula.api as statfa
import pandas as pd
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
 
data = [[2081], [4493], [6291], [8397]]
= [i[0:2for i in data]
= [i[2for i in data]
 
X_1=statm.add_constant(X)
results=statm.OLS(Y,X_1).fit()
 
hour_class=pd.DataFrame(X,columns=['study_hours','private_class'])
hour_class['Score']=pd.Series(Y)
 
model = statfa.ols(formula='Score ~ study_hours + private_class', data=hour_class)
 
results_formula = model.fit()
 
a, b = np.meshgrid(np.linspace(hour_class.study_hours.min(),hour_class.study_hours.max(),100),
                   np.linspace(hour_class.private_class.min(),hour_class.private_class.max(),100))
 
X_ax = pd.DataFrame({'study_hours': a.ravel(), 'private_class': b.ravel()})
fittedY=results_formula.predict(exog=X_ax)
fig = plt.figure()
 
graph = fig.add_subplot(111, projection='3d')
 
graph.scatter(hour_class['study_hours'],hour_class['private_class'],hour_class['Score'],
              c='blue',marker='o', alpha=1)
graph.plot_surface(a,b,fittedY.reshape(a.shape),
                   rstride=1, cstride=1, color='none', alpha=0.4)
graph.set_xlabel('study_hours')
graph.set_ylabel('private_class')
graph.set_zlabel('Score')
 
plt.show()
cs



1차원 예측 직선이 3차원 '예측 평면'으로 바뀌었다.

좀 더 정밀한 예측을 할 수 있게 됐다.

댓글