梯度下降法是一种常见的优化算法,在机器学习中应用很广泛。本文从代码的角度,带你理解梯度下降法。
优化指的是改变x以最小化或最大化某个函数 f(x) 的任务。通常以最小化 f(x) 指代大多数最优化问题。最大化可以通过最小化 -f(x) 来实现。
在机器学习领域,我们把要最小化或最大化的函数称为目标函数(objective function)或准则(criterion)。当我们对其进行最小化时,也把它称为代价函数(cost function)、损失函数(loss function)或误差函数(error function)。1
优化算法中常用的迭代方法有线性搜索和置信域方法等。线性搜索的策略是寻找方向和步长,具体算法有:梯度下降法、牛顿法、共轭梯度法等。2
梯度下降法为一阶收敛算法,当靠近局部最小解时梯度变小,收敛速度会变慢,并且可能以“之字形”的方式下降。如果目标函数为二阶连续可微,可以采用牛顿法,牛顿法(Newton’smethod)为二阶收敛算法,收敛速度更快,但是每次迭代需要计算Hessian矩阵的逆矩阵,复杂度较高。2下一章解析牛顿法。
梯度(gradient)是相对一个向量求导的导数: f f f的导数是包含所有偏导数的向量,记为 ∇ x f ( x ) \nabla_\boldsymbol{x} f(\boldsymbol x) ∇xf(x)。梯度的第 i i i个元素是 f f f关于 x i \boldsymbol{x}_i xi的偏导数。在多维情况下,临界点是梯度中所有元素都为零的点。
梯度下降(gradient descent)的原理是,梯度向量指向上坡,负梯度向量指向下坡。在负梯度方向上移动可以减小f。
所以,为了让目标函数继续减小,第t+1步的更新值由第t步的值向负梯度方向移动:
x t + 1 = x t − α ∇ x f ( x ) \boldsymbol x_{t+1} = \boldsymbol x_t - α\nabla_\boldsymbol{x} f(\boldsymbol x) xt+1=xt−α∇xf(x)
α是学习率,用于控制梯度下降的速度。一般初始取值0.01、0.001等,可以在训练过程中动态调整。
采用梯度下降法的前提是,我们需要构建一个可以求偏导的目标函数,然后通过不断迭代,得到一个符合预期的结果。
具体的,假如f的值由x、y两个变量确定,则梯度可以这样表示:
∇ f ( x , y ) = ∂ f ∂ x i + ∂ f ∂ y j \nabla f(x,y)=\frac{\partial{f}}{\partial{x}}\bold{i}+\frac{\partial{f}}{\partial{y}}\bold{j} ∇f(x,y)=∂x∂fi+∂y∂fj
下面用代码具体举例梯度下降的算法步骤。
我们用梯度下降法来求多元函数z=f(x,y)的最小值,计算每一次迭代后的坐标位置,并绘制在三维空间中,查看目标函数值是否按照期望下降。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
# 目标函数
def f(x,y):
return x**2 + y**2 + x*y
# 对x求偏导
def partial_x(x,y):
return 2*x+y
# 对y求偏导
def partial_y(x,y):
return 2*y+x
X = np.arange(-10, 10, 1)
Y = np.arange(-10, 10, 1)
X, Y = np.meshgrid(X, Y)
Z = f(X,Y)
# 绘制曲面
fig = plt.figure()
ax = Axes3D(fig)
surf = ax.plot_wireframe(X, Y, Z, rstride=1, cstride=1, cmap=cm.viridis)
#ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.viridis)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
# 随机初始点
x = 8
y = 5
z = f(x,y)
next_x = x
next_y = y
xlist=[x]
ylist=[y]
zlist=[z]
# 设定一个学习率
step = 0.01
while True:
next_x = x-step*partial_x(x,y)
next_y = y-step*partial_y(x,y)
next_z = f(next_x,next_y)
#print(next_x,next_y,next_z)
# 小于阈值时,停止下降
if z - next_z < 1e-9:
break
x = next_x
y = next_y
z = f(x,y)
xlist.append(x)
ylist.append(y)
zlist.append(z)
ax.plot(xlist,ylist,zlist,'r--')
plt.show()
当梯度下降停止时,当前到达的(x,y,z)坐标为:
x=0.000222924064513216,y=-0.00022292403194797448,z=4.9695131279517545e-08
与f(x,y)的最小值误差在可接受范围内,优化完成。
《深度学习》 ↩︎
《神经网络与深度学习》 ↩︎ ↩︎