一、深度学习中常用的调节参数
本节为笔者上课笔记(CDA深度学习实战课程第一期)
1、学习率
步长的选择:你走的距离长短,越短当然不会错过,但是耗时间。步长的选择比较麻烦。步长越小,越容易得到局部最优化(到了比较大的山谷,就出不去了),而大了会全局最优
一般来说,前1000步,很大,0.1;到了后面,迭代次数增高,下降0.01,再多,然后再小一些。
2、权重
梯度消失的情况,就是当数值接近于正向∞,求导之后就更小的,约等于0,偏导为0
梯度爆炸,数值无限大
对于梯度消失现象:激活函数
Sigmoid会发生梯度消失的情况,所以激活函数一般不用,收敛不了了。Tanh(x),没解决梯度消失的问题。
ReLu Max(0,x),比较好,代表Max门单元,解决了梯度消失的问题,而且起到了降维
权重初始化,可以随机也可以一开始设置一定的图形分布,用高斯初始化
3、层数
越多,灵敏度越好,收敛地更好,激活函数也越多,曲线的性能也更好
但是,神经元过拟合,并且计算量较大层数越多。在节点多的情况下一般会考虑:Drop-out
节点太多也不好,所以需要删除一些无效的节点
但是去掉节点,这里却是随机的,随机去掉(30%-60%)的节点
注意:随机的选择,去掉一些节点。但是drop-out也不一定是避免过拟合
很常见。一般不drop-out一定会过拟合,有drop-out概率低一些
4、过拟合
上面的drop-out就算一种。其他过拟合可能也会使用:BN,batch normalization(归一化)
在caffe操作时候,模型训练中如何解决过拟合现象?
看到验证集的数据趋于平稳,譬如第1000次之后,验证集的loss平稳了,那么就截取1000次,把学习率降低为原来的0.1,拿来第10000次结果,修改文件,继续训练。
.
5、Loss设计与观察
一般来说分类就是Softmax, 回归就是L2的loss. 但是要注意loss的错误范围(主要是回归), 你预测一个label是10000的值, 模型输出0, 你算算这loss多大, 这还是单变量的情况下. 一般结果都是nan. 所以不仅仅输入要做normalization, 输出也要。
准确率虽然是评测指标, 但是训练过程中还是要注意loss的. 你会发现有些情况下, 准确率是突变的, 原来一直是0, 可能保持上千迭代, 然后突然变1. 要是因为这个你提前中断训练了, 只有老天替你惋惜了. 而loss是不会有这么诡异的情况发生的, 毕竟优化目标是loss.
对比训练集和验证集的loss。 判断过拟合, 训练是否足够, 是否需要early stop的依据
二、caffe训练时Loss变为nan的原因
本节转载于公众号平台:极市平台
1、梯度爆炸
原因:梯度变得非常大,使得学习过程难以继续
现象:观察log,注意每一轮迭代后的loss。loss随着每轮迭代越来越大,最终超过了浮点型表示的范围,就变成了NaN。
措施:
1. 减小solver.prototxt中的base_lr,至少减小一个数量级。如果有多个loss layer,需要找出哪个损失层导致了梯度爆炸,并在train_val.prototxt中减小该层的loss_weight,而非是减小通用的base_lr。
2. 设置clip gradient,用于限制过大的diff
2、不当的损失函数
原因:有时候损失层中loss的计算可能导致NaN的出现。比如,给InfogainLoss层(信息熵损失)输入没有归一化的值,使用带有bug的自定义损失层等等。
现象:观测训练产生的log时一开始并不能看到异常,loss也在逐步的降低,但突然之间NaN就出现了。
措施:看看你是否能重现这个错误,在loss layer中加入一些输出以进行调试。
示例:有一次我使用的loss归一化了batch中label错误的次数。如果某个label从未在batch中出现过,loss就会变成NaN。在这种情况下,可以用足够大的batch来尽量避免这个错误。
3、不当的输入
原因:输入中就含有NaN。
现象:每当学习的过程中碰到这个错误的输入,就会变成NaN。观察log的时候也许不能察觉任何异常,loss逐步的降低,但突然间就变成NaN了。
措施:重整你的数据集,确保训练集和验证集里面没有损坏的图片。调试中你可以使用一个简单的网络来读取输入层,有一个缺省的loss,并过一遍所有输入,如果其中有错误的输入,这个缺省的层也会产生NaN。
案例:有一次公司需要训练一个模型,把标注好的图片放在了七牛上,拉下来的时候发生了dns劫持,有一张图片被换成了淘宝的购物二维码,且这个二维码格式与原图的格式不符合,因此成为了一张“损坏”图片。每次训练遇到这个图片的时候就会产生NaN。
良好的习惯是,你有一个检测性的网络,每次训练目标网络之前把所有的样本在这个检测性的网络里面过一遍,去掉非法值。
4、池化层中步长比核的尺寸大
如下例所示,当池化层中stride > kernel的时候会在y中产生NaN
layer {
name: "faulty_pooling"
type: "Pooling"
bottom: "x"
top: "y"
pooling_param {
pool: AVE
stride: 5
kernel: 3
}
}
http://*.com/questions/33962226/common-causes-of-NaNs-during-training
.
.
三、一些训练时候出现的问题
本节转载于公众号深度学习大讲堂,文章《caffe代码夜话1》
1、为啥label需要从0开始?
在使用SoftmaxLoss层作为损失函数层的单标签分类问题中,label要求从零开始,例如1000类的ImageNet分类任务,label的范围是0~999。这个限制来自于Caffe的一个实现机制,label会直接作为数组的下标使用,具体代码SoftmaxLoss.cpp中133行和139行的实现代码。
132行第一层for循环中的outer_num等于batch size,对于人脸识别和图像分类等单标签分类任务而言,inner_num等于1。如果label从1开始,会导致bottom_diff数组访问越界。
.
2、为什么Caffe中引入了这个inner_num,inner_num等于什么
从FCN全卷积网络的方向去思考。FCN中label标签长度=图片尺寸
caffe引入inner_num使得输入image的size可以是任意大小,innuer_num大小即为softmax层输入的height*width
.
3、在标签正确的前提下,如果倒数第一个全连接层num_output > 实际的类别数,Caffe的训练是否会报错?
不会报错且无影响
.
4、BN中的use_global_status
图2. ResNet部署阶模型Proto文件片段
但是如果直接拿这个Proto用于训练(基于随机初始化),则会导致模型不收敛,原因在于在Caffe的batch_norm_layer.cpp实现中,use_global_stats==true时会强制使用模型中存储的BatchNorm层均值与方差参数,而非基于当前batch内计算均值和方差。
首先看use_global_stats变量是如何计算的:
图3. use_global_stats计算
再看这个变量的作用:
图4. use_global_stats为true时的行为
以下代码在use_global_stats为false的时候通过moving average策略计算模型中最终存储的均值和方差:
图5. BatchNorm层均值和方差的moving average
因此,对于随机初始化训练BatchNorm层,只需要在Proto文件中移除use_global_stats参数即可,Caffe会根据当前的Phase(TRAIN或者TEST)自动去设置use_global_stats的值。
.
5、BatchNorm层是否支持in place运算,为什么?
BN是对输入那一层做归一化操作,要对每个元素-均值/标准差,且输入输出规格相当,是可以进行in place。
标准的ReLU函数为max(x, 0),而一般为当x > 0时输出x,但x <= 0时输出negative_slope。RELU层支持in-place计算,这意味着bottom的输出和输入相同以避免内存的消耗。
.
.
四、过拟合解决:dropout、batch Normalization
来源于:https://github.com/exacity/deeplearningbook-chinese/releases/
1、dropout——另类Bagging(类似随机森林RF)
引用自Dropout作者:
在标准神经网络中,每个参数接收的导数表明其应该如何变化才能使最终损失函数降低,并给定所有其它神经网络单元的状态。因此神经单元可能以一种可以修正其它神经网络单元的错误的方式进行改变。而这就可能导致复杂的共适应(co-adaptations)。由于这些共适应现象没有推广到未见的数据,将导致过拟合。我们假设对每个隐藏层的神经网络单元,Dropout通过使其它隐藏层神经网络单元不可靠从而阻止了共适应的发生。因此,一个隐藏层神经元不能依赖其它特定神经元去纠正其错误。(来源:赛尔译文 Dropout分析)
Dropout可以被认为是集成非常多的大神经 网络的实用Bagging方法。当每个模型是一个大型神经网络时,这似乎是不切实际的,因为训练和 评估这样的网络需要花费很多运行时间和内存。
Dropout提供了一种廉价的Bagging集成近似,能够训练和评估指数级的神经网络。
操作方法:将一些单元的输出乘零就能有效地删除一个单元。
(1)具体工作过程:
Dropout以概率p关闭神经元,相应的,以大小为q=1-p的概率开启其他神经元。每个单个神经元有同等概率被关闭。当一个神经元被丢弃时,无论其输入及相关的学习参数是多少,其输出都会被置为0。
丢弃的神经元在训练阶段的前向传播和后向传播阶段都不起作用:因为这个原因,每当一个单一的神经元被丢弃时,训练阶段就好像是在一个新的神经网络上完成。
训练阶段,可以使用伯努利随机变量、二项式随机变量来对一组神经元上的Dropout进行建模。
(来源:赛尔译文 Dropout分析)
(2)dropout类型:
正向dropout、反向dropout。
反向Dropout有助于只定义一次模型并且只改变了一个参数(保持/丢弃概率)以使用同一模型进行训练和测试。相反,直接Dropout,迫使你在测试阶段修改网络。因为如果你不乘以比例因子q,神经网络的输出将产生更高的相对于连续神经元所期望的值(因此神经元可能饱和):这就是为什么反向Dropout是更加常见的实现方式。
(3)dropout与其他规则
故反向Dropout应该与限制参数值的其他归一化技术一起使用,以便简化学习速率选择过程
正向Dropout:通常与L2正则化和其它参数约束技术(如Max Norm1)一起使用。正则化有助于保持模型参数值在可控范围内增长。
反向Dropout:学习速率被缩放至q的因子,我们将其称q为推动因子(boosting factor),因为它推动了学习速率。此外,我们将r(q)称为有效学习速率(effective learning rate)。总之,有效学习速率相对于所选择的学习速率更高:由于这个原因,限制参数值的正则化可以帮助简化学习速率选择过程。
(来源:赛尔译文 Dropout分析)
(4)优势:
看作是对输入内容的信息高度智能化、自适应破坏的一种形式,而不是 对输入原始值的破坏。
Dropout不仅仅是训练一个Bagging的集成模型,并且是共享隐藏单元的集成模型。这意味着无论其他隐藏单元是否在模型中,每个隐藏单元必须都能够表现良好。隐藏单元必须准备好进行模型之间的交换和互换。
计算方便是Dropout的一个优点。训练过程中使用Dropout产生 n 个随机二进制 数与状态相乘,每个样本每次更新只需 O(n)的计算复杂度。
Dropout的另一个显著优点是不怎么限制适用的模型或训练过程。几乎在所有 使用分布式表示且可以用随机梯度下降训练的模型上都表现很好。包括前馈神经网 络、概率模型,如受限玻尔兹曼机(Srivastava et al., 2014),以及循环神经网络(Bayer and Osendorfer, 2014; Pascanu et al., 2014a)。许多其他差不多强大正则化策略对模 型结构的限制更严格。
(5)劣势:
Dropout是一个正则化技术,它减少了模型的有效容量。为了抵消这种影响,我们必须增大模型规模。不出意外的话,使 用Dropout时最佳验证集的误差会低很多,但这是以更大的模型和更多训练算法的迭
代次数为代价换来的。对于非常大的数据集,正则化带来的泛化误差减少得很小。在
这些情况下,使用Dropout和更大模型的计算代价可能超过正则化带来的好处。只有极少的训练样本可用时,Dropout不会很有效。在只有不到 5000 的样本 的Alternative Splicing数据集上 (Xiong et al., 2011),贝叶斯神经网络 (Neal, 1996)比Dropout表现更好
(Srivastava et al., 2014)。当有其他未分类的数据可用时,无监 督特征学习比Dropout更有优势。
.
2、batch Normalization
batch normalization的主要目的是改善优化,但噪音具有正则化的效果,有时使Dropout变得没有必要。
参数训练过程中多层之间协调更新的问题:在其他层不改变的假设下,梯度用于如何更新每一个参数。但是,一般情况下会同时更新所有层。 这造成了很难选择一个合适的学习速率,因为某一层中参数更新的效果很大程度上取决 于其他所有层。
batch normalization可应用于网络 的任何输入层或隐藏层。设 H 是需要标准化的某层的minibatch激励函数,布置为 设计矩阵,每个样本的激励出现在矩阵的每一行中。标准化 H,我们替代它为
其中 μ 是包含每个单元均值的向量,σ 是包含每个单元标准差的向量。
反向传播这些操作,计算均值和标准差,并应用它们于标准化 H。这意味着,梯度不会再简单地增加 hi 的标准差或均值;标准化操作会 除掉这一操作的影响,归零其在梯度中的元素。
以前的方法添加代价函数的惩罚,以鼓励单位标准化激励统计量,或是 在每个梯度下降步骤之后重新标准化单位统计量。
前者通常会导致不完全的标准化, 而后者通常会显著地消耗时间,因为学习算法会反复改变均值和方差而标准化步骤 会反复抵消这种变化。
batch normalization重新参数化模型,以使一些单元总是被定 义标准化,巧妙地回避了这两个问题。