티스토리 뷰
앞선 포스팅에서
선형 회귀에 대한 내용을 알아보았다.
이번에는 경사 하강법에 대해
쉬운 소개를 해보려고 한다.
1. 경사 하강법이란(Gradient Descent)
위와 같은 그래프에서
오차가 제일 적은 지점은
a = m일 때이다.
아래로 볼록한 함수의
가장 아랫 부분을 찾는 것이다.
a가 m에서 멀어질 수록 오차는 커진다.
즉, m과 같은 a(기울기)를 찾았을 때
오차가 최소화 된다는 개념이다.
이 m을 찾아가는 과정을
위 그래프와 같이
경사를 하강시키며 (m에 수렴시키며)
적합한 a를 찾는 과정을
경사하강법이라고 한다.
처음 그래프를 보면
잘 이해가 안될 수 있는데,
우리는 이차함수 그래프 중
y=ax+b인 그래프에만 익숙하기 때문이다.
그래서 이를 x에 대하여 미분한 값인
a를 기울기라고 칭해왔다.
y=ax+b 그래프에서
y는 오차(E)가 되고 x는 기울기(a)로 바꾸면
위의 그래프와 같다.
그래서 최솟값 m에서의 순간 기울기가
0이 될 때가
오차가 최소화되는 지점인 것이다.
오차 함수 그래프에서
미분 값이 0인 지점을 찾아라!
가 우리의 미션이다.
오차 함수에 대해서 이해가 가지 않는다면
를 참고하길 바란다.
2. 학습률 (learning rate, lr)
우리는 경사가 계속 하강하듯이 (그림 2 참고)
a의 지점을 바꿔주면서 m으로 수렴시키는데,
어느만큼 이동시킬지,
이동 거리를 결정하는 것이 학습률이다.
학습률의 값은 최적의 값이라는 건 없고,
적절히 바꿔주면서 최적의 학습률을 찾아야 한다.
+ 추가
y=ax+b 식이 있을 때,
적절한 a만 찾는다고
미분 값이 0인 지점을 찾을 수 있는 것이 아니라,
b값도 고려해야 한다.
b값이 너무 크거나 작으면
오차도 함께 커지기 때문이다.
이 b도 역시 경사 하강법을 통해 구한다.
3. 어떻게 하는가?
최솟값이 되는 지점을 찾으려면
이차 함수의 미분이 필요하다.
그 이차 함수는 평균 제곱 오차 함수가 된다.
평균 제곱 오차의 식은 원래
$\frac{1}{n}\sum_ \ (\hat{y_{i}}-y_{i})^2$인데,
$\hat{y_{i}}$은 원래 $x_{i}$를
대입했을 때의 값이므로,
$y_{i}=ax_{i}+b$를 대입하면
$\frac{1}{n}\sum_ \ ((ax_{i}+b)-y_{i})^2$
와 같이 바뀐다.
이 식을 우리가 궁금해하는 a와 b를 위해
각각 a와 b로 편미분 한다.
이를 코딩으로 옮기면 된다.
평균 제곱 오차를 a/b로 미분한 결과를
학습률을 곱해 기존의 a, 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 matplotlib.pyplot as plt
import numpy as np
data = [[2, 81], [4, 93], [6, 91], [8, 97]] # 데이터셋 설정
x = [i[0] for i in data] # [2, 4, 6, 8]이 됨
y = [i[1] for i in data] # [81, 93, 91, 97]이 됨
x_data = np.array(x) # 넘파이 배열로 변환
y_data = np.array(y)
a = 0 # 기울기 a를 0으로 초기화
b = 0 # y절편 b를 0으로 초기화
lr = 0.05 # 학습률 설정 (learning rate)
epochs = 2000 # 반복 횟수 설정
# 경사 하강법 시작
for i in range(epochs):
y_pred = a * x_data + b # y 예측 값을 구하는 식
error = y_data - y_pred # 오차 error = y 값 - y 예측 값
a_diff = -(1 / len(x_data)) * sum(x_data * (error)) # 평균 제곱 오차를 a로 미분한 값
b_diff = -(1 / len(x_data)) * sum(y_data - y_pred) # 평균 제곱 오차를 b로 미분한 값
a = a - lr * a_diff # 학습률 * 미분 결과 후 기존 a 값 업데이트
b = b - lr * b_diff # 학습률 * 미분 결과 후 기존 b 값 업데이트
if i % 100 == 0: # epoch가 100번 반복될 때마다 아래의 내용을 출력
print("epoch = %.f, 기울기 = %.04f, 절편 = %.04f, 에러 = %.04f" % (i, a, b, error.mean()))
plt.scatter(x, y) # 이하 그래프 출력
plt.plot([min(x_data), max(x_data)], [min(y_pred), max(y_pred)])
plt.show()
|
cs |
설명은 주석에 붙여두긴 했으나,
본인의 경우에는 line 23-24의 과정이
잘 이해되지 않았었다.
line 23-24 :
a_diff와 b_diff가
오차 함수를 각각 a, b로
편미분 한 변수인데
a_diff = -(1 / len(x_data)) * sum(x_data * (error)) # 평균 제곱 오차를 a로 미분한 값
b_diff = -(1 / len(x_data)) * sum(y_data - y_pred) # 평균 제곱 오차를 b로 미분한 값
갑자기 식이 이렇게 프로그래밍화 되는 것이
이해하기 어려웠다.
는 시그마 값의 2/n이니
평균을 구한다는 것인데,
2가 왜 갑자기 1이 되는가에 대해서는
어차피 lr(학습률)을 곱하기 때문에
있으나 마나 한 수라고 이해했다.
(그저 수식을 간단하게 하는 것이다.)
이후 * sum(x_data * (error)) 부분은
(error)가 y^ - y 이고,
y^는 ax+b이기 때문에,
x * (ax+b-y)
= x_data * (y^-y)
= x_data * error가 된 것이다.
x, y가 1개가 아니라
$x_{i}$처럼 여러 데이터이기 때문에
sum() 을 한 것이다.
이를 epoch를 통해 여러번 반복한 후
matplotlib을 이용하여
line 32부터 그래프 출력을 한다.
- 결과
최적의 기울기 a는 2.3,
y 절편 b는 79가 나왔고
에러 값이 0에 도달했다.
epoch가 100번일 때마다
결과값을 출력하도록 했으므로
2000번째까지 보고 싶다면
epoch를 2001로 조정하면 된다.
여기서 line 33의 plt.plot()는
그래프의 x축과 y축 값을 설정해주는 것인데,
plt.plot([min(x_data), max(x_data)], [min(y_pred), max(y_pred)])
라고 썼으므로
파란색 직선의 그래프를 나타낸다고 할 수 있다.
즉, x값에 따른 y값의 예측 그래프인 것이다.
파란색 점은 원래 있던 데이터셋의 정보이다.
아래는 경사 하강법을 공부하는 데에 있어
많은 의문을 해결하게 해준 좋은 포스팅들이다.
더 깊게 공부해보고 싶다면
참고하시길 권한다.
https://m.blog.naver.com/marketing815/221783327249
https://brunch.co.kr/@linecard/447
'Programming Language > AI with Python' 카테고리의 다른 글
[Python] 선형회귀 (2) / 기울기 a와 y절편 b에 따른 평균 오차 제곱(MSE) 프로그래밍 하기, 선형회귀 실습 (0) | 2021.03.30 |
---|---|
[Python] 선형회귀 (1) / 최소제곱법의 프로그래밍과 결과값 그래프로 나타내기 (0) | 2021.03.26 |
[Python] 선형회귀 / Linear Regression Model / Basic (0) | 2021.03.26 |
[Python] 로봇 기자가 쓰는 야구 기사 (0) | 2021.03.24 |
[Python] 텍스트 파일에 있는 단어의 개수를 세는 프로그램 (0) | 2021.03.24 |
- Thanks for comming.
- 오늘은
- 명이 방문했어요
- 어제는
- 명이 방문했어요