• 深度学习优化算法之梯度下降(泰勒展开式推导)


            有一定深度学习背景知识的伙伴们都知道,为了得到一个好的模型,都预先定义一个损失函数(优化的目标函数),然后使用合适的优化算法去试图得到一个最小值。优化的目标就是为了降低训练误差,对于深度学习的模型来说,是为了降低泛化误差,因为单纯的降低训练误差,有可能会造成过拟合。在尽可能降低损失函数的值的过程中,会遇到两个问题,局部最小值和鞍点。
            在实际问题中,目标函数都比较复杂,为了问题的简化,我们一般将目标函数在某点邻域展开成泰勒多项式来逼近原函数(一阶泰勒展开式就是拉格朗日中值定理),直接上图来看下泰勒展开式在某点的展开,通过推导我们得出了梯度下降的原理

    我们从图中的推导,了解到了梯度下降的原理,其中1阶的泰勒展开式也就是大家常说的拉格朗日中值定理 f(x)=f(a)+df(a)*(x-a)  —>  df(a)=[f(x)-f(a)]/x-a 这些公式对于导数与函数之间起到了桥梁作用,用处很大。

    局部最小值(Local Minimum)

    求解过程分为解析解和数值解,简单来说解析解就是数学公式直接推导求得,然而我们知道目标函数一般都比较复杂,所以基本上都是使用数值解。目标函数一般会有若干局部最小值,在这个附近的梯度接近或为0,那么最终迭代求得的值,很大程度上不是全局最小化,而是局部最小化。
    我们来看一个函数 f(x)=x*cos(π*x) 的走势图,代码如下

    1. import d2lzh as d2l
    2. from mpl_toolkits import mplot3d
    3. import numpy as np
    4. def f(x):
    5. return x*np.cos(np.pi*x)
    6. d2l.plt.rcParams['font.family']=['STFangsong']#显示中文
    7. d2l.set_figsize((5.5,3))
    8. x=np.arange(-1,2,0.1)
    9. fig,=d2l.plt.plot(x,f(x))
    10. #指向的最优值是大概位置
    11. fig.axes.annotate('局部最小值',xytext=(-0.77,-1.0),xy=(-0.25,-0.25),arrowprops=dict(arrowstyle="->"))
    12. fig.axes.annotate('全局最小值',xytext=(0.6,0.8),xy=(1.1,-0.95),arrowprops=dict(arrowstyle="->"))
    13. d2l.plt.xlabel('x')
    14. d2l.plt.ylabel('f(x)')

    图中可以看到这个函数存在局部最小值和全局最小值,一般情况得到的结果都是局部最小值。

    鞍点(Saddle Point)

    除了上面所说的情况之外,另一种就是在鞍点附近,也会使得梯度接近或为0
    我们来看下函数  f(x)=x³ 的走势情况,代码如下:

    1. def f(x):
    2. return x**3
    3. d2l.plt.rcParams['font.family']=['STFangsong']#显示中文
    4. x=np.arange(-2,2,0.1)
    5. fig,=d2l.plt.plot(x,f(x))
    6. fig.axes.annotate('鞍点',xytext=(-0.5,-5),xy=(0,-0.2),arrowprops=dict(arrowstyle="->"))
    7. d2l.plt.xlabel('x')
    8. d2l.plt.ylabel('f(x)')

    再看一个三维图形函数 f(x,y)=x²-y² 代码如下:

    1. d2l.plt.rcParams['font.family']=['STFangsong']#显示中文
    2. x,y=np.mgrid[-1:1:31j,-1:1:31j]
    3. print(x.shape)#(31, 31)
    4. z=x**2-y**2
    5. ax=d2l.plt.figure().add_subplot(111,projection='3d')
    6. ax.plot_wireframe(x,y,z,**{'rstride':2,'cstride':2})
    7. ax.plot([0],[0],[0],'rX')
    8. ticks=[-1,0,1]
    9. d2l.plt.xticks(ticks)
    10. d2l.plt.yticks(ticks)
    11. ax.set_zticks(ticks)
    12. d2l.plt.xlabel('x')
    13. d2l.plt.ylabel('y')

    从图中的鞍点位置(红色标注点)可以看出,目标函数在x轴方向上是局部最小值,但是在y轴方向上是局部最大值。那大概率求解出来的是属于哪种情况?我们通过海森矩阵(黑塞矩阵)来了解其原理

    海森矩阵(Hessian matrix)

    海森矩阵是一个多元函数的二阶偏导数构成的方阵,描述了函数的局部曲率,具体详情可以参阅百度百科的黑塞矩阵

    如图:

    假设函数输入是k维向量,输出是标量,那么黑塞矩阵(Hessian matrix)有k个特征值,该函数在梯度为0的位置上可能是局部最小值、局部最大值或者鞍点三种情况,出现概率如下:

    1、当函数的黑塞矩阵在梯度为0的位置上的特征值全为正时,该函数得到局部最小值
    2、当函数的黑塞矩阵在梯度为0的位置上的特征值全为负时,该函数得到局部最大值
    3、当函数的黑塞矩阵在梯度为0的位置上的特征值有正有负时,该函数得到鞍点

    对于一个大的高斯随机矩阵来说,正负概率各占一半,那从图中可以得出,1和2的情况的概率就是0.5的k次方,k一般很大,所以概率是很小的,也就是说目标函数更容易得到的是鞍点而不是局部最优值。

    虽然找到目标函数的全局最优解很难,但并非必要,下面的优化算法在实际问题中都能训练出十分有效的深度学习模型

    一维梯度下降

    对于梯度大家应该很熟悉了,一维就是导数,二维就是偏导数的集合,我们通过代码可视化梯度下降,看下具体是如何工作的。

    函数 f(x)=x² 我们知道其最小值是0,观察它的迭代,代码如下:

    1. def gd(eta):
    2. x=10
    3. results=[x]
    4. for i in range(10):
    5. x-=eta*2*x #f(x)=x²的导数是2x
    6. results.append(x)
    7. print('epoch 10,x:',x)
    8. return results
    9. res=gd(1.1)
    10. #可视化梯度下降轨迹
    11. def show_trace(res):
    12. #f_line=np.arange(-10,10,0.1)
    13. n=max(abs(min(res)),abs(max(res)),10)
    14. f_line=np.arange(-n,n,0.1)
    15. d2l.set_figsize()
    16. d2l.plt.plot(f_line,[x**2 for x in f_line])#抛物线
    17. d2l.plt.plot(res,[x**2 for x in res],'-o')#梯度迭代节点
    18. d2l.plt.xlabel('x')
    19. d2l.plt.ylabel('f(x)')
    20. show_trace(res)

    其中eta学习率是超参数,设定过小、合适、过大,分别看下什么效果:

    我们发现学习率过小,x更新缓慢,需要更多迭代才可以,过大就导致 |ηf'(x)| 过大,一阶泰勒展开式就不再成立,也就不能保证迭代x会降低f(x)的值了。

    多维梯度下降

    我们可以通过一维梯度推广到多维梯度,设目标函数的输入是一个d维向量,那么有关x的梯度就是一个有d个偏导数组成的向量,现在对函数 f(x)=x_{1}^{2} +2x_{2}^{2} 进行可视化观察梯度下降情况

    1. #d2lzh包中已有
    2. def train_2d(trainer):
    3. x1,x2,s1,s2=-5,-2,0,0
    4. results=[(x1,x2)]
    5. for i in range(20):
    6. x1,x2,s1,s2=trainer(x1,x2,s1,s2)#s1和s2是自变量状态,后期一些优化算法将被使用
    7. results.append((x1,x2))
    8. print('epoch %d,x1 %f,x2 %f' % (i+1,x1,x2))
    9. return results
    10. def show_trace_2d(f,results):
    11. d2l.plt.plot(*zip(*results),'-o',color='#ff7f0e')
    12. x1,x2=np.meshgrid(np.arange(-5.5,1.0,0.1),np.arange(-3.0,1.0,0.1))
    13. d2l.plt.contour(x1,x2,f(x1,x2),colors='#1f77b4')
    14. d2l.plt.xlabel('x1')
    15. d2l.plt.ylabel('x2')
    16. eta=0.1
    17. def f_2d(x1,x2):
    18. return x1**2 + 2*x2**2
    19. def gd_2d(x1,x2,s1,s2):
    20. return (x1-eta*2*x1,x2-eta*4*x2,0,0)
    21. show_trace_2d(f_2d,train_2d(gd_2d))
    22. #epoch 20,x1 -0.057646,x2 -0.000073

    想了解更多关于梯度的伙伴们可以点击:

    Python随机梯度下降法(一)

    Python随机梯度下降法(二)

    Python随机梯度下降法(三)

    Python随机梯度下降法(四)【完结篇】

  • 相关阅读:
    TensorRt推理部署优化方案及流程概述
    一线大厂研发流程
    python中的迭代器
    114. 二叉树展开为链表
    Linux安装免费Https证书,过期自动更新 省钱秘籍
    python实现ssl通信
    Linux:kkFileView v4.0.0 安装、启动教程
    Pod 管理与使用
    Android RecyclerView BaseSectionQuickAdapter实现分组功能
    携手!Kyligence 支持 Amazon EMR Serverless,赋能云上企业降本增效
  • 原文地址:https://blog.csdn.net/weixin_41896770/article/details/126721464