参考:
1
技巧链接一!重要
技巧链接二!重要
技巧链接三!重要
模型训练技巧最直接的就是几个超参数的设置
根据图片大小来选择网络和超参数
如果图片不是很大比如3030,这种情况下做分类就不能用VGG和Resnet这样的网络。此时要么把图像变大要么就是选择小的网络,或者把VGG里pooling的步长设置为1试试,如果类别不多(没有上千),那么直接使用小网络,如果是100100这样的大图片就采用VGG和Resnet这样的大网络。
根据图片类别数和数量来选择batch_size
如果训练样本少,少于1000,那么直接使用全梯度下降,不需要用批梯度下降。用批梯度的目的是为了加快训练速度,所以当训练样本少的时候是没有必要使用批梯度下降的。只是用全梯度下降反向传播一次需要很久的时间,训练起来很慢。若训练类别很多,那么bacth_size一定不要太小,例如若是上千的类别数,那么bacth_size值就设置为为128,否则震荡会很严重。
根据网络规模和loss下降速率来选择学习率
学习率的选择一般是0.001 0.0001 0.00001 0.000001等中的一个值,选择哪个值的最根本的依据是网络很复杂的时候学习率不能太低,否则传到后面的时候就会基本没梯度了。三五层的网络学习率基本要小于1*e^(-5),不然会下降过快导致震荡。初始学习率可以随意选择来尝试试探,如果发现loss下降得过快,那么要减少学习率。如果发现loss降低不下去,就适当增加学习率。
深度学习的训练过程
深度学习的训练过程大同小异,一般可以分为如下几步:
- 定义算法公式,也就是神经网络的前向算法,一般使用现成的网络,例如inceptionV4,mobilenet等。
- 定义loss,选择优化器,让loss最小。
- 对数据迭代训练,让loss最小。
- 在测试集或者验证集上对准确率评估
深度学习模型训练过程中常遇到的问题
问题一:收敛速度慢,训练时间长
- 深度学习训练过程就是一个不断调参的过程,收敛速度慢、训练时间长会使得相同总训练时间内迭代次数少,从而影响准确率。另外训练次数变少,使得尝试超参数的次数变少。
解决办法一:设置合理的初始化权重和偏置
- 深度学习通过前向计算和反向传播,不断调整参数,来提取最优特征。调整的参数就是权重和偏置。根据奥卡姆剃刀法则,模型越简单越好,以线性函数这种最简单的表达式来提取特征。即f(x)=wx+b。深度学习训练时几乎所有的工作量都是用来求解w和b。训练本质也就是调整w和b的过程。
- 一般使用截断的正态分布(也叫作高斯分布)来初始化w。
如下
# 权重weight,标准差0.1。truncated_normal截断的正态分布来初始化weight。权重初始化很有讲究的,会决定学习的快慢
def weight_variable(shape, vname):
initial = tf.truncated_normal(shape, stddev=0.1, name=vname)
return tf.Variable(initial)
tf.truncated_normal定义如下
tf.truncated_normal(
shape, # 正态分布输出数据结构,1维tensor
mean=0.0, # 平均值,默认为0.我们一般取默认值0
stddev=1.0, # 标准差
dtype=tf.float32, # 输出数据类型
seed=None, # 随机分布都会有一个seed来决定分布
name=None
)
- 下图左图为标准正态分布,也叫作高斯分布。利用TensorFlow中的tf.random_normal()可以得到x取值范围从负无穷到正无穷的值。所以的y值加起来为1。初始化w时,没必要将其初始化为很大或者很小的值,所以更倾向于使用截断正态分布,如下图中的右图。截断正态分布和标准正态分布的区别是:限制了x取值必须在[-2 x stddev, 2 x stddev]之间。
- f(x)=wx+b,b由于是加和关系,对收敛速度影响不大,一般初始化为0.如下所示
# 偏置量bias,初始化为0,偏置可直接使用常量初始化
def bias_variable(shape, vname):
initial = tf.constant(0, shape=shape, name=vname)
return tf.Variable(initial)
解决办法二:优化学习率
- ,模型训练就是不断尝试和调试w和b,每次调整的幅度是多少,关系到学习率。w和b是在一定范围内调整的,增大学习率就减少了迭代次数,但学习率太大,也容易越过局部最优点,降低准确率。
- 所以,一般采用,一开始学习率大,从而加速收敛,训练后期学习率小一点,从而稳定地落入局部最优点。使用Adam,Adagrad等自适应优化算法,就可以实现学习率的自适应调整。从而保证准确率的同时加快收敛速度。
解决办法三:网络节点输入值正则化batch normalization(批标准化)
- 神经网络训练时,每一层的输入分布都在变化,不论输入值是大还是小,学习率都是相同的,这是很浪费效率的,当输入值很小时,为了保证精细调整,学习率不能设置太大,如果让输入值标准化落到某一个范围内,如[0,1]之间,这样就不用为太小的输入值犯愁。
- 学习的是输入的特征分布,而不是绝对值,所以可以对每一个mini-batch数据内部进行标准化,使它们规范化到[0,1]之间。这就是bacth normalization正则化。
- inceptionV2在每个卷积层后,使用一个BN层,从而使得学习率可以设定为一个较大的值,使用了BN之后的inceptionV2,只需要以前的1/14的迭代次数就能达到之前的准确值,加快了收敛速度。
- Normalization时,选的平均值跟标准差希望它代表的是整个training set全体。但是实际上统计整个training set全体的statistics是非常耗费时间的。所以实际上算平均值和标准差的时候,只会在batch里面算。所以batch size一定要够大,如果太小的话Batch Normalization的性能就会很差,因为你没有办法从一个batch里面估测整个data集,可以想象极端case,如果batch size=1,则不能apply BN想法。
解决办法四:采用更先进的网络结构,减少参数量
- 训练速度慢,归根结底是网络结构参数多,减少参数量,可以大大加快收敛速度。采用先进的网络结构可以可以用更少的参数数量达到更高的精度。如何用更少的参数数量达到更高的精度,有如下几种方法:
方法一: 使用小卷积核代替大卷积核
VGGNet全部使用33的小卷积核,来代替AlexNet中的1111和55等大卷积核。小卷积核虽然参数量少,但也会带来特征面积捕获过小的问题。inception net认为越往后的卷积层,应该捕获更多更高阶的抽象特征。因此它在靠后的卷积层中使用的55等大面积的卷积核的比率较高,而在前面几层卷积层中,更多使用的是11和33的卷积核。
方法二: 使用两个串联小卷积核来代替大卷积核
inceptionV2中提出两个33的卷积核代替一个55的卷积核,在效果相同的情况下,参数量仅为原先的332/5*5=18/25
方法三: 1 * 1卷积核的使用
1 * 1卷积核是性价比最高的卷积,它在参数量为1的情况下,同样能够提供线性变换、relu激活、输入输出channel变换。是VGGNet提出的1 * 1卷积核。
方法四: 非对称卷积核的使用
inceptionV3中将一个7 * 7的卷积拆分成了一个1 * 7和一个7 * 1的卷积核,卷积效果相同的情况下,参数量大大减小,而且还提高了卷积的多样性。
方法五: depthwise卷积的使用
mobileNet中将一个3 * 3的卷积拆分成了串联的一个3 * 3 depthwise卷积和一个1 * 1正常卷积。对于输入channel为M,输出为N的卷积,正常情况下,每个输出channel均需要M个卷积核对输入的每个channel进行卷积、并叠加。也就是需要M * N个卷积。而在depthwise卷积中,输出channel和输入相同,每个输入channel仅需要一个卷积核,而将channel变换的工作交给了1 * 1卷积核。这个方法在参数量减少到之前的1/9的情况下,精度仍能达到80%。
方法六:全局平均池化代替全连接层
AlexNet和VGGNet中,全连接层几乎占据了90%的参数量,inceptionV1使用全局平均池化来代替最后的全连接层。使得其在网络结构更深的情况下,(22层,AlexNet仅有8层)。参数量500万,是AlexNet的1/12。
方法七:GPU并行计算
深度学习模型训练,基本由卷积计算和矩阵乘法构成,都很适合并行运行。
总结
参数量的减小,加快收敛速度、减少训练时间、减小模型体积、加快预测时间、提高实时性。
问题二:线性模型的局限性
根据奥卡姆剃刀法则,使用最简单的线性模型即wx+b来表征神经网络。线性模型的特点是:任意线性模型的组合仍然是线性模型。即不论采用如何复杂的网络,都是线性模型。但是线性模型能够解决的问题是有限的,所以需要增加非线性元素。
激活函数的使用
- 在每个卷积后,加入一个激活函数,激活函数如relu和tanh和sigmoid都是非线性函数,一方面可以增加模型的非线性元素,另一方面可以降低梯度弥散问题。目前使用较多的激活函数是relu函数。它模拟了生物学上的阈值响应机制,利用人脑只对大于某个值的信号才产生响应的机制,提出了单侧抑制的理念。relu非线性激活函数的表达式是:f(x)=max(0,x)。当x>0时,y=x,当x<0时,y=0。relu即rectified linear unit。
- 相比于tanh和sigmoid,relu的优点是:计算速度快,易收敛,relu是一个取max的函数,没有复杂运算,所以计算速度快,相比于tanh计算速度快6倍。第二个优点是梯度不会大幅缩小,x>0时,relu的梯度为1,梯度可以简单理解为偏导数。sigmoid函数是x稍微远离0梯度就会大幅减小,所以sigmoid激活函数会更容易出现梯度弥散的问题。
- 补充:梯度弥散:当使用反向传播计算导数的时候,随着网络深度的加深,反向传播梯度的幅值会显著减小,这就会造成整体的损失函数相对于最初几层的权重的导数非常小,这样当使用梯度下降法的时候,最初几层的权重变化非常缓慢,以至于不能从样本中有效的学习。
- 补充:与梯度弥散紧密相关的问题是:当神经网络的最后几层含有足够数量神经元的时候,可能单独这几层就足以对有标签数据进行建模,而不用最初几层的帮助。因此对所有层都进行随机初始化的方法训练得到的整个网络的性能与训练得到的浅层网络(仅有深度网络的最后几层组成的浅层网络)的性能相似。
两个小卷积核的叠加代替一个大卷积核
激活函数是增加非线性的法宝,但是一般只能在卷积之后使用,所以需要增加使用激活函数的场景,方法就是增加卷积层。inceptionV2提出使用两个33的卷积核代替一个55的卷积核。每次卷积后,都使用一次relu非线性激活。、
1*1小卷积核的使用
relu在参数量为1的条件下,能提供线性变换、relu激活、输入输出channel变换等。inceptionV1利用network in neiwork的思想,提出inception module这一结构。它在每个并行分支的最前面,使用一个1*1的卷积,卷积后紧跟一个relu激活,所以大大增加relu的使用率,提高模型的非线性特征。
问题三:过拟合问题
过拟合指的是:一定次数的迭代后,模型准确度在训练集上越来越好,但是在测试集上越来越差,原因就是模型学习了太多无关特征,将这些特征认为是目标所应该具备的特征。
神经网络中,由于参数众多,经常出现参数比输入数据还要多的情况,导致很容易出现模型只记住了训练集特征的情况。两个方法解决这个问题:一是扩大数据量,二是减少特征量。
方法一:输入增强,扩大样本量
收集更多样本,可以抑制过拟合。素材整理和数据获取是深度学习的瓶颈。使用输入增强方法,对数据旋转、裁切、加入噪声等。可以增加样本数量和泛化性。tensorflow就提供了大量方法用于数据增强,方便我们增加样本数量。
方法二:dropout,减少特征量
- 使用dropout,对神经网络某一层的输出节点数据随机丢弃,从而减少特征量。这实际上相当于创造了很多新的样本,可以理解为是对特征的一次采样,一般在神经网络的全连接层使用dropout。
- 使用丢弃法应对过拟合,丢弃法只在训练模型时使用,在测试模型时是不使用丢弃法的。
方法三:权重衰减
- 权重衰减等价于L2范数正则化regularization,正则化通过为模型损失函数添加惩罚项使得学出的模型参数值较小,是应对过拟合的手段。
- L2正则化(权重衰减)通过惩罚绝对值较大的模型参数为需要学习的模型增加了限制,这可能对过拟合有效。实际使用中,有时会在惩罚项中添加偏差元素的平方和。
- 在构造优化器实例时可以通过weight_decay参数来指定权重衰减超参数。默认下pytorch会对权重和偏差同时衰减,可以分别对权重和偏差构造优化器实例,从而只对权重衰减。
问题四:梯度弥散,无法使用更深的网络
深度学习网络利用正向传播提取特征,同时利用反向传播调整特征。反向传播中梯度值逐渐减小,神经网络层数较多时,传播到前面几层时,梯度接近0,无法对参数做出指导性调整了,此时基本起不到训练作用,这就是梯度弥散,梯度弥散使得模型网络深度不能太大,但是网络深度越深,提取的特征越高阶,泛化性越好。
解决办法一:relu代替sigmoid激活函数
sigmoid函数值范围:[0,1],relu函数值范围:[0,+无穷],relu函数在x>0时导数为1,sigmoid函数,x稍微远离0,梯度就大幅减小。几乎接近0,所以在反向传播中无法指导参数更新。
解决办法二:残差网络
resNet将一部分输入值不经过正向传播网络,而是直接作用到输出中,这样可以提高原始信息的完整性,从而在反向传播中可以指导前面几层参数的调整。
使用了残差网络的resNet,将深度提高到152层,提高模型的泛化能力,从而提高预测准确率。
激活函数
sigmoid
优点:输出值是[0,1],符合概率分布。
缺点:
x稍微远离0,导数就接近于0了,这样在反向传播优化w时,无论w取何值,梯度都很小,也就无法对w的更新给出指导。这叫做梯度弥散,在网络层级较深时尤为明显。
第二个缺点需要进行指数运算,计算量大。
tanh
tanh和sigmoid很像,只是y的分布以0为中心,同样存在梯度弥散和计算耗时的问题。
relu
使用最多的激活函数,几乎所有的cnn均使用relu作为激活函数。
优点是:不存在梯度弥散问题,计算简单。
损失函数
损失函数用来衡量预测值和真实值之间的差距,目的是达到较小的损失值,这个损失值可以是局部最优解,也可以是全局最优解,全局最优解很难取得,且往往是一个过拟合的结果。损失函数有如下几种:
损失函数的第一种:平方差
L(Y,f(x))=(Y-f(x))^2,Y为真实值,f(x)为预测值。
线性回归中经常使用这种形式,分类问题中不常使用。
损失函数的第二种:交叉熵
描述两个概率分布之间的距离,在分类问题中常使用。
优化方法
优化方法用来指导如何调整参数w和b。来最有效率的使得损失函数达到最小值。优化方法最初需要手动调整学习率,来调整参数大小,这种手动方法麻烦,所以后面出现一些自动调整学习率的优化方法。
优化方法一:BGD batch gradient descent
BGD每步迭代中,都需要使用训练集的所有内容来计算梯度和误差,来指导参数的更新,这种方法由于使用了训练集中的所有数据,所以能够保证是真实有效并且不含有噪声。所以可以设置一个固定的学习率,但是计算量大。
优化方法二: SGD stochastic gradient descent
针对BGD计算量大的改进,随机梯度下降,每次随机抽取一定的样本计算梯度和误差,并更新参数,这种方式计算量不大,但是采用的是随机样本,所以梯度不一定是真实的梯度。带有噪声。随着梯度下降,需要减小学习率,让其稳定落入局部最优解。
优化方法三:momentum
针对SGD中含有噪声的改进,它将前几次的梯度也参与到本次梯度计算中来,也就是利用梯度之和来指导更新,它可以加速学习率,从而减少迭代次数,加快收敛速度。
优化方法四:AdaGrad
可以自动更新学习率,但是需要设置一个全局学习率,学习率表达式如下:
ϵ为全局学习率,需要设置一个固定的值。δ是一个很小的常量,大概在e^-7, 主要是为了防止分母为0.gi为第i次迭代时的梯度。可以看到随着梯度累加和的增加,学习率会降低,从而使损失函数稳定落入局部最优解。
优化方法五:Adam Adaptive Moment Estimation自适应矩估计
概率论中矩的定义是,如果一个随机变量服从某个分布,则其一阶矩为其平均值,即E(X)。二阶矩为其平方的平均值,即E(X^2)。Adam根据损失函数梯度的一阶矩估计和二阶矩估计来动态调整学习率。算过程如下
g为迭代运算损失函数梯度的累加和,s为梯度的一阶矩估计,r为梯度的二阶矩估计。ρ1和ρ2为衰减系数,一般ρ1=0.9,ρ2=0.999。δ目的是防止分母为0,一般取e-8。ϵ为用户设置的全局学习率,一般可设为e-4。θ为学习率。
训练模型时的小技巧
第一个 多尺度训练或者测试
目标检测模型用于不同大小的图片,因而包含不同尺度的物体,很多网络并不关注输入图像的size,一个可以让模型对不同大小的输入泛化的方法是每一定的迭代过程中随机选择不同的输入尺寸,比如随机从320 * 320到608 * 608之间选择输入,而不是恒定在416 * 416。在测试的时候,也可以将图像resize到各个尺寸,得到不同尺度的框做NMS,思路和图像金字塔有点像。
第二个 热身训练warm-up training
yolo在早期训练阶段为每个单元中心增加一个假的真实框(先验框),采用这个额外的坐标损失来鼓励模型的预测可以匹配到检测器的先验框。
第三个 难例挖掘hard negative mining
因为大部分检测器是不负责检测任何物体的,这意味着正例数量要远少于负例,yolo采用一个超参数来处理这种情况,但是SSD采用难例挖掘,它并不是计算所有负例的损失,而是只计算那些预测结果最错的部分损失(即置信度较高的负例)
第四个 NMS
如下图,用于有效筛除多余的检测框。
第五个 Soft NMS
这个技巧是为了解决在NMS技巧中,有可能出现的问题是,如下图,NMS会把重叠、贴近的目标筛除,下图中人和马贴的很近,所有很容易NMS就把其中一个框给删掉了。
比较NMS和Soft NMS
- NMS算法的思路是:先对得分排序,然后从输出结果中挑出得分最高的放入最终输出的检测结果中,接着遍历剩下的框,如果IOU重叠超过某个阈值,就直接排除这个框,遍历一次之后,再从剩下的框里按得分排序,挑出得分最高的加入最终输出的结果,如此循环直到最后输出结果里的所有的框都被挑出来或者排除掉。
- Soft NMS的思路是:只是在NMS思路的基础上改变了一点:IOU如果超过某个阈值,不再是直接删掉这个框,而是降低它的得分,得分如果低到一定程度就会被排除,但是如果降低后仍然比较高,就有保留下来的机会。
热力图
- 通过热力图可以知道卷积神经网络是通过什么特征来分类的,这个是卷积神经网络中的隐藏特性。有一些模型把这种隐藏属性利用了,例如注意力模型,每次学习迭代中,对热力图集中部分信号加强。并且抑制其他部分。使得学习变得更加专注。也还可以查看分类因素是否正确,例如美国国防部投资 识别坦克的例子。国防部花了100万买了个模型识别坦克,确实也可以用。但是后来才发现,有坦克的场景都是阴天。原来模型识别到的是区分晴天和阴天,而不是坦克。
- 一般任务有回归和heatmap两种方式,heatmap相对回归来说最后的结果可能会更好一点,因为回归可能只给网络输入几个关键点的信息,而使用heatmap作为监督信号可以传递更多的信息。
- 在我们使用 CNN 进行图片分类时,模型到底关注的是图像的哪个区域?Grad-CAM 利用卷积网络最后一个特征图的信息,并加权对应的梯度而构建模型分类的热力图,通过该热力图,我们可以清楚地了解哪一块区域对于类别是最重要的。
- 这种技术不仅适用于定位,还可以用于视觉问答,图像标注等。
- 这种技术还在建立精确模型的数据需求方面有帮助。
如何知道 CNN 究竟在寻找什么?答案就是,Grad-CAM。即加权梯度类激活映射
补充小知识点:
- 经典的卷积神经网络有一个问题是它只能接受固定大小的输入图像,这是因为第一个全连接层和它之前的卷积层之间的权重矩阵大小是固定的,而卷积层、全连接层本身对输入图像的大小并没有限制。而在做目标检测时,卷积网络面临的输入候选区域图像大小尺寸是不固定的。
- 让一个已经设计好的DCNN模型,可以支持任意大小图片输入,其中一种方案是全卷积网络(FCN),即去掉所有全连接层,全部由卷积层来替代。
- 在卷积神经网络中,卷积层并不要求输入图像的尺寸固定,只有第一个全连接层需要固定尺寸的输入,因为它和前一层之间的权重矩阵是固定大小的,其他的全连接层也不要求图像的尺寸固定。如果在最后一个卷积层和第一个全连接层之间做一些处理,将不同大小的图像变为固定大小的全连接层输入就可以解决问题。
超参数的设定
输入数据像素大小
- 使用卷积网络处理图像问题时,对不同输入图像为了得到同等规格的输出,同时也为了GPU设备并行,统一将图像压缩到2的n次幂大小。例如imagenet数据集常用的224x224像素。
- 如果不考虑显存大小的限制,更高分辨率图像作为输入数据有助于网络性能的提升。特别是对基于注意力模型的深度网络提升更显著。
- 但是高分辨率图像会增加模型计算消耗而导致网络整体训练时间延长。
- 一般卷积神经网络都采用全连接层作为最后分类层,若直接改变原始网络模型的输入图像分辨率,会导致原始模型卷积层的最终输出无法输入全连接层的情况,此时需要重新改变全连接层输入滤波器的大小或者是重新指定其他相关参数。
卷积层参数的设定
- 卷积层的超参数主要包括卷积核大小、卷积操作的步长和卷积核的个数。
- 小卷积核比大卷积核相比有两个优势:
(1)优点一:增强网络容量和模型复杂度
(2)优点二:减少卷积参数个数
- 实践中推荐使用3x3和5x5这样的小卷积核,其对应卷积操作步长建议设置为1.
- 卷积操作前还可以搭配填充操作padding。填充操作的两个优点:
(1)优点一:可以充分利用和处理输入图像的边缘信息。
(2)优点二:搭配合适的卷积层参数可以保持输出与输入同等大小,而避免随着网络深度增加,输入大小的急剧减小。
- 例如,当卷积核大小为3x3,步长为1时,可以将输入数据上下左右各填充1各单位的黑色像素,则padding=1,值为0,所以也叫作zeros-padding。这样做可以保持输出结果与原来的输入同等大小。
- 当卷积核为5x5,步长stride为1时,指定padding=2,也可以保持输出与输入等大。
-
总结:对于卷积核大小f x f,步长为1的卷积操作,当padding为p=(f-1)/2时,可以维持输出与原来的输入等大。
- 为了硬件字节级存储管理的方便,卷积核个数通常设置为2的次幂,这样的设置有利于硬件计算过程中划分数据矩阵和参数矩阵,尤其在利用显卡计算时更为显著。
池化层参数的设置
- 和卷积核大小设置一样,池化层的核大小一般也设置为较小的值,如2x2,3x3等。常用的参数设定是2x2,池化层步长是2,在这个常用的设置下,输出结果大小仅仅为输入数据长宽大小的四分之一。即输入数据中有75%的响应值被丢弃,这就起到了下采样的作用。
-
为了不丢弃过多输入响应而损失网络性能,池化操作极少超过3x3大小的池化操作。
训练技巧
训练数据随机打乱
- 信息论:从不相似的事件中学习总是比从相似事件中学习具有更多的信息量。
- 训练卷积神经网络时,尽管训练数据固定,但是采用了随机批处理mini-batch的训练机制,因此可以在模型每轮epoch训练进行前将训练数据集随机打乱,确保模型不同轮次相同批次看到的数据是不一样的。
- 这种打乱操作提高模型的收敛速度,也能提升模型在测试集上的预测结果。
学习率的设定
- 学习率设定需要遵循下面两个原则:
- 模型训练开始的时候,初始学习率不应该过大,以0.01和0.001最好。
- 如果刚开始训练没有几个批次mini-batch,模型的目标损失值就急剧上升,这就说明模型训练的学习率过大,此时应该减小学习率从头训练。
- 模型训练过程中,学习率应该随着轮数增加而减缓,减缓机制有三种:
(1)方式一:轮数减缓step decay,例如五轮训练后学习率减半,下一个五轮后再次减半。
(2)方式二:指数减缓。学习率按照训练轮数增长指数插值递减等
(3)方式三:分数减缓。
- 寻找理想学习率或者是诊断模型训练学习率是否合适时可以借助模型训练曲线。下图中的红色曲线是理想学习率曲线。曲线表示:不同的学习率下训练损失值随着训练轮数增加呈现的状态
批规范化操作BN
- BN加快了模型的收敛速度,也在一定程度上缓解了梯度弥散问题。
- 目前BN几乎用于所有卷积神经网络。
- BN是在模型每次随机梯度下降训练时,通过mini-batch来对相应的网络响应做规范化。使得结果输出信号各个维度的均值为0,方差为1.
-
BN操作共分为四步:
(1)第一步:计算批处理的数据均值
(2)第二步:计算批处理的数据方差
(3)第三步:根据均值和方差对该批数据做规范化
(4)第四步:尺度变换和偏移,是为了让因训练所需而刻意加入的BN能有可能还原最初的输入,从而保证整个网络的容量。
-
BN能起作用的原因
(1)在统计机器学习中的一个经典假设是:源空间和目标空间的数据分布是不一致的,如果不一致,那么出现新的机器学习领域即迁移学习。
(2)协变量偏移是分布不一致假设下的一个分支问题,它是指源空间和目标空间的条件概率是一致的,但是其边缘概率是不同的。
(3)对于神经网络的各层输出,由于它们经过了层内操作,其分布显然与各层对应的输入信号分布不一样,而且差异会随着网络深度增大而越来越大。但是它们所指示的样本标记仍然保持不变,这就符合了协变量偏移的定义。
(4)可以通过BN来规范化某些层或所有层的输入,从而可以固定每层输入信号的均值和方差。这样的话,即使网络模型较深层的响应或者梯度很小,也可以通过BN的规范化作用将其的尺度变大。这样就可以解决深层网络训练很可能带来的梯度弥散。
-
BN的使用位置
(1)在卷积神经网络中BN一般应该作用在非线性映射函数前
(2)在神经网络训练时遇到收敛速度慢或者是梯度爆炸等无法训练的情况,也可以尝试用BN解决。
(3)常规使用情况下,同样可以加入BN来加快模型的训练速度,甚至提高模型精度。
- BN的变种也作为一种有效的特征处理手段应用于人脸识别等任务中,即特征规范化。FN。FN作用于网络最后一层的特征表示上,FN的下一层是目标函数层。FN的使用可以提高习得特征的分辨能力,适用于类似人脸识别、行人重检测、车辆重检测等。
优化算法
梯度下降法在每次迭代求解机器学习目标函数最优解时,需要计算所有训练集样本的梯度。如果训练集很大,特别是如果训练数据上万甚至上百万,所以梯度下降这种方法的效率很低。而且硬件限制所以这种做法在实际中不现实。随机梯度下降是通过每次计算一个样本来对模型参数迭代,这样只需要几百或者是几千样本便可以得到最优解,所以随机梯度下降比梯度下降效率高。但是缺点也就在于:随机梯度下降法由于每次计算只考虑一个样本,使得它每次迭代并不一定都是模型整体最优的方向,如果样本噪声多,基于随机梯度下降法的模型很容易陷入局部最优解而收敛到不理想的状态。所以深度学习中,仍然需要遍历所有的训练样本,每次遍历训练集样本一次称为训练经过了一轮epoch。在深度学习中,将SGD经过了改造,每次选取一批样本,利用这批样本上的梯度信息完成一次模型的更新。每在一批数据上训练一次,称之为一个batch的训练。所以批处理的SGD相比经典的SGD更加稳定。
随机梯度下降法
- SGD即每次批处理训练时计算网络误差并且做误差的反向传播,然后根据一阶梯度信息对参数更新。
- 一阶梯度信息完全依赖于当前批数据在网络目标函数上的误差,故可以将学习率理解为当前批的梯度对网络整体参数更新的影响程度。
- 随机梯度下降是最常见的神经网络优化方法,收敛效果稳定但是速度过慢。
基于动量的随机梯度下降
- 基于动量的随机梯度下降用于改善SGD更新时可能产生的震荡现象,通过积累前几轮的动量信息辅助参数更新。
- 基于动量的随机梯度下降除了可以抑制震荡,还可以在网络训练中后期趋于收敛,网络参数在局部最小值附近来回震荡时帮助其跳出局部限制,找到更优的网络参数。
- 对于动量因子,除了设置为0.9的静态设定方式,还可以将其设置为动态因子。常用的动态设定方式是将动量因子初始值设置为0.5,之后随着训练轮数增长逐渐变为0.9或者是0.99.
Nesterov型动量随机下降法
- 这种方法是在上述动量梯度下降法更新梯度时加入对当前梯度的校正。相比于一般动量法,这个方法对于凸函数在收敛性上有更强的理论保证。
总结:
- 上面介绍的三种优化算法都是为了使得梯度更新更加灵活,对于优化神经网络这种拥有非凸且异常复杂函数空间的学习模型尤为重要。
- 但是上面介绍的三种优化算法的局限性在于:因为稍微小的学习率更加适合网络后期的优化,但是这些方法的学习率却一直固定不变,并未将学习率的自适应性考虑进去。
Adagrad法
- 针对学习率自适应问题,该方法根据训练轮数的不同,对学习率进行了动态调整。
Adadelta法
- 该方法是对Adagrad法的扩展,通过引入衰减因子消除Adagrad法对于全局学习率的依赖。
RMSProp法
- 该方法可以看成是Adadelta法的一个特例。
- 但是RMSProp依然利用全局学习率是它的一个缺陷。
Adam法
- 该方法本质上是带有动量项的RMSProp,它利用梯度的一阶矩估计和二阶矩估计动态调整每个参数的学习率。
- 该方法的优点在于经过偏置校正后,每一次迭代学习率都有一个确定的范围,这样可以使得参数更新更加平稳。
微调神经网络
- 除了从头训练自己的网络,一种更高效的方法是微调已经预训练好的网络模型。
- 微调预训练模型就是用目标任务数据在原先预训练模型上继续进行训练。
- 由于网络已经在原始数据集上收敛,所以应该设置较小的学习率在目标数据上微调,如10^-4数量级或者以下。
- 卷积神经网络的浅层拥有更广泛的特征,例如边缘、纹理等。深层网络特征对应高层语义。所以在新数据上微调时,浅层的泛化特征更新的程度比较小。而深层的高层语义更新的程度比较大。所以可以根据层深对不同层设置不同的学习率。深层网络的学习率可以稍微大于浅层网络的学习率。
- 根据目标任务与原始数据相似程度采用不同的微调策略:
- 当目标数据较少且目标数据与原始数据非常相似时,可以仅仅微调网络靠近目标函数的后几层。
- 当目标数据充足且相似时,可以微调更多网络层,也可以全部微调。
- 当目标数据充足但是与原始数据差异较大时,此时要多调节一些网络层,直至微调全部。
- 当目标数据极少,同时还与原始数据有较大差异时,可以尝试先微调网络后几层再微调整个网络模型。
- 针对目标数据极少 ,同时还与原始数据有较大差异的情况,一种方法是:借助部分原始数据与目标数据协同训练。因为预训练模型的浅层网络特征更具有泛化性,所以可以在浅层特征空间选择目标数据的近邻作为原始数据子集。之后,将微调阶段改造为多目标学习任务。一是将目标任务基于原始数据子集,二是将目标任务基于全部目标数据。
-
总结:
(1)关于模型参数的优化算法选择,随机梯度下降法是目前使用最多的网络训练方法。
(2)在理想的网络参数初始化和学习率设置方案下,随机梯度下降法得到的网络更稳定,结果更可靠。
(3)若希望网络更快收敛且需要训练较复杂结构的网络时,推荐使用Adagrad、Adadelta、RMSProp、Adam等优化算法。
(4)Adagrad、Adadelta、RMSProp和Adam是性能相近算法,在相同问题上表现并无较大差异。
(5)随机梯度下降、动量法随机梯度下降和Nesterov型动量法也是性能相近的算法。
(6)上面讲到的算法都是一阶梯度算法,基于牛顿法的二阶优化算法也是存在的。但是直接使用二阶方法用于深度卷积网络优化目前是不现实的。因为这种方法需要在整体海量的训练集上计算海森矩阵,会带来巨大的计算代价。
不平衡样本的处理
- 不平衡的训练样本会导致训练模型侧重样本数目较多的类别,而轻视样本数目较少的类别。这样模型在测试数据上的泛化能力会受到影响。
- 从数据层面和算法层面解决不平衡样本问题。
数据层面处理方法
- 数据层面处理方法借助数据采样阀使得整体训练集样本趋于平衡。
一:数据重采样
- 简单的数据重采样包括上采样和下采样。
- 对于样本较少类,使用上采样,即复制该类图像直至与样本最多类的样本数一致。也可以用数据扩充方式来代替简单的复制操作。
- 对于样本较多类别,使用下采样。
- 对深度学习而言,下采样并不是随机丢弃一部分图像,因为那样做会降低训练数据多样性进而影响模型泛化能力。
- 正确的下采样方式是:在批处理训练时对每批随机抽取的图像严格控制其样本较多类别的图像数量。
- 如果仅仅使用数据上采样可能会引起模型过拟合,更保险和有效的数据重采样是上采样和下采样结合使用。
二:类别平衡采样
- 把样本按照类别分组,每个类别生成一个样本列表。
- 训练过程中先随机选择一个或者几个类别,然后从各个类别所对应的样本列表中随机选择样本,这样可以保证每个类别参与训练的机会比较均衡。
- 但是这种方法不适用于海量类别任务。
- 在类别平衡采样的基础上,还有类别重组的平衡方法。
- 类别重组法:只需要原始图像列表即可完成同样的均匀采样任务。
- 类别重组的过程:首先按照类别顺序对原始样本进行排序,之后计算每个类别的样本数目。记录样本最多的那个类别的样本数量。之后,根据这个最多样本数对每类样本产生一个随机排列列表。然后用这个列表中的随机数对各自类别的样本数求余,得到对应的索引值。接着根据索引值从该类的图像中提取图像,生成该类的图像随机列表。之后把所有类别的随机列表连在一起随机打乱次序,即可得到最终图像列表。可以发现最终列表中每类样本数目均等。根据此列表训练模型,当训练列表遍历完毕,则重头再做一遍上述操作即可。进行第二轮训练,如此重复下去。
- 类别重组法的优点在于:只需要原始图像列表,且所有操作均在内存中在线完成,易于实现。类别重组法与数据下采样有异曲同工之意。
算法层面处理方法
- 对于不平衡样本导致样本数目较少的类别欠学习这一现象,一个解决办法是:增加小样本错分的惩罚代价,并将此惩罚代价直接体现在目标函数中,即代价敏感方法。
- 这样通过优化目标函数就可以调整模型在小样本上的注意力。算法层面处理不平衡样本问题的方法多从代价敏感角度出发。
一:代价敏感方法
- 代价敏感方法有两种,一个是基于代价敏感矩阵,另一个是基于代价敏感向量。
- 通过指定代价敏感矩阵或者是代价敏感向量的错分权重,可以缓解样本不平衡带来的影响。
模型集成方法
- 集成学习是机器学习中的一类学习算法。指的是训练多个学习器并且将它们组合起来使用的方法。
- 集成学习通常会比单个学习器有更好的预测结果。
- 深度模型的集成从数据层面和模型层面两方面着手。
数据层面的集成方法
一:测试阶段数据扩充
- 把在训练阶段用到的数据扩充手段用在测试集上
二:简易集成法
- 是一种针对不平衡样本的集成学习方法。
- 思路是:对于样本较多的类采取降采样,每次采样数依照样本数目最少的类别而定,这样每类取到的样本数可以保持均等。
- 采样结束后,针对每次采样得到的子数据集训练模型,采样、训练反复进行多次。
- 最后对测试数据的预测依据训练得到若干个模型的结果取平均或者是投票获得。
- 简易集成除了能实现模型集成,还能缓解数据不平衡。
模型层面的集成
一:单模型集成
多层特征融合
- 多层特征融合是针对单模型的集成方法。
- 网络不同层特征富含的语义信息可以相互补充。
- 在图像语义分割、细粒度图像检索、基于视频的表象性格分析等任务中经常用到多层特征融合策略。
- 多层特征融合时可以直接将不同层网络的特征级联。
- 在特征融合时关于网络层的选取:最好使用靠近目标函数的几层卷积特征,因为越深层的特征包含的高层语义越强,分辨能力也越强。如果是选择网络的浅层特征,用于特征融合很可能起不到作用,可能甚至会起到反作用。
网络“快照”集成
- 深度神经网络模型复杂的解空间中存在很多的局部最优解,但是批处理随机梯度下降法mini-batch SGD只能让网络模型收敛到其中一个局部最优解。
- 网络快照集成就是利用网络解空间的这些局部最优解来对单个网络做模型集成。
- 通过循环调整学习率可以使得网络依次收敛到不同的局部最优解。
- 将收敛奥不同局部最优解的模型保存可以得到M个处于不同收敛状态的模型。
- 测试阶段,做模型集成时,由于深度网络在初始训练阶段未必拥有优越性能,所以在测试阶段,一般挑选最后m个模型快照用于集成。
多模型集成
多模型的生成策略
- 第一种:同一模型不同初始化:不同的网络模型参数初始化会导致不同的训练结果。
- 实际中,特别是小样本学习,首先对同一模型不同初始化操作,之后将得到的网络模型进行结果集成会大幅缓解其随机性,提升最终任务的预测结果。
- 第二种:同一模型的不同训练轮数:如果网络超参数设置得当,深度模型随着网络训练的进行会逐步趋于收敛,但是不同训练轮数的结果仍有不同,无法确定到底哪一轮训练得到的模型最适用于测试数据。
- 所以简单的解决办法是:将最后几轮训练模型结果集成,这样既能够降低随机误差,也可以避免训练轮数过多带来的过拟合风险。
- 这种操作叫做轮数集成。
- 第三种:不同目标函数: 选择不同的目标函数即损失函数可以使得网络学习到不同的特征表示。
- 以分类任务为例,可以将交叉熵损失函数、合页损失函数、大间隔交叉熵损失函数、中心损失函数作为目标函数分别训练模型。
- 在预测阶段,既可以直接对不同模型预测结果做置信度级别的平均或者投票,也可以做特征级别的模型集成。
- 将不同网络得到的深度特征抽取后级联作为最终特征,之后再离线训练浅层分类器(如支持向量机)完成预测任务。
- 第四种:不同网络结构: 操作时可以在VGG或者深度残差网络等不同的架构上训练模型,最后将不同架构网络得到的结果集成。
总结:
- 多模型集成上,可以通过不同参数初始化、不同训练轮数和不同目标函数的设定产生多个网络模型的训练结果。最后使用平均法、投票法和堆叠法进行结果集成。
- 之前提到的随机失活dropout实际上也是一种隐式的模型集成方法。
梯度累积的trick
- 一般增大batch size会使得最终的预测效果变好,但是GPU显存是有限的,不可能无限增大batch size,这时候梯度累积就发挥作用了。
- 梯度累积就是累积多个batch的梯度然后一次更新参数,而不是常用的一个batch更新一次,这种trick在小数据集上是有效果提升的。
#loss,preds,step_acc = train_step(model,inputs,labels,criterion,optimizer)
#将batch_accumulate_size个batch的梯度累积起来,只在最后一侧更新网络参数
inputs = inputs,to(DEVICE,dtype=torch.float)
labels = labels.to(DEVICE,dtype=torch.float)
if step % batch_accumulate_size == 0:
optimizer.zero_grad()
with torch.set_grad_enables(True):
#forward
outputs = model(inputs)
#下面式子中损失值要除以batch_accumulate_size的原因是在使用梯度积累这个trick时,
# 需要确保累积梯度的平均值与之前的相同,所以为了使得梯度变得相同就需要在每次batch_accumulate_size时
# 将损失值除以batch_accunulate_size值。
# 如果进行了除以batch_accumulate_size操作后,就无需更改学习率,如果不进行出发操作,就要将学习率除以iter_size来获得相同的性能
# 在使用这个梯度累积trick时,假设使用SGD作为优化器。
loss = criterion(outputs,labels.long())/batch_accumulate_size#一定要除以这个batch_accumulate_size。
loss.backward()
_,preds = torch.max(outputs,1)
correct_num = torch.sum(preds == labels.long())
step_acc = correct_num.double()/inputs.size(0)
if (step + 1) % batch_accumulate_size == 0:
optimizer.step()#只在最后一次更新网络参数
loss = batch_accumulate_size * loss.item()#转换为数字方便后面使用
step_acc = step_acc.item()
训练时要多去尝试不同的模型。
- 将多个模型的输出集成起来,粗暴一点就是直接将输出的概率值求平均再取top3即得到最终的输出。
predictions balancing trick
- 测试集中的groundtruth分布应该是均匀的,而且(训练集样本数目+1)/类别数目=330(对应于一个特定比赛的计算结果)。这一点很重要,通过对模型输出的概率按照这个规律后处理,平均给每个模型带来0.7%的提升。
- 后处理的算法思路:对于当前最多的预测类别,将所有这个类别对应的概率不断减去一个很小的数,直到这个类别不是最多的,重复上面的过程直到预测类别差不多均匀。
- 类似上面思路的算法可以分解为如下四步
(1)先对每一种类别赋一个初始为1的系数coeddicients,当前预测概率等于实际概率乘以对应的系数。
(2)计算每种类别的数目,按照这个数目再计算一个score,逻辑是预测越均匀则score越大。
- 对最多的类别label,执行coefficients[label] -= alpha
- 若还没有达到最大迭代次数,就继续执行第2步和第3步,执行过程中记录最大的score对应的coefficients,迭代完成后返回这个coefficients。
算法的实现代码:pytorch实现链接
可能存在输入数据图片尺寸越大分数则越高,但是由于显存限制,尺寸越大也就会越难训练。
经常保存checkpoint带来的提升在于:snapshot ensembling,即一个模型最终的预测输出是这个模型的几个checkpoint的综合,最后的输出是多个模型的平均blend。
对于超大数据集的图像类比赛,一般网络越深、图片尺寸越大、batchsize越大,则性能就越好。