※ 본 글은 한경훈 교수님의 머신러닝 강의를 정리, 보충한 글입니다. ※
[딥러닝I] 8강. 수치미분과 gradient - YouTube
수치미분
우리가 고등학교때 배운 미분은 극한을 이용한 미분이었지만, 이를 컴퓨터에게 이해시키기는 매우 힘들다.
( 0 이 아니지만 한없이 0에 가까워진다는 극한의 개념을 수식으로 나타내기 힘들기 때문! )
따라서 h를 극한으로 보내는 대신, 아주 작은 값(이 책에서는 0.0001)으로 잡아 값을 근사시킨다.
이때, h를 0.0001 보다 더 작은 수로 근사시키면, 반올림 오차때문에 0으로 인식되는 경우도 있으므로 주의해야 한다.
또한 f(x+h)-(x)/h 보다 f(x+h)-(x-h)/2h가 실제 미분값 f'(x)에 더 가까우므로 수치미분으로 f(x+h)-(x-h)/2h의 값을 자주 사용한다.
def numerical_diff(f,x):
h = 1e-4 #0.0001
return (f(x+h)-f(x-h))/2*h
수치미분을 이용하여 접선 구하기
def tangent_line(f, x): # cf. 접선을 영어로 tangent_line이라 한다.
d = numerical_diff(f, x) # f'(x)
print(d)
y = f(x) - d * x # y = f(x) - f'(x)*x
return lambda t: d * t + y # g(t) = = f'(x)(t-x) + f(x)
x = np.arange(0.0, 20.0, 0.1) # [0, 0.1, 0.2, ..., 19.9]
y = function_1(x)
plt.xlabel("x")
plt.ylabel("f(x)")
tf = tangent_line(function_1, 5)
y2 = tf(x)
plt.plot(x, y) # 그래프
plt.plot(x, y2) # 접선 그래프
plt.show()
Gradient
모든 변수에 대한 편미분을 벡터로 정리한 것을 gradient(기울기)라고 하고 ∇를 앞에 붙여 표기한다.
ex, f(x,y)가 3x^2 * y 일 때, ∇ f(x,y) 는 (6yx, 3x^2) 이다.
gradient의 사용
기존에는 방향 미분계수를 구하기 위해 식 f(x+h)-f(x)/h 에 값을 직접 대입하곤 했다.
하지만 gradient와 방향 벡터를 내적하면 방향 미분계수를 바로 구할 수 있으므로 훨씬 간단해진다.
ex. f(x,y) = x^2 + y^2 일때, (1,1)로의 방향 미분계수는 ∇ f(x,y) = (2x, 2y)와 (1,1)을 내적한 2x + 2y 즉 4이다.
cf. 이를 바탕으로 접평면의 방정식을 구하면 아래와 같다.
$$z = ∇ f(x_0,y_0) ~ · ((x,y)-(x_0,y_0))+f(x_0,y_0)$$
방향 미분계수의 최대, 최소
함수 𝑓와 점 𝐱는 고정되어 있고 방향의 크기 |v| 는 1이라 하자.
방향 미분 계수는 gradient와 벡터의 내적이므로 아래와 같이 나태낼 수 있다.
$$∇ f(x) · v = ∇ f(x) |v| cosθ = ∇ f(x) cosθ$$
따라서 방향 미분이 가장 커지는 방향은 cosθ가 1일 때 (θ = 0)
즉, gradient 방향과 방향벡터의 방향이 같을 때이고, 방향미분계수의 최대값은 gradient의 크기이다.
같은 원리로, 방향 미분이 가장 작아지는 방향은 cosθ가 -1일 때 (θ = 180도)
즉, gradient 방향과 방향벡터의 방향이 반대일 때이고, 방향미분계수의 최소값은 - gradient의 크기이다.
정리
방향 미분이 가장 커지는 방향은 gradient 방향이고 값은 gradient의 크기이다.
⭐방향 미분이 가장 작아지는 방향은 gradient 반대 방향이고 값은 마이너스 gradient의 크기이다
방향 미분이 0이 되는 방향은 gradient와 수직인 방향이다.
🤔아니 우리는 머신러닝을 배우고 있는데 방향미분계수의 최대최소는 왜 배우는거지??
라고 생각할 수 있지만, 한경훈 교수님 피셜 위 정리는 머신러닝을 통틀어서 가장 중요한 수학적 정리라고 한다.
위 정리는 딥러닝과 머신러닝의 초석이 되기도 하고 쓰이기도 굉장히 자주 쓰인다고 한다! 이유는 뒤에 나옴!
등위선, 등위면
고등수학에서 일변수 함수 f(x)는 그래프를 좌표평면 위에 그릴 수 있었다.
하지만, 이변수함수나 삼변변수 함수는 3차원 이상이므로 평면위에 그래프를 그리기 힘들다.
이러한 문제를 해결하기 위해 도입한 개념이 바로 등위(곡)선, 등위(곡)면이다.
ex.
이변수함수 f(x,y)와 상수 c에 대해 [(x,y):f(x,y)=c]를 만족하는 f(x,y)를 f의 c - 등위선이라 한다.
삼변수함수 f(x,y,z)와 상수 c 에 대해 [(x,y,z):f(x,y,z)=c]를 만족하는 f(x,y,z)를 f의 c - 등위면이라 한다.
gradient 를 이용하면 등위곡선 or 등위곡면에서 함수값의 변화율이 가장 큰 방향을 찾을 수 있다.
'함수값이 가장 빨리 증가할 때는 gradient랑 같은 방향일 때이다.'라는 정리를 이용하면 된다.
같은 방법으로 함수값이 가장 빨리 감소하는 방향은 gradient랑 반대 방향이다.
등위선(면)에서 gradient의 의미는 기하학적으로도 해석될 수 있다.
원래는 수학적 증명을 거쳐야 하지만 내가 이해가 잘 안되므로 (...😓) 간단하게 증명하고 넘어가자!
등위선을 가장 빨리 올라가는 궤적은 등위선에 수직인 궤적이다.
앞서 우리는 함수값의 변화율이 최대일때의 방향은 gradient 방향인 것을 증명하였다.
따라서 등위선의 수직방향은 gradient 방향과 동일함을 알 수 있다.
⇒ 즉, 등위선(면)과 gradient는 항상 수직이다.
cf. 사실 1학년때 배운 미적분학에 대해 하나도 기억나지 않으므로 위의 정리가 맞는지는 잘 모르겠다..
여튼 중요한 것은 등위선(면)과 gradient가 항상 수직이라는 사실 아닐까..?
수치미분을 이용해 gradient 구현
def _numerical_gradient_no_batch(f, x): # batch가 아닌 경우 즉, x가 벡터인 경우
h = 1e-4 # 0.0001
grad = np.zeros_like(x) # x와 모양이 같고 원소가 0인 벡터 생성
for idx in range(x.size): # x = (a,b,c)이고 idx = 0 일때
tmp_val = x[idx] # tmp_val == a
# f(x+h) 계산
x[idx] = float(tmp_val) + h # x = (a+0.0001,b,c)
fxh1 = f(x) # fxh1 = f(a+0.0001,b,c)
# f(x-h) 계산
x[idx] = tmp_val - h # x = (a-0.0001,b,c)
fxh2 = f(x) # fxh2 = f(a-0.0001,b,c)
grad[idx] = (fxh1 - fxh2) / (2*h) # grad[0] = a에 대해 수치미분(편미분)
x[idx] = tmp_val # 값 복원 : x = (a,b,c)
return grad # grad = (a 편미분, b 편미분, c 편미분)
def numerical_gradient(f, X):
# x가 백터면 no_batch 로 처리
if X.ndim == 1:
return _numerical_gradient_no_batch(f, X)
# x가 행렬이면 batch로 판단하여 처리
else:
grad = np.zeros_like(X)
# enumerate - 인덱스 번호와 컬렉션의 원소를 tuple형태로 반환
# idx : 몇번째 행인지, x : 해당 행의 원소
for idx, x in enumerate(X):
grad[idx] = _numerical_gradient_no_batch(f, x)
return grad
이미지 출처 :
'ML' 카테고리의 다른 글
[ML] 딥러닝 1 - 10강 수치미분을 통한 학습 구현 (0) | 2021.08.22 |
---|---|
[ML] 딥러닝 1 - 9강 경사하강법 (0) | 2021.08.03 |
[ML] 딥러닝 1 - 7강 엔트로피 (0) | 2021.07.29 |
[ML] 딥러닝 1 - 6강 손실함수 (0) | 2021.07.23 |
[ML] 딥러닝 1 - 5강 신경망 구현 (0) | 2021.07.23 |