기계학습은 학습 단계에서 최적의 매개변수를 찾아내야 한다. 최적이란 손실 함수가 최솟값이 될 때의 매개변수 값인데 기울기를 이용해 함수의 최솟값을 찾으려는 것이 경사법이다.그런데 기울기가 가르키는 곳이 함수의 최솟값이 아닐수도 있다는 점을 명심해야한다. 복잡하게 생긴 함수(이를테면 3차 이상의)를 생각해보면 실제로 최솟값이 아닌데도 최솟값처럼 보이는 애들이 있다. 이것을 유의해야한다.
경사법은 현 위치에서 기울어진 방향으로 일정 거리만큼 이동한다. 이동한 곳에서 기울기를 구하고, 그 기울어진 방향으로 나아가서 함수의 값을 점차 줄인다. 경사법을 파이썬으로 구현하면 이렇다.
def gradient_descent(f, init_x, lr=0.01, step_num=100):
x = init_x
for i in range(step_num):
grad = numerical_gradient(f, x)
x -= lr * grad
return x
$$f(x_0,x_1)=x^2_0+x^2_1$$식의 최솟값을 구해보자.
import numpy as np
import matplotlib.pylab as plt
from mpl_toolkits.mplot3d import Axes3D
def gradient_descent(f, init_x, lr=0.01, step_num=100):
x = init_x
for i in range(step_num):
grad = numerical_gradient(f, x)
x -= lr * grad
return x
def _numerical_gradient_no_batch(f, x):
h = 1e-4
grad = np.zeros_like(x)
for idx in range(x.size):
tmp_val = x[idx]
x[idx] = tmp_val + h
fxh1 = f(x)
x[idx] = tmp_val - h
fxh2 = f(x)
grad[idx] = (fxh1 - fxh2) / (2*h)
x[idx] = tmp_val
return grad
def numerical_gradient(f, x):
if x.ndim == 1:
return _numerical_gradient_no_batch(f, x)
#받은 배열이 1차원이라면 그냥 진행한다.
else:
#2차원이 넘어간다면! 차원별로 나눠주어서 진행한다.
grad = np.zeros_like(x)
for idx, x in enumerate(x):
grad[idx] = _numerical_gradient_no_batch(f, x)
return grad
def function_2(x):
return x[0]**2 + x[1]**2
init_x = np.array([-3.0,4.0])
print(gradient_descent(function_2, init_x=init_x, lr=0.1, step_num=100))
#[-6.11110793e-10 8.14814391e-10]
이는 0에 가까운 결과로 최소값이 0,0인것을 우리는 알고 있기 때문에 근사하게 예측했다고 생각할 수 있다. 그림으로 나타내면 다음과 같다.
import numpy as np
import matplotlib.pylab as plt
from mpl_toolkits.mplot3d import Axes3D
def gradient_descent(f, init_x, lr=0.01, step_num=100):
x = init_x
output1 = []
output2 = []
for i in range(step_num):
output1.append(x[0])
output2.append(x[1])
grad = numerical_gradient(f, x)
x -= lr * grad
return output1, output2
def _numerical_gradient_no_batch(f, x):
h = 1e-4
grad = np.zeros_like(x)
for idx in range(x.size):
tmp_val = x[idx]
x[idx] = tmp_val + h
fxh1 = f(x)
x[idx] = tmp_val - h
fxh2 = f(x)
grad[idx] = (fxh1 - fxh2) / (2*h)
x[idx] = tmp_val
return grad
def numerical_gradient(f, x):
if x.ndim == 1:
return _numerical_gradient_no_batch(f, x)
#받은 배열이 1차원이라면 그냥 진행한다.
else:
#2차원이 넘어간다면! 차원별로 나눠주어서 진행한다.
grad = np.zeros_like(x)
for idx, x in enumerate(x):
grad[idx] = _numerical_gradient_no_batch(f, x)
return grad
def function_2(x):
return x[0]**2 + x[1]**2
if __name__ == '__main__':
init_x = np.array([-3.0,4.0])
output1, output2 = gradient_descent(function_2, init_x=init_x, lr=0.1, step_num=100)
plt.scatter(output1,output2)
plt.xlim([-4, 4])
plt.ylim([-5, 5])
plt.show()
그래프를 보면 근사값이 점점 0에 다가가는 것을 알 수 있다. 그치만 학습이 너무 적거나 많으면 어떤 일이 일어날까? lr값을 조정하여 학습해본다.
5로 줬더니 길을 잃고 헤맨다.
반대로 너무 조금 줘도 자기들끼리 찾아다니다가 지쳐서 뻗어버린다. 적당한 학습률이 중요하다.
'Python > DeepLearning' 카테고리의 다른 글
Tensorflow(keras)를 이용해 MNIST digits 분류해보기 (0) | 2019.04.24 |
---|---|
List에 값을 append했을 때 List 전체 값이 변하는 현상 (0) | 2019.04.23 |
퍼셉트론에서 신경망으로(6) (0) | 2019.04.23 |
퍼셉트론에서 신경망으로(5) (0) | 2019.04.23 |
퍼셉트론에서 신경망으로(4) (1) | 2019.04.22 |