一、梯度累加(Gradient Accumulation)
在训练神经网络的时候,超参数batch size的大小会对最终的模型效果产生很大的影响。一定条件下,batch size设置的越大,模型就会越稳定。但是当做一些计算量需求大的任务(例如语义分割、GAN等)或者输入图片尺寸太大的时候,batch size往往只能设置为2或者4,否则就会出现"CUDA OUT OF MEMORY”的不可抗力报错。
那么如何在有限的计算资源的条件下,训练时采用更大的batch size呢?
这就是梯度累加(Gradient Accumulation)技术了。
一个神经网络的训练过程通常如下:
从代码中可以很清楚地看到神经网络是如何做到训练的:
1.将前一个batch计算之后的网络梯度清零
2.正向传播,将数据传入网络,得到预测结果
3.根据预测结果与label,计算损失值
4.利用损失进行反向传播,计算参数梯度
5.利用计算的参数梯度更新网络参数
下面来看梯度累加是如何做的:
1.正向传播,将数据传入网络,得到预测结果
2.根据预测结果与label,计算损失值
3.利用损失进行反向传播,计算参数梯度
4.重复1-3,不清空梯度,而是将梯度累加
5.梯度累加达到固定次数之后,更新参数,然后将梯度清零
梯度累加的固定次数就是我们将batch_size(此batch_size比较大,会导致内存不足,但是我们还想使用这个batch_size进行计算)继续分块为mini_batch的块数。例如我们将一个batch_size分为8块mini_batch,那么固定次数即为8,每八次梯度累加之后,才进行梯度清零。这样一番操作下来,就相当于我们成功的使用了batch_size的样本数。
总结:
梯度累加就是每计算一个batch的梯度,不进行清零,而是做梯度的累加,当累加到一定的次数之后,再更新网络参数,然后将梯度清零。
通过这种参数延迟更新的手段,可以实现与采用大batch size相近的效果。在实验过程中,一般会采用梯度累加技术,大多数情况下,采用梯度累加训练的模型效果,要比采用小batch size训练的模型效果要好很多。
二、正向累积(传播)和反向累积(传播)
1、区别
正向传播(forward-propagation):指对神经网络沿着输入层到输出层的顺序,依次计算并存储模型的中间变量。
反向传播(back-propagation):沿着从输出层到输入层的顺序,依据链式法则,依次计算并存储目标函数有关神经网络各层的中间变量以及参数的梯度。
反向传播是一种计算神经网络参数梯度的方法
在训练深度学习模型时,正向传播和反向传播相互依赖。
一方面,正向传播的计算可能依赖于模型参数的当前值,而这些模型参数是在反向传播梯度计算后通过优化算法迭代的。
另一方面,反向传播的梯度计算可能依赖于各变量的当前值,而这些变量的当前值是通过正向传播计算得到的。
因此,在参数初始化完成后,我们交替进行正向传播和方向传播。
2、为什么深度学习都是使用反向累积
反向传播就是为了实现最优化,省去了重复的求导步骤
从一道编程题目来理解,这道题目是给出一个三角形的数组,从上到下找到一条路径使得这条路径上数字的和最小,并且路径层与层之间的节点左右需要相邻。
图一中是一个具体的例子,最小和的路径如箭头所示,路径的和为11。最初的思路是从上到下不断将问题分解成小问题去处理,具体来说上图的大三角形可以分解成3为顶点和4为顶点的两个小三角形,如图二所示,求出这两个子问题的最小路径,选择这两个路径和较小者加上顶点2的值就为整个问题的最小值,而对于每个分解的子问题,再故伎重演地继续分解来处理。
但是这样会导致Time Limit Exceeded 的超时错误,究其原因是这种从上到下的计算方式中存在大量的重复计算,如图二所示:将一个大的问题分解成两个子问题(红蓝两个三角形)时,这两个三角形之间有交叠,即图2中的紫色圈,这些交叠部分会导致重复计算,使得计算超时。图中仅仅是一个子问题的重复计算,实际上每一次子问题的分解都有这样的重复计算,因此整个问题的重复计算量非常的大。
实际上这个问题的正确解决方法是使用动态规划算法,动态规划要解决的正是这种包含重复子问题的情况。其实现方法一般分为两种,一种是将计算过的子问题都缓存起来,当遇到了相同的问题就直接取出缓存的值,避免重复计算;另一种是方式是换一个“计算方向”(或者说计算的先后次序),使得在这个计算方向上没有重复的子问题。对于上述编程题我们的解法就是将这一算法换一个计算方向,由从上到下变换为从下到上。从最底层开始由下到上计算以当前点为顶点的“三角形”最小路径值,下层的顶点先计算,上层可以利用下层的计算结果,这就避免了重复计算。
再看一看图3的例子,现在假设输入向量经过正向传播后,现在要求出参数w1和w2的导数,按照上述方法计算时,对w1微扰后,需要重新计算红框内的节点;对w2微扰后,需要重新计算绿框内的节点。这两次计算中也有大量的“重复单元”即图中的蓝框,实际上神经网络的每一个参数的计算都包含着这样大量的重复单眼,那么神经网络规模一旦变大,输入的x特征增多,这种算法的计算量一定爆炸,没有适用价值。
在神经网络中,反向传播就是选择了另一条计算方向去计算梯度,这个方向就是从后向前“反向”地计算各层参数的梯度。这种方法利用了函数求导的链式法则,从输出层到输入层逐层计算模型参数的梯度值,只要模型中每个计算都能求导,那么这种方法就没问题。可以看到按照这个方向计算梯度,各个神经单元只计算了一次,没有重复计算。这个计算方向能够高效的根本原因是,在计算梯度时前面的单元是依赖后面的单元的计算,而“从后向前”的计算顺序正好“解耦”了这种依赖关系,先算后面的单元,并且记住后面单元的梯度值,计算前面单元之就能充分利用已经计算出来的结果,避免了重复计算。
理解向------正向传播与反向传播:
(5条消息) 深度学习系列(2):前向传播和后向传播算法_Demon的黑与白的博客-CSDN博客_前向传播和后向传播
三、模型参数初始化
初始化方案的选择在神经网络学习中起着举足轻重的作用, 它对保持数值稳定性至关重要。 此外,这些初始化方案的选择可以与非线性激活函数的选择有趣的结合在一起。 我们选择哪个函数以及如何初始化参数可以决定优化算法收敛的速度有多快。 糟糕选择可能会导致我们在训练时遇到梯度爆炸或梯度消失。
四、激活函数的作用
1、激活函数的本质是引入非线性因素
激活函数是用来加入非线性因素的,提高神经网络对模型的表达能力,解决线性模型所不能解决的问题。
在我们面对线性可分的数据集的时候,简单的用线性分类器即可解决分类问题。但是现实生活中的数据往往不是线性可分的,面对这样的数据,一般有两个方法:引入非线性函数、线性变换。
线性变换
就是把当前特征空间通过一定的线性映射转换到另一个空间,让数据能够更好的被分类。
激活函数
激活函数是如何引入非线性因素的呢?在神经网络中,为了避免单纯的线性组合,我们在每一层的输出后面都添加一个激活函数(sigmoid、tanh、ReLu等等),每一层的输出通过这些激活函数之后,就变得比以前复杂很多,从而提升了神经网络模型的表达能力。
五、隐藏层
隐藏层的意义就是把输入数据的特征,抽象到另一个维度空间,来展现其更抽象化的特征,这些特征能更好的进行线性划分。