梯度的一些笔记
导数、偏导数、方向导数、梯度的含义
导数
表示函数
f
(
x
)
f(x)
f(x)在该点的变化率。函数值在增量与在该点的自变量的增量的比值的极限存在的话,导数就存在,反应的是变化率的大小,导数的绝对值越大,说明变化幅度越大,变化越剧烈。如果是一元函数,表示的是函数在某一点的切线的斜率,斜率绝对值越大,表示越陡峭,即变化的幅度越大。
如果是时间
t
t
t 是自变量,位移
s
(
t
)
s(t)
s(t) 是时间
t
t
t 的函数,那么某一时刻的导数
s
′
(
t
)
s\prime(t)
s′(t) 就是这一时刻的瞬时速度。
偏导数
是个向量,多元函数 f ( x , y ) f(x,y) f(x,y)在点 ( x 0 , y 0 ) (x_0,y_0) (x0,y0)对各个坐标轴方向上的导数,例如向量 ( f x ( x 0 , y 0 ) , f y ( x 0 , y 0 ) ) (f_x(x_0,y_0),f_y(x_0,y_0)) (fx(x0,y0),fy(x0,y0))
方向导数
是偏导数概念的推广,是个向量,函数在某点沿着方向向量l的导数,方向向量l的指向有无数种
梯度
梯度也是个向量,数值为方向导数的最大值,方向地偏导数的方向
函数沿着梯度下降的方向,函数值下降的最快,这是很多梯度下降优化的基础。
为什么沿着梯度的反方向是下降最快的方向?
可以参考附录的链接地址,需要理清方向导数和梯度的关系,实际当目标函数 f ( x , y ) f(x,y) f(x,y)对直线 l : ( c o s α , c o s β ) l:(cos\alpha,cos\beta) l:(cosα,cosβ) 的导数的方向与梯度方向一致时,即方向导数与梯度的方向的方向完全一致,目标函数的方向导数取得最大值,即目标函数 f ( x , y ) f(x,y) f(x,y)沿着梯度方向值增长的最快,也就是说,按照梯度的反方向值下降的最快。
应用到机器学习
通常我们要优化的目标函数是一个损失函数 L o s s ( θ 1 , θ 2 , . . . , θ M ) Loss(\theta_1,\theta_2,...,\theta_M) Loss(θ1,θ2,...,θM),极小化这个目标函数,参数是我们要学习的机器学习参数 θ 1 , θ 2 , . . . , θ M \theta_1,\theta_2,...,\theta_M θ1,θ2,...,θM
我们首先计算出目标函数的梯度,然后按梯度反方向更新梯度,这样就可以使得目标函数的函数值以最快的方式下降到极小值。
θ
i
=
θ
i
−
λ
∂
L
o
s
s
(
θ
1
,
θ
2
,
.
.
.
,
θ
M
)
∂
θ
i
\theta_i = \theta_i - \lambda \frac{\partial Loss(\theta_1,\theta_2,...,\theta_M)}{\partial \theta_i}
θi=θi−λ∂θi∂Loss(θ1,θ2,...,θM)
λ
是学习率
\lambda 是学习率
λ是学习率
特别地,如果目标函数是凸函数,那么得到的极小值就是全局最小,此时得到的参数即为全局最优的参数解
梯度下降的示例
给定一批样例数据
x
,
f
(
x
)
x, f(x)
x,f(x),运用梯度下降求解参数
a
,
b
,
c
a, b, c
a,b,c
f
(
x
)
=
a
x
2
+
b
x
+
c
f(x) = ax^2 + bx+c
f(x)=ax2+bx+c
先构造一批数据,然后用梯度下降来求解
#!/usr/bin/python
import numpy as np
data = []
def build_data(a, b, c, num=10000):
for i in range(num):
x = np.random.uniform(-10, 10)
eps = np.random.normal(0, 0.001)
y = a * (x ** 2) + b * x + c + eps
data.append((x, y))
def calc_error(a, b, c):
error = 0
for i in data:
x = i[0]
y = i[1]
y_hat = a * (x ** 2) + b * x + c
error += (y_hat - y) ** 2 / (2 * len(data))
return error
def gradient_descent(a, b, c):
a_gradient = 0
b_gradient = 0
c_gradient = 0
for i in data:
x = i[0]
y = i[1]
bais = a * (x**2) + b * x + c - y
a_gradient += bais * (x ** 2)
b_gradient += bais * x
c_gradient += bais
a_gradient /= len(data)
b_gradient /= len(data)
c_gradient /= len(data)
return a_gradient, b_gradient, c_gradient
def train():
build_data(a=1.56,b=3.48,c=2.3)
a, b, c = 0, 0, 1
iter = 4000
lr = 0.0005
for i in range(iter):
error = calc_error(a, b, c)
a_grad, b_grad, c_grad = gradient_descent(a, b, c)
a = a - lr * a_grad
b = b - lr * b_grad
c = c - lr * c_grad
print('iter:', i, 'error', error, 'a', a, 'b', b, 'c', c, 'a_grad', a_grad, 'b_grad', b_grad, 'c_grad', c_grad)
train()