深度学习中的梯度裁剪策略比较 (深度学习算法)
梯度裁剪是一种用于防止深度学习训练过程中梯度爆炸问题(即梯度值变得非常大,导致模型训练不稳定)的技术。通过限制梯度的最大值或最小值,它可以帮助模型更稳定地收敛。
梯度裁剪的基本理解
梯度裁剪的基本思想是在梯度更新之前,对梯度的值进行限制。如果梯度的模(即其大小)超过了预设的阈值,就将其缩放到阈值范围内。这样做可以防止梯度过大导致的训练不稳定性,同时也能在一定程度上避免梯度过小导致的训练停滞。
常见的梯度裁剪策略
2.1 全局裁剪(GlobalClipping)全局裁剪是最简单的一种裁剪策略。它对所有参数的梯度进行统一的阈值限制。如果梯度的模大于设定的阈值,就将其缩放到阈值大小;如果梯度的模小于阈值的负值,就将其缩放到阈值的负值大小。这种方法简单易实现,但可能不够灵活,因为它忽略了不同参数梯度的差异性。
2.2 局部裁剪(LocalClipping)局部裁剪策略针对每个参数或参数组单独设置阈值。这种方法更加灵活,因为它允许模型根据参数的敏感性来调整梯度的大小。这种方法的计算成本较高,因为需要为每个参数或参数组单独计算阈值。
2.3 梯度缩放(GradientScaling)梯度缩放是一种动态调整梯度的方法。在反向传播之前,先对梯度进行缩放,使得梯度的模不超过某个阈值。这种方法可以在一定程度上减少梯度爆炸的风险,同时保持梯度的动态范围。
2.4 梯度累积(GradientAccumulation)梯度累积不是直接裁剪梯度,而是通过累积多个小批量的梯度来模拟一个大批量的梯度。这种方法可以减少内存的使用,同时避免因批量大小过大导致的梯度爆炸问题。
梯度裁剪策略的比较
在实际应用中,选择哪种梯度裁剪策略取决于具体的任务和模型。全局裁剪因其简单性而被广泛使用,但它可能不适用于所有情况。局部裁剪提供了更高的灵活性,但计算成本较高。梯度缩放和梯度累积则提供了不同的解决方案,分别适用于不同的场景。
在实际比较中,我们可以考虑以下几个方面:
- 效果:不同的裁剪策略对模型收敛速度和最终性能的影响。
- 计算成本:实施每种策略所需的计算资源。
- 适用性:策略在不同类型的模型和任务中的适用性。
- 稳定性:策略在处理梯度爆炸和梯度消失问题时的稳定性。
梯度裁剪是深度学习中一个重要的概念,它有助于提高模型训练的稳定性和效率。不同的裁剪策略各有优势和局限性。在实际应用中,研究人员和工程师需要根据具体任务的需求和资源限制来选择合适的梯度裁剪策略。通过实验和调整,可以找到最适合当前模型和数据集的裁剪方法,从而优化训练过程,提高模型的性能。
随着深度学习技术的不断发展,未来可能会出现更多高效且灵活的梯度裁剪策略,以应对日益复杂的模型和任务。
优化算法总结
本文介绍一下机器学习和深度学习中常用的优化算法和优化器以及一些其他我知道的优化算法,部分算法我也没有搞懂,就先记录下来以后慢慢研究吧.*_*.1.梯度下降算法(Gradient Descent) 梯度下降法可以参考我另一篇文章 机器学习-线性回归 里的讲解,这里就不在重复叙述.这里需要强调一下,深度学习里常用的SGD,翻译过来是随机梯度下降,但是实质是mini-batch梯度下降(mini-batch-gd),或者说是两者的结合更准确一些. SGD的优点是,算法简单,计算量小,在函数为凸函数时可以找到全局最优解.所以是最常用的优化算法.缺点是如果函数不是凸函数的话,很容易进入到局部最优解而无法跳出来.同时SGD在选择学习率上也是比较困难的.2.牛顿法 牛顿法和拟牛顿法都是求解无约束最优化问题的常用方法,其中牛顿法是迭代算法,每一步需要求解目标函数的海森矩阵的逆矩阵,计算比较复杂. 牛顿法在求解方程根的思想:在二维情况下,迭代的寻找某一点x,寻找方法是随机一个初始点x_0,目标函数在该点x_0的切线与x坐标轴的交点就是下一个x点,也就是x_1.不断迭代寻找x.其中切线的斜率为目标函数在点x_0的导数(梯度),切必过点(x_0,f(x_0)).所以迭代的方程式如图1,为了求该方程的极值点,还需要令其导数等于0,也就是又求了一次导数,所以需要用到f(x)的二阶导数. 在最优化的问题中,牛顿法提供了一种求解的办法. 假设任务是优化一个目标函数f, 求函数ff的极大极小问题, 可以转化为求解函数f导数等于0的问题, 这样求可以把优化问题看成方程求解问题(f的导数等于0). 剩下的问题就和牛顿法求解方程根的思想很相似了. 目标函数的泰勒展开式: 化简后: 这样就得到了与图1相似的公式,这里是二维的,在多维空间上,求二阶导数就是求海森矩阵,因为是分母,所以还需要求海森矩阵的逆矩阵. 牛顿法和SGD的区别: 牛顿法是二阶求导,SGD是一阶求导,所以牛顿法要收敛的更快一些只考虑当前情况下梯度下降最快的方向,而牛顿法不仅考虑当前梯度下降最快,还有考虑下一步下降最快的方向. 牛顿法的优点是二阶求导下降速度快,但是因为是迭代算法,每一步都需要求解海森矩阵的逆矩阵,所以计算复杂.3.拟牛顿法(没搞懂,待定) 考虑到牛顿法计算海森矩阵比较麻烦,所以它使用正定矩阵来代替海森矩阵的逆矩阵,从而简化了计算过程. 常用的拟牛顿法有DFP算法和BFGS算法.4.共轭梯度法(Conjugate Gradient) 共轭梯度法是介于最速下降法与牛顿法之间的一个方法,它仅需利用一阶导数信息,但克服了最速下降法收敛慢的缺点,又避免了牛顿法计算海森矩阵并求逆的缺点.共轭梯度法不仅是解决大型线性方程组最有用的方法之一,也是解大型非线性最优化最有效的算法之一.5.拉格朗日法 参考SVM里的讲解 机器学习-SVM 6.动量优化法(Momentum) 动量优化法主要是在SGD的基础上,加入了历史的梯度更新信息或者说是加入了速度更新虽然是很流行的优化算法,但是其学习过程很慢,因为总是以同样的步长沿着梯度下降的方向.所以动量是为了加速学习的方法. 其中第一行的减号部分是计算当前的梯度,第一行是根据梯度更新速度v,而α是新引进的参数,在实践中,α的一般取值为 0.5,0.9 和 0.99.和学习率一样,α 也会随着时间不断调整.一般初始值是一个较小的值,随后会慢慢变大加速梯度(NAG, Nesterov accelerated gradient) NAG是在动量优化算法的基础上又进行了改进.根据下图可以看出,Nesterov 动量和标准动量之间的区别体现在梯度计算上, Nesterov 动量中,梯度计算在施加当前速度之后.因此,Nesterov 动量可以解释为往标准动量方法中添加了一个校正因子算法 AdaGrad算法,自适应优化算法的一种,独立地适应所有模型参数的学习率,缩放每个参数反比于其所有梯度历史平均值总和的平方根.具有代价函数最大梯度的参数相应地有个快速下降的学习率,而具有小梯度的参数在学习率上有相对较小的下降.通俗一点的讲,就是根据实际情况更改学习率,比如模型快要收敛的时候,学习率步长就会小一点,防止跳出最优解. 其中g是梯度,第一行的分母是计算累计梯度的平方根,是为了防止分母为0加上的极小常数项,α是学习率. Adagrad的主要优点是不需要人为的调节学习率,它可以自动调节.但是依然需要设置一个初始的全局学习率.缺点是随着迭代次数增多,学习率会越来越小,最终会趋近于算法 RMSProp修改 AdaGrad 以在非凸设定下效果更好,改变梯度积累为指数加权的移动平均旨在应用于凸问题时快速收敛算法 算法 Adam是Momentum和RMSprop的结合体,也就是带动量的自适应优化算法算法 13.模拟退火算法 14.蚁群算法 15.遗传算法 动量是为了加快学习速度,而自适应是为了加快收敛速度,注意学习速度快不一定收敛速度就快,比如步长大学习速度快,但是很容易跳出极值点,在极值点附近波动,很难达到收敛. 未完待定.... 参考: 《统计学习方法》 李航著 《深度学习》 花书
Batch Normlization原理
在深度学习中,由于问题的复杂性,我们往往会使用较深层数的网络进行训练,相信很多炼丹的朋友都对调参的困难有所体会,尤其是对深层神经网络的训练调参更是困难且复杂。
在这个过程中,我们需要去尝试不同的学习率、初始化参数方法(例如Xavier初始化)等方式来帮助我们的模型加速收敛。深度神经网络之所以如此难训练,其中一个重要原因就是网络中层与层之间存在高度的关联性与耦合性。下图是一个多层的神经网络,层与层之间采用全连接的方式进行连接。
我们规定左侧为神经网络的底层,右侧为神经网络的上层。那么网络中层与层之间的关联性会导致如下的状况:随着训练的进行,网络中的参数也随着梯度下降在不停更新。
Batch Normalization的原论文作者给了Internal Covariate Shift一个较规范的定义: 在深层网络训练的过程中,由于网络中参数变化而引起内部结点数据分布发生变化的这一过程被称作Internal Covariate Shift 。
这句话怎么理解呢?我们定义每一层的线性变换为,其中代表层数;非线性变换为,其中,为 第层的激活函数。
醉着梯度下降的进行,每一层的参数与都会被更新,那么的分布也就发生了改变,进而也同样出现分布的改变。而作为第层的输入,意味着层就需要去不停适应这种数据分布的变化,这一过程就被叫做Internal Covariate Shift。
(1)上层网络需要不停地调整来适应输入数据分布的变化,导致网络学习速度的降低
我们在上面提到梯度下降的过程会让每一层的参数和发生变化,进而使得每一层的线性与非线性计算结果分布产生变化。后层网络就要不停地适应这种分布的变化,这个时候就会使得整个网络的学习速率变慢。
(2)网络的训练过程容易陷入梯度饱和区,减缓网络收敛的速度
当我们在神经网络中采用饱和激活函数(saturated activation function)时,例如sigmoid,tanh激活函数,很容易使得模型训练陷入梯度饱和区(saturated regime)。随着模型训练的进行,我们的参数 会逐渐更新并变大,此时就会随着变大,并且还要收到更底层网络参数的影响,随着网络层数的增加,很容易陷入梯度饱和区,此时梯度会变得很小甚至接近与0,参数的更新速度就会变慢,进而就会放慢网络的收敛速度。
对于激活函数梯度饱和的问题,有两种解决思路:第一种就是使用ReLU等非线性激活函数,可以一定程度上解决训练陷入梯度饱和区的问题。另一种就是,我们可以让激活函数的分布保持在一个稳定的状态,来尽可能避免它们陷入梯度饱和区,也就是Normalization的思路。
要缓解ICS的问题,就要明白它产生的原因。ICS产生的原因是由于参数更新带来的网络中每一层输入值分布的改变,并且随着网络层数的加深而变得更加严重,因此我们可以通过固定每一层网络输入值的分布来对减缓ICS问题。
(1)白化
白化(Whitening)是机器学习里面常用的一种规范化数据分布的方法,主要是PCA白化与ZCA白化。白化是对输入数据分布进行变换,进而达到以下两个目的:
(2)Batch Normalization提出
既然白化可以解决这个问题,为什么我们还要提出别的解决办法?当然是现有的方法具有一定的缺陷,白化主要有以下两个问题:
既然有了上面两个问题,那我们的解决思路就很简单,一方面,我们提出的normalization方法要能够简化计算过程;另一方面又需要经过规范化处理后让数据尽可能保留原始的表达能力。于是就有了简化+改进版的白化——Batch Normalization。
既然白化计算过程比较复杂,那我们就简化一点,比如我们可以尝试单独对每个特征进行normalizaiton就可以了,让每个特征都有均值为0,方差为1的分布就OK。
另一个问题,既然白化操作减弱了网络中每一层输入数据表达能力,那我就再加个线性变换操作,让这些数据再能够尽可能恢复本身的表达能力就好了。
因此,基于上面两个解决问题的思路,作者提出了Batch Normalization,下一部分来具体讲解这个算法步骤。
![深度学习](https://tyye.cn/zb_users/theme/tpure/style/images/lazyload.png)
举例计算:
上图展示了一个batch size为2(两张图片)的Batch Normalization的计算过程。
假设feature1、feature2分别是由image1、image2经过一系列卷积池化后得到的特征矩阵,feature的channel数均为2,那么代表该batch的所有feature的channel1的数据,同理代表该batch的所有feature的channel2的数据。
然后分别计算和的均值和方差,得到我们的和两个向量。
然后在根据标准差计算公式分别计算每个channel的值(公式中的是一个很小的常量,防止分母为零的情况)
在我们训练网络的过程中,我们是通过一个batch一个batch的数据进行训练的,但是我们在预测过程中通常都是输入一张图片进行预测,此时batch size为1,如果在通过上述方法计算均值和方差就没有意义了。所以我们在训练过程中要去不断的计算每个batch的均值和方差,并使用移动平均(moving average)的方法记录统计的均值和方差,在我们训练完后我们可以近似认为我们所统计的均值和方差就等于我们整个训练集的均值和方差。然后在我们验证以及预测过程中,就使用我们统计得到的均值和方差进行标准化处理。
在训练过程中,均值和方差通过计算当前批次数据得到的记为和,而我们在预测过程中所使用的均值和方差是一个训练过程中保存的统计量,记和,和的具体更新策略如下,momentum默认取值为0.1:
需要注意的是:
下面是使用pytorch做的测试:
(1)bn_process函数是自定义的bn处理方法验证是否和使用官方bn处理方法结果一致。在bn_process中计算输入batch数据的每个维度(这里的维度是channel维度)的均值和标准差(标准差等于方差开平方),然后通过计算得到的均值和总体标准差对feature每个维度进行标准化,然后使用均值和样本标准差更新统计均值和标准差。 (2)初始化统计均值是一个元素为0的向量,元素个数等于channel深度;初始化统计方差是一个元素为1的向量,元素个数等于channel深度,初始化,。
设置一个断点进行调试,查看下官方bn对feature处理后得到的统计均值和方差。我们可以发现官方提供的bn的running_mean和running_var和我们自己计算的calculate_mean和calculate_var是一模一样的(只是精度不同):
输出结果如下:
从结果可以看出:通过自定义bn_process函数得到的输出以及使用官方bn处理得到输出,明显结果是一样的(只是精度不同)。
Batch Normalization在实际工程中被证明了能够缓解神经网络难以训练的问题,BN具有的有事可以总结为以下四点:
(1)BN使得网络中每层输入数据的分布相对稳定,加速模型学习速度
BN通过规范化与线性变换使得每一层网络的输入数据的均值与方差都在一定范围内,使得后一层网络不必不断去适应底层网络中输入的变化,从而实现了网络中层与层之间的解耦,允许每一层进行独立学习,有利于提高整个神经网络的学习速度。
(2)BN使得模型对网络中的参数不那么敏感,简化调参过程,使得网络学习更加稳定
在神经网络中,我们经常会谨慎地采用一些权重初始化方法(例如Xavier)或者合适的学习率来保证网络稳定训练。 当学习率设置太高时,会使得参数更新步伐过大,容易出现震荡和不收敛。但是使用BN的网络将不会受到参数数值大小的影响。 因此,在使用Batch Normalization之后,抑制了参数微小变化随着网络层数加深被放大的问题,使得网络对参数大小的适应能力更强,此时我们可以设置较大的学习率而不用过于担心模型divergence的风险。
3)BN允许网络使用饱和性激活函数(例如sigmoid,tanh等),缓解梯度消失问题
在不使用BN层的时候,由于网络的深度与复杂性,很容易使得底层网络变化累积到上层网络中,导致模型的训练很容易进入到激活函数的梯度饱和区;通过normalize操作可以让激活函数的输入数据落在梯度非饱和区,缓解梯度消失的问题;另外通过自适应学习与又让数据保留更多的原始信息。
(4)BN具有一定的正则化效果
在Batch Normalization中,由于我们使用mini-batch的均值与方差作为对整体训练样本均值与方差的估计,尽管每一个batch中的数据都是从总体样本中抽样得到,但不同mini-batch的均值与方差会有所不同,这就为网络的学习过程中增加了随机噪音,与Dropout通过关闭神经元给网络训练带来噪音类似,在一定程度上对模型起到了正则化的效果。
Batch Normalization原理与实战 Batch Normalization详解以及pytorch实验
免责声明:本文转载或采集自网络,版权归原作者所有。本网站刊发此文旨在传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及版权、内容等问题,请联系本网,我们将在第一时间删除。同时,本网站不对所刊发内容的准确性、真实性、完整性、及时性、原创性等进行保证,请读者仅作参考,并请自行核实相关内容。对于因使用或依赖本文内容所产生的任何直接或间接损失,本网站不承担任何责任。