미분은 변수의 움직임에 따른 함수값의 변화를 측정하기 위한 도구
고등학교때 배웠던 극한의 개념.
import sympy as sym
from sympy.abc import x
sym.diff(sym.poly(x**2 + 2*x +3),x ) #x로 미분하는 함수
Poly(2*x +2, x, domain='ZZ') # 결과값으로 왼쪽과 같이 나오게 된다.
요즘엔 컴퓨터로 미분이 가능한 시대라 손으로 할 필요는 없다.
(gradient ascent)
라고 한다.Input : gradient, init, lr, eps, Output : var
gradient : 미분을 계산하는 함수
init: 시작점, lr: 학습률, eps: 알고리즘 종료 조건
var = init
grad = gradient(var)
while(abs(grad) > eps):
var = var - lr * grad # 학습률을 잘 고려해서 정해야한다.
grad = gradient(var)
입력이 다변수 함수의 경우 편미분(partial differentiation)을 사용해야한다.
x를 편미분한다면, 나머지 변수 y는 그냥 상수 취급을한다.
var = init
grad = gradient(var)
while(norm(grad) > eps): # norm 을 사용 하는걸 주의.
var = var - lr * grad
grad = gradient(var)
기습 복습! :
제1 노름 : 각 성분의 변화량을 절대값하여 더하기
L1-노름은 이상치에 덜 민감하고, 벡터의 희소성(sparcity)을 더 잘 반영하는 등의 장점이 있습니다.
제2 노름: 피타고라스 정리를 사용해 유클리드 거리를 계산
L2-노름은 가장 흔히 사용되는 노름 중 하나이며, 종종 벡터의 크기를 나타내는 데 사용됩니다.
유클리드란? :
우리가 학교다닐때 많이 썻던 이 공식을 말함.
함수 : f(x) = X2 + 2x + 3 일때 경사하강법으로 최소점을 찾는 코드
def func(val):
fun = sym.poly(x**2+2+x+3)
return fun.subs(x, val), fun
def func_gradient(fun, val):
_, function = fun(val)
diff = sym.diff(function, x)
return diff.subs(x, val), diff
def gradient_descent(fun,init_point,lr_rate=1e-2, epsilon = 1e-5):
cnt = 0
val = init_point
diff,_=func_gradient(fun,init_point)
while np.abs(diff)> epsilon:
val = val - lr_rate*diff
diff, _ = func_gradient(fun,val)
cnt+=1
print('함수:{}, 연산횟수: {},최소점:({},{})".format(fun(val)[1],cnt,val,fun(val)[0]))
gradient_descent(fun*func,init_point*np.random.uniform(-2,2))
X = np.array([[1,1], [1,2], [2,2], [2,3]])
y = np.dot(X, np.array([1,2])) + 3
beta_gd = [10.1, 15.1, -6.5]
X_ = np.array([np.append(x,[1]) for x in X]) #intercept 항 추가
for t in range(100): # 100이 학습횟수
error = y - X_ @ beta_gd
# error = error / np.linalg.norm(error)
grad = -np.transpose(X_) @ error
beta_gd = beta_gd - 0.01 * grad # 0.01이 러닝레이트.
print(beta_gd)