神经网络基础部件-优化算法详解(代码片段)

author author     2023-02-07     669

关键词:

前言

所谓深度神经网络的优化算法,即用来更新神经网络参数,并使损失函数最小化的算法。优化算法对于深度学习非常重要,如果说网络参数初始化(模型迭代的初始点)能够决定模型是否收敛,那优化算法的性能则直接影响模型的训练效率。

了解不同优化算法的原理及其超参数的作用将使我们更有效的调整优化器的超参数,从而提高模型的性能。

本文的优化算法特指: 寻找神经网络上的一组参数 $\\theta$,它能显著地降低损失函数 $J(\\theta )$,该损失函数通常包括整个训练集上的性能评估和额外的正则化项。

一,梯度下降优化算法

1.1,随机梯度下降 SGD

梯度下降法是最基本的一类优化器,目前主要分为三种梯度下降法:标准梯度下降法(GD, Gradient Descent),随机梯度下降法(SGD, Stochastic Gradient Descent)及批量梯度下降法(BGD, Batch Gradient Descent)。

深度学习项目中的 SGD 优化一般默认指批量梯度下降法。其算法描述如下:

  • 输入和超参数: $\\eta$ 全局学习率

  • 计算梯度:$g_t = \\nabla_\\theta J(\\theta_t-1)$

  • 更新参数:$\\theta_t = \\theta_t-1 - \\eta \\cdot g_t$

SGD 优化算法是最经典的神经网络优化方法,虽然收敛速度慢,但是收敛效果比较稳定

下图1展现了随机梯度下降算法的梯度搜索轨迹示意图。可以看出由于梯度的随机性质,梯度搜索轨迹要很嘈杂(动荡现象)。

因此,在实际应用中,随机梯度下降 SGD 法必须和动态学习率方法结合起来使用,否则使用固定学习率 + SGD的组合会使得模型收敛过程变得更复杂。

1.2,动量 Momentum

虽然随机梯度下降仍然是非常受欢迎的优化方法,但其学习过程有时会很慢且其梯度更新方向完全依赖于当前 batch 样本数据计算出的梯度,因而十分不稳定,因为数据可能有噪音。

受启发于物理学研究领域研究,基于动量 Momentum (Polyak, 1964) 的 SGD 算法用于改善参数更新时可能产生的振荡现象。动量算法旨在加速学习,特别是处理高曲率、小但一致的梯度,或是带噪声的梯度。两种算法效果对比如下图 2所示。

Momentum 算法的通俗理解就是,其模拟了物体运动时的惯性,即更新参数的时候会同时结合过去以及当前 batch 的梯度。通俗来讲就是,Momentum 算法更新的时候在一定程度上保留之前更新的方向,同时利用当前batch 的梯度微调最终的更新方向。这样一来,可以在一定程度上增加稳定性,从而学习地更快,并且还有一定摆脱局部最优的能力。

下图3动量算法的前进方向。第一次的梯度更新完毕后,会记录 $v1$ 的动量值。在“求梯度点”进行第二次梯度检查时,得到2号方向,与 $v1$ 的动量组合后,最终的更新为2方向。这样一来,由于有 $v1$ 的存在,会迫使梯度更新方向具备“惯性”,从而可以减小随机样本造成的震荡。

Momentum 算法描述如下:

1,输入和参数:

  • $\\eta$ - 全局学习率
  • $\\alpha$ - 动量参数,一般取值为 0.5, 0.9, 0.99,取 0,则等效于常规的随机梯度下降法,其控制动量信息对整体梯度更新的影响程度
  • $v_t$ - 当前时刻的动量,初值为 0。

2,算法计算过程

  • 计算梯度:$g_t = \\nabla_\\theta J(\\theta_t-1)$

  • 计算速度更新:$v_t = \\alpha \\cdot v_t-1 + \\eta \\cdot g_t$ (公式1)

  • 更新参数:$\\theta_t = \\theta_t-1 - v_t$ (公式2)

通过推导参数更新迭代公式,更容易理解算法,根据算法公式(1)(2),以$W$参数为例,有:

  1. $v_0 = 0$
  2. $dW_0 = \\nabla J(w)$
  3. $v_1 = \\alpha v_0 + \\eta \\cdot dW_0 = \\eta \\cdot dW_0$
  4. $W_1 = W_0 - v_1=W_0 - \\eta \\cdot dW_0$
  5. $dW_1 = \\nabla J(w)$
  6. $v_2 = \\alpha v_1 + \\eta dW_1$
  7. $W_2 = W_1 - v_2 = W_1 - (\\alpha v_1 +\\eta dW_1) = W_1 - \\alpha \\cdot \\eta \\cdot dW_0 - \\eta \\cdot dW_1$
  8. $dW_2 = \\nabla J(w)$
  9. $v_3=\\alpha v_2 + \\eta dW_2$
  10. $W_3 = W_2 - v_3=W_2-(\\alpha v_2 + \\eta dW_2) = W_2 - \\alpha^2 \\eta dW_0 - \\alpha \\eta dW_1 - \\eta dW_2$

可以看出与普通 SGD 的算法 $W_3 = W_2 - \\eta dW_2$ 相比,动量法不但每次要减去当前梯度,还要减去历史梯度$W_0, W_1$ 乘以一个不断减弱的因子$\\alpha$、$\\alpha^2$,因为$\\alpha$小于1,所以$\\alpha^2$比$\\alpha$小,$\\alpha^3$比$\\alpha^2$小。这种方式的学名叫做指数加权平均。

在实际模型训练中,SGD 和动量法的比较如下表所示。

算法 损失函数和准确率
SGD
Momentum

从上表的对比可以看出,同一个深度模型, 普通随机梯度下降法的曲线震荡很严重,且经过 epoch=10000 次也没有到达预定 0.001 的损失值;但动量算法经过 2000 个 epoch 就迭代结束。

1.3,Nesterov 动量

受 Nesterov 加速梯度算法 (Nesterov, 1983, 2004) 启发,Sutskever et al. (2013) 提出了动量算法的一个变种,Nesterov 动量随机下降法(NAG ,英文全称是 Nesterov Accelerated Gradient,或者叫做 Nesterov Momentum 。

Nesterov 动量随机梯度下降方法是在上述动量梯度下降法更新梯度时加入对当前梯度的校正,简单解释就是往标准动量方法中添加了一个校正因子

NAG 算法描述如下:

1,输入和参数

  • $\\eta$ - 全局学习率
  • $\\alpha$ - 动量参数,缺省取值0.9
  • $v$ - 动量,初始值为0

2,算法计算过程

  • 参数临时更新:$\\hat \\theta = \\theta_t-1 - \\alpha \\cdot v_t-1$
  • 网络前向传播计算:$f(\\hat \\theta)$
  • 计算梯度:$g_t = \\nabla_\\hat\\theta J(\\hat \\theta)$
  • 计算速度更新:$v_t = \\alpha \\cdot v_t-1 + \\eta \\cdot g_t$
  • 更新参数:$\\theta_t = \\theta_t-1 - v_t$

1.4,代码实践

Pytorch 框架中把普通 SGD、Momentum 算法和 Nesterov Momentum 算法的实现结合在一起了,对应的类是 torch.optim.SGD。注意,其更新公式与其他框架略有不同,其中 $p$、$g$、$v$、$\\mu$ 表示分别是参数、梯度、速度和动量。

$$ \\beginaligned v_t+1 &= \\mu * v_t + g_t+1 \\ p_t+1 &= p_t - \\textlr * v_t+1 \\ &= p_t - \\textlr * \\mu * v_t - \\textlr * g_t+1 \\endaligned $$

# 和源码比省略了部分不常用参数
class torch.optim.SGD(params, lr=required, momentum=0, dampening=0,
                 weight_decay=0, nesterov=False)

1,功能解释

可实现 SGD 优化算法、带动量 SGD 优化算法、带 NAG(Nesterov accelerated gradient)动量 SGD 优化算法,并且均可拥有 weight_decay 项。

2,参数解释

  • params(iterable): 参数组(参数组的概念参考优化器基类: Optimizer),即优化器要管理的那部分参数。

  • lr(float): 初始学习率,可按需随着训练过程不断调整学习率。

  • momentum(float): 动量因子,通常设置为 0.9,0.8。

  • weight_decay(float): 权值衰减系数,也就是 L2 正则项的系数。

  • nesterov(bool)- bool 选项,是否使用 NAG(Nesterov accelerated gradient)。

训练模型时常用配置如下:

torch.optim.SGD(lr=0.02, momentum=0.9, weight_decay=0.0001)

二,自适应学习率算法

神经网络研究员早就意识到学习率肯定是难以设置的超参数之一,因为它对深度学习模型的性能有着显著的影响。

2.1,AdaGrad

在 AdaGrad 提出之前,我们对于所有的参数使用相同的学习率进行更新,它是第一个自适应学习率算法,通过所有梯度历史平方值之和的平方根,从而使得步长单调递减。它根据自变量在每个维度的梯度值的大小来调整各个维度上的学习率,从而避免统一的学习率难以适应所有维度的问题。

AdaGrad 法根据训练轮数的不同,对学习率进行了动态调整。具体表现在,对低频出现的参数进行大的更新(快速下降的学习率),对高频出现的参数进行小的更新(相对较小的下降学习率)。因此,他很适合于处理稀疏数据。

AdaGrad 算法描述如下:

1,输入和参数

  • $\\eta$ - 全局学习率
  • $\\epsilon$ - 用于数值稳定的小常数,建议缺省值为1e-6
  • $r=0$ 初始值

2,算法计算过程

  • 计算梯度:$g_t = \\nabla_\\theta J(\\theta_t-1)$

  • 累计平方梯度:$r_t = r_t-1 + g_t \\odot g_t$

  • 计算梯度更新:$\\Delta \\theta = \\eta \\over \\epsilon + \\sqrtr_t \\odot g_t$(和动手学深度学习给出的学习率调整公式形式不同)

  • 更新参数:$\\theta_t=\\theta_t-1 - \\Delta \\theta$

$\\odot$ 按元素相乘,开方、除法和乘法的运算都是按元素运算的。这些按元素运算使得目标函数自变量中每个元素都分别拥有自己的学习率。

AdaGrad 总结:在凸优化背景中,AdaGrad 算法具有一些令人满意的理论性质。但是,经验上已经发现,对于训练深度神经网络模型而言,从训练开始时积累梯度平方会导致有效学习率过早和过量的减小。AdaGrad 在某些深度学习模型上效果不错,但不是全部

Pytorch 框架中 AdaGrad 优化器:

class torch.optim.Adagrad(params, lr=0.01, lr_decay=0, weight_decay=0, initial _accumulator_value=0)

2.2,RMSProp

RMSProp(Root Mean Square Prop),均方根反向传播。

RMSProp 算法 (Hinton, 2012) 和 AdaGrad 算法的不同在于, RMSProp算法使⽤了小批量随机梯度按元素平⽅的指数加权移动平均来调整学习率

RMSProp 算法描述如下:

1,输入和参数

  • $\\eta$ - 全局学习率,建议设置为0.001
  • $\\epsilon$ - 用于数值稳定的小常数,建议缺省值为1e-8
  • $\\alpha$ - 衰减速率,建议缺省取值0.9
  • $r$ - 累积变量矩阵,与$\\theta$尺寸相同,初始化为0

2,算法计算过程(计算梯度和更新参数公式和 AdaGrad 算法一样):

  • 累计平方梯度:$r = \\alpha \\cdot r + (1-\\alpha)(g_t \\odot g_t)$

  • 计算梯度更新:$\\Delta \\theta = \\eta \\over \\sqrtr + \\epsilon \\odot g_t$

RMSProp 总结:经验上,RMSProp 已被证明是一种有效且实用的深度神经网络优化算法。目前,它是深度学习从业者经常采用的优化方法之一。其初始学习率设置为 0.01 时比较理想。

Pytorch 框架中 RMSProp 优化器:

class torch.optim.RMSprop(params, lr=0.01, alpha=0.99, eps=1e- 08, weight_decay=0, momentum=0, centered=False)

2.3,AdaDelta

AdaDelta 法也是对 AdaGrad 法的一种改进,它旨在解决深度模型训练后期,学习率过小问题。相比计算之前所有梯度值的平方和,AdaDelta 法仅计算在一个大小为 $w$ 的时间区间内梯度值的累积和。

RMSProp 算法计算过程如下:

1,参数定义

  • Adadelta 没有学习率参数。相反,它使用参数本身的变化率来调整学习率。

  • $s$ - 累积变量,初始值 0

2,算法计算过程:

  • 计算梯度:$g_t = \\nabla_\\theta J(\\theta_t-1)$
  • 累积平方梯度:$s_t = \\alpha \\cdot s_t-1 + (1-\\alpha) \\cdot g_t \\odot g_t$
  • 计算梯度更新:$\\Delta \\theta = \\sqrtr_t-1 + \\epsilon \\over s_t + \\epsilon \\odot g_t$
  • 更新梯度:$\\theta_t = \\theta_t-1 - \\Delta \\theta$
  • 更新变化量:$r = \\alpha \\cdot r_t-1 + (1-\\alpha) \\cdot \\Delta \\theta \\odot \\Delta \\theta$

Pytorch 框架中 AdaDelta 优化器:

class torch.optim.Adadelta(params, lr=1.0, rho=0.9, eps=1e- 06, weight_decay=0)

2.4,Adam

Adam (Adaptive Moment Estimation,Kingma and Ba, 2014) 是另一种学习率自适应的优化算法,相当于 RMSProp + Momentum 的效果,即动量项的 RMSprop 算法

Adam 算法在 RMSProp 算法基础上对小批量随机梯度也做了指数加权移动平均。和 AdaGrad 算法、RMSProp 算法以及 AdaDelta 算法一样,目标函数自变量中每个元素都分别拥有自己的学习率

Adam 算法计算过程如下:

1,参数定义

  • $t$ - 当前迭代次数
  • $\\eta$ - 全局学习率,建议缺省值为0.001
  • $\\epsilon$ - 用于数值稳定的小常数,建议缺省值为1e-8
  • $\\beta_1, \\beta_2$ - 矩估计的指数衰减速率,$\\in[0,1)$,建议缺省值分别为0.9和0.999

2,算法计算过程:

  • 计算梯度:$g_t = \\nabla_\\theta J(\\theta_t-1)$

  • 计数器加一:$t=t+1$

  • 更新有偏一阶矩估计:$m_t = \\beta_1 \\cdot m_t-1 + (1-\\beta_1) \\cdot g_t$

  • 更新有偏二阶矩估计:$v_t = \\beta_2 \\cdot v_t-1 + (1-\\beta_2)(g_t \\odot g_t)$

  • 修正一阶矩的偏差:$\\hat m_t = m_t / (1-\\beta_1^t)$

  • 修正二阶矩的偏差:$\\hat v_t = v_t / (1-\\beta_2^t)$

  • 计算梯度更新:$\\Delta \\theta = \\eta \\cdot \\hat m_t /(\\epsilon + \\sqrt\\hat v_t)$

  • 更新参数:$\\theta_t=\\theta_t-1 - \\Delta \\theta$

从上述公式可以看出 Adam 使用指数加权移动平均值来估算梯度的动量和二次矩,即使用了状态变量 $m_t、v_t$。

怎么理解 Adam 算法?

首先,在 Adam 中,动量直接并入了梯度一阶矩(指数加权)的估计。将动量加入 RMSProp 最直观的方法是将动量应用于缩放后的梯度。结合缩放的动量使用没有明确的理论动机。其次,Adam 包括偏置修正,修正从原点初始化的一阶矩(动量项)和(非中心的)二阶矩的估计。RMSProp 也采用了(非中心的)二阶矩估计,然而缺失了修正因子。因此,不像 Adam,RMSProp 二阶矩估计可能在训练初期有很高的偏置。 Adam 通常被认为对超参数的选择相当鲁棒,尽管学习率有时需要从建议的默认修改。

Adam 算法实现步骤如下。

Adam 总结:由于 Adam 继承了 RMSProp 的传统,所以学习率同样不宜设置太高,初始学习率设置为 0.01 时比较理想。

Pytorch 框架中 Adam 优化器:

class torch.optim.Adam(params, lr=0.001, betas=(0.9, 0.999), eps=1e- 08, weight_decay=0, amsgrad=False)

三,总结

3.1,PyTorch 的十个优化器

PyTorch 中所有的优化器基类是 Optimizer 类,在 Optimizer 类中定义了 5 个 实用的基本方法,分别是

  • zero_grad():将梯度清零。
  • step(closure):执行一步权重参数值更新, 其中可传入参数 closure(一个闭包)。
  • state_dict():获取模型当前参数,以一个有序字典形式返回,key 是参数名,value 是参数。
  • load_state_dict(state_dict) :将 state_dict 中的参数加载到当前网络,常用于 finetune。
  • add_param_group(param_group):给 optimizer 管理的参数组中增加一组参数,可为该组参数定制 lr, momentum, weight_decay 等,在 finetune 中常用。

PyTorch 基于 Optimizer 基类构建了十种优化器,有常见的 SGD、ASGD、Rprop、 RMSprop、Adam 等等。注意 PyTorch 中的优化器和前文描述的优化算法略有不同,PyTorch 中 给出的优化器与原始论文中提出的优化方法,多少是有些改动的,详情可直接阅读源码。

3.2,优化算法总结

  • Adam 等自适应学习率算法对于稀疏数据具有优势,且收敛速度很快;但精调参数的 SGD(+Momentum)往往能够取得更好的最终结果。

  • 用相同数量的超参数来调参,尽管有时自适应优化算法在训练集上的 loss 更小,但是他们在测试集上的 loss 却可能比 SGD 系列方法高。

  • 自适应优化算法在训练前期阶段在训练集上收敛的更快,但可能在测试集上的泛化性不好。

  • 目前,最流行并且使用很高的优化算法包括 SGD、具动量的 SGD、RMSProp、 具动量的 RMSProp、AdaDelta 和 Adam。但选择哪一个算法主要取决于使用者对算法的熟悉程度(更方便调节超参数)。

参考资料

  1. 《智能之门-神经网络与深度学习入门》-15.2 梯度下降优化算法
  2. 《深度学习》-第八章 深度模型中的优化
  3. 《动手学深度学习》-优化算法

基于蝙蝠算法优化bp神经网络的数据分类算法及其matlab实现-附代码(代码片段)

基于蝙蝠算法优化BP神经网络的数据分类算法及其MATLAB实现-附代码文章目录基于蝙蝠算法优化BP神经网络的数据分类算法及其MATLAB实现-附代码1蝙蝠算法与BP神经网络分类模型1.1蝙蝠算法BA1.2one-hot编码2基于蝙蝠算法BA优化的BP神经... 查看详情

入门神经网络优化算法:gradientdescent,momentum,nesterovacceleratedgradient(代码片段)

入门神经网络优化算法(一):GradientDescent,Momentum,Nesterovacceleratedgradient入门神经网络优化算法(二):AdaptiveOptimizationMethods:Adagrad,RMSprop, 查看详情

基于文化算法优化的神经网络预测研究(matlab代码实现)(代码片段)

目录1文化优化算法2 人工神经网络3Matlab代码及详细文章阅读4 基于文化算法优化的神经网络预测研究(Matlab代码实现)运行结果5参考文献 6写在最后1文化优化算法大自然里的各种生物在生存环境中相互竞争,优胜... 查看详情

神经网络基础部件-卷积层详解(代码片段)

前言在全连接层构成的多层感知机网络中,我们要通过将图像数据展平成一维向量来送入模型,但这会忽略了每个图像的空间结构信息。理想的策略应该是要利用相近像素之间的相互关联性,将图像数据二维矩阵送给模型中学习... 查看详情

详解神经网络基础部件bn层(代码片段)

...f0c;而BN可以解决这个问题。本文分享自华为云社区《神经网络基础部件-BN层详解》,作者:嵌入式视觉。一,数学基础1.1,概率密度函数随机变量(randomvariable)是可以随机地取不同值的变量。随机变量可... 查看详情

优化预测基于matlab粒子群算法优化bp神经网络(多输入多输出)含matlab源码1418期(代码片段)

一、粒子群算法及BP神经网络简介由于BP神经网络在应用过程中初始权值和阈值随机选取,容易出现局部收敛极小点,从而降低拟合效果,为了解决这个问题,采用PSO优化BP神经网络(PSO-BP)算法的初始权值和阈值,解决局部极小点问题,提... 查看详情

优化预测基于matlab灰狼算法优化bp神经网络预测含matlab源码1720期(代码片段)

一、灰狼算法及BP神经网络简介1BP算法BP(Back—Propagation)神经网络是由Rumelhart,McClelland提出的概念,其结构简单、可操作性强,具有非线性映射能力,是目前应用最广泛的人工神经网络。但BP算法存在收敛速度慢、容易陷入局部最优等... 查看详情

算法bp神经网络结构详解!(代码片段)

BP神经网络结构与原理参数表示$n_l$:表示网络层数,此处为4$L_l$​:表示第l层,L1是输入层,$L_n$​是输出层,其他为隐含层$w^(l)_ij$​:表示第l+1层第i个单元与第l层第j个单元的连接权重$b^(l)_i$:表示第l层第i个单元的偏置项(... 查看详情

备战数学建模40-遗传算法优化bp神经网络(攻坚站4)(代码片段)

BP神经网络主要用于预测和分类,对于大样本的数据,BP神经网络的预测效果较佳,BP神经网络包括输入层、输出层和隐含层三层,通过划分训练集和测试集可以完成模型的训练和预测,由于其简单的结构,... 查看详情

电力负荷预测基于matlab遗传算法优化bp神经网络电力负荷预测含matlab源码1524期(代码片段)

....6遗传算法的改进方向3遗传算法流程4关键参数说明二、BP神经网络简介1BP神经网络预测原理简介BP神经网络是一种多层前馈神经网络,常用的为输入层-单隐含层-输出层的三层结构,如下图所示。BP神经网络训练的主要思... 查看详情

bp预测基于遗传算法优化bp神经网络实现数据预测matlab源码(代码片段)

    一、BP神经网络预测算法简介说明:1.1节主要是概括和帮助理解考虑影响因素的BP神经网络算法原理,即常规的BP模型训练原理讲解(可根据自身掌握的知识是否跳过)。1.2节开始讲基于历史值影响的BP神经网... 查看详情

bp预测基于鲸鱼算法优化bp神经网络实现数据预测matlab源码(代码片段)

  一、BP神经网络预测算法简介说明:1.1节主要是概括和帮助理解考虑影响因素的BP神经网络算法原理,即常规的BP模型训练原理讲解(可根据自身掌握的知识是否跳过)。1.2节开始讲基于历史值影响的BP神经网络... 查看详情

bp预测基于遗传算法优化bp神经网络实现数据预测matlab源码(代码片段)

   一、BP神经网络预测算法简介说明:1.1节主要是概括和帮助理解考虑影响因素的BP神经网络算法原理,即常规的BP模型训练原理讲解(可根据自身掌握的知识是否跳过)。1.2节开始讲基于历史值影响的BP神经网... 查看详情

bp预测基于鲸鱼算法优化bp神经网络实现数据预测matlab源码(代码片段)

 一、BP神经网络预测算法简介说明:1.1节主要是概括和帮助理解考虑影响因素的BP神经网络算法原理,即常规的BP模型训练原理讲解(可根据自身掌握的知识是否跳过)。1.2节开始讲基于历史值影响的BP神经网络预... 查看详情

基于ga优化bp神经网络的传感器故障诊断算法matlab仿真(代码片段)

...同?一)可以改变网络参数的初始值,再用BP神经网络的反向传播来寻得整个网络参数的最优二)可以直接遗传算法优化整个网络参数, 查看详情

优化算法—梯度下降(代码片段)

...最流行的优化(optimization)算法,亦是至今最常用的优化神经网络的方法。本文旨在让你对不同的优化梯度下降法的算法有一个直观认识,以帮助你使用这些算法。我们首先会考察梯度下降法的各种变体,然后会简要地总结在训... 查看详情

bp预测基于粒子群算法优化bp神经网络实现数据预测matlab源码(代码片段)

     一、BP神经网络预测算法简介说明:1.1节主要是概括和帮助理解考虑影响因素的BP神经网络算法原理,即常规的BP模型训练原理讲解(可根据自身掌握的知识是否跳过)。1.2节开始讲基于历史值影响的BP神经... 查看详情

bp预测基于粒子群算法优化bp神经网络实现数据预测matlab源码(代码片段)

    一、BP神经网络预测算法简介说明:1.1节主要是概括和帮助理解考虑影响因素的BP神经网络算法原理,即常规的BP模型训练原理讲解(可根据自身掌握的知识是否跳过)。1.2节开始讲基于历史值影响的BP神经网... 查看详情