深度学习 “炼丹” 技巧的总结
链接 | https://www.zhihu.com/question/25097993
编辑 | 海边的拾遗者公众号
深度学习调参有哪些技巧?
作者:Jarvix
https://www.zhihu.com/question/25097993/answer/153674495
泻药
只想说一句:初始化
一次惨痛的教训是用normal初始化cnn的参数,最后acc只能到70%多,仅仅改成xavier,acc可以到98%。
还有一次给word embedding初始化,最开始使用了TensorFlow中默认的initializer(即glorot_uniform_initializer,也就是大家经常说的无脑使用xavier),训练速度慢不说,结果也不好。改为uniform,训练速度飙升,结果也飙升。
所以,初始化就跟黑科技一样,用对了超参都不用调;没用对,跑出来的结果就跟模型有bug一样不忍直视。
作者:BBuf
https://www.zhihu.com/question/25097993/answer/934100939
做工程
卷积是CNN的主流组件。平时有设计一些解决分类,回归任务的网络,里面的卷积核基本都设置为 ,要说原因的话应该去问问 VGG16
吧。两个的卷积核堆叠能获得 卷积核的感受野并且参数比 卷积核少,所以是大量推荐使用的。 可以适当使用 卷积。为什么要提这一点呢,这是因为 卷积可以减少计算量,并且 卷积可以在某个方向强调感受野,也就是说假如如果你要对一个长方形形状的目标进行分类,你可以使用 的卷积核搭配 的卷积核对长边方向设定更大的感受野,或许可以获得泛化性能的提升。 ACNet结构。这个研究来自于ICCV2019,可以在 卷积的基础上加上 和 的旁路卷积核,最后在推理阶段把三个卷积核都 fusion
到卷积核上,在许多经典CV任务上都可以获得大概1个点的提升。大家可以看看这篇文章解读:3*3卷积+1*3卷积+3*1卷积=白给的精度提升 卷积核权重初始化方式。对于 weight
的初始化我一般都是使用xavier
初始化。当然也可以可以尝试何凯明大神的He初始化。对于bias的初始化全置于0。Batch Normalization
。这是我一直在使用的技巧,可以很大程度的加快收敛速度。建议搭建自己网络的时候尽量加上BN
,如果有BN
了全连接层就没必要加Dropout
了。目标检测不能盲目去掉 fpn
结构。在针对自己的数据调检测任务如yolov3
的时候不能盲目砍掉fpn
结构,尽管你分析出某个分支的Anchor基本不可能会对你预测的目标起作用,但如果你直接去掉分支很可能会带来漏检。优化器的选择。我基本都是带动量的 SGD
。如果优化不动可以试试Adam
。激活函数。可以先用 ReLU
做一版,如果想再提升精度可以将ReLU
改成PReLU
试试。我更倾向于直接使用ReLU
。batch_size
:在不同类型的任务中,batch_size
的影响也不同,大家可以看看这篇batch_size
对模型性能影响的文章,来自公众号AI开发者。Batch_size是怎么影响模型性能的初始学习率。一般我是从 0.01
开始设置,我个人认为这个学习率和学习率衰减策略是相关的,但不宜设置的过大过小,0.01
和0.1
应该是比较常用的。学习率衰减策略我一般使用multistep
方式,step_size
的设置要看视你的的max_iter
而定。数据与处理之 zero-center
。第一次见到这个词是在看cs231n的视频上。主要有2个步骤,第一个是减均值,第二个是除以方差。这样做下来最后的输入是满足均值为0方差为1的概率分布的,一般减均值是最常用的,后面的除以方差用不用可能需要自己动手试验一下看看效果。残差结构和密集连接。 resnet
的残差结构和dense net
密集连接结构,做工程的时候考虑到速度近乎不可能说完全使用完整版本的resnet
和densenet
的完整结构,但我们可以自己动手将我们网络的某些模块替换为残差结构和密集连接,替换的时候可以适当降低这俩结构的复杂度,类似于通道数减半,密集连接中只保留一半连接等等。这里需要做一些消融实验来验证改进后的精度。关于loss。优秀的 loss
一般是对模型的泛化性能有所改善的,但在用loss
的时候往往并不是直接替换loss
那么简单,需要仔细思考loss
背后的数学原理,要用对地方才可有提升。例如,如何将Focal Loss用到YOLOv3中提升map
,大家可以看看这个帖子。https://www.zhihu.com/question/293369755。找到模型调参时的可靠评价指标。在调整参数训练模型时一定要找到正确的评价指标,没调整一个参数就要记录一下模型的评价指标如准确率, map
值,miou
值等。并且在调参时建议将调整的参数和在测试集上的精度组合成一个字符串给模型重命令,方便之后快速review
。使用了带 backbone
的网络,如训练VGG16-SSD
建议选择finetune
的方式,从头训练不仅费时费力,甚至难以收敛。在做分割实验的时候我发现用upsamling 加1*1卷积代替反卷积做上采样得到的结果更平滑,并且miou差距不大,所以我认为这两者都是都可以使用的。 一些Anchor-based目标检测算法为了提高精度,都是疯狂给框,ap值确实上去了,但也导致了fp会很多,并且这部分fp没有回归,在nms阶段也滤不掉。相比于ap提升而言,工程上减少fp更加重要。Gaussian yolov3的fp相比于yolov3会减少40%,Anchor-free算法暂时接触得不多,就不太了解了。
做比赛
特征提取。VGG16,VGG19,ResNet50,Xception是非常好用的几个特征提取模型。建议使用训练好的经典模型对数据集提取特征向量存储到本地,更方便使用,同时可以大幅度降低显存消耗。 ensemble: 将不同的经典网络提取出的特征向量,假设 VGG16
提取出的特征向量维度是[N,c1]
,ResNet50
提取的特征向量维度是[N,c2]
,Xception
提取的特征向量维度是[N, c3]
,那么我们可以使用三个系数a、b、c
将其组合为形状为[N, a*c1+b*c2+c*c3]
,其中a、b、c
三个参数的取值代表我们使用哪个模型的特征多一些,如果是分类回归比赛,我们在后面接特征处理网络就可以了。可以取不同的a、b、c
得到不同的特征,然后对结果做voting
,soft-voting
等多种处理,一般结果不会太差啦。可以使用不同的初始化方式训练出模型,然后做ensemble。 可以使用用不同超参数(如学习率, batch_size
,优化器)训练出不同模型,然后做ensemble。
因为我就做了一点点入门级比赛,上面介绍的方法取得了还不错的结果,所以我就在这里献丑啦,方法确实挺无脑的,大家笑一笑就好啦。继续想了下,我好像除了这些有接触或者使用到,暂时没有什么其它的了,如果想起其他的了,之后补充下。
作者:Captain Jack
https://www.zhihu.com/question/25097993/answer/127472322
我和@杨军类似, 也是半路出家. 现在的工作内容主要就是使用CNN做CV任务. 干调参这种活也有两年时间了. 我的回答可能更多的还是侧重工业应用, 技术上只限制在CNN这块.
首先说下可视化:
关于权重的可视化[Visualize Layer Weights](现在是否强求smooth其实意义不大, 这个后面说.):
同样, 你看到一个不满足平滑结果的图像, 你知道, 这网络训练的不好, 但是为什么呢? 是数据不好? 没有预处理? 网络结构问题? Learning Rate太大或者太小? 或者就是差了一个LRN层(之前我就遇到, 加个LRN就能出smooth的weights, 当然这其实和预处理有关)?
Smooth是需要看一下的, 心里有个数. 但是具体调参怎么调是没辙的. 第一, 你不可能告诉网络, 这层你得学个边界检测的功能出来. 第二, 不同任务下会有不同的weights(虽然底层的特征有很大的通用性), 你觉得你凭什么来指导一个看图片比你快得多的机器?
再说现在是否需要强求smooth. 现在的趋势是鼓励使用小filter, 3x3大小, 多加层次(这样, 非线性更好点). 换句话说, 3x3的图片, 总共才9个像素, 你怎么判断smooth与否呢? 当然如果你使用大的filter, 一般5x5往上, 运气不差的话, 你是可以看到smooth的结果的.
咱们再说另外一个极端, 一个网络,运行的完美(满足应用要求就算完美), 打开一看, 这weights不smooth啊. 你告诉我, 你打算怎么办? 没错, 具有不平滑的权重的网络同样可以获得很好的结果(这种情况我都习以为常了).
那么可视化网络就不重要了?
那么怎样训练一个不错的网络呢?
Using convolutional neural nets to detect facial keypoints tutorial
我自己的经验, 有下面这些:
快速试错
+ 你要验证自己的训练脚本的流程对不对. 这一步小数据量, 生成速度快, 但是所有的脚本都是和未来大规模训练一致的(除了少跑点循环)
+ 如果小数据量下, 你这么粗暴的大网络奔着过拟合去都没效果. 那么, 你要开始反思自己了, 模型的输入输出是不是有问题? 要不要检查自己的代码(永远不要怀疑工具库, 除非你动过代码)? 模型解决的问题定义是不是有问题? 你对应用场景的理解是不是有错? 不要怀疑NN的能力, 不要怀疑NN的能力, 不要怀疑NN的能力. 就我们调参狗能遇到的问题, NN没法拟合的, 这概率是有多小?
+ 你可以不这么做, 但是等你数据准备了两天, 结果发现有问题要重新生成的时候, 你这周时间就酱油了.
+ 多任务情况下, 各loss想法限制在一个量级上, 或者最终限制在一个量级上, 初期可以着重一个任务的loss
给NN一点时间, 要根据任务留给NN的学习一定空间. 不能说前面一段时间没起色就不管了. 有些情况下就是前面一段时间看不出起色, 然后开始稳定学习.
+ 太大: loss爆炸, 或者nan
+ 太小: 半天loss没反映(但是, LR需要降低的情况也是这样, 这里可视化网络中间结果, 不是weights, 有效果, 俩者可视化结果是不一样的, 太小的话中间结果有点水波纹或者噪点的样子, 因为filter学习太慢的原因, 试过就会知道很明显)
+ 需要进一步降低了: loss在当前LR下一路降了下来, 但是半天不再降了.
+ 如果有个复杂点的任务, 刚开始, 是需要人肉盯着调LR的. 后面熟悉这个任务网络学习的特性后, 可以扔一边跑去了.
+ 如果上面的Loss设计那块你没法合理, 初始情况下容易爆, 先上一个小LR保证不爆, 等loss降下来了, 再慢慢升LR, 之后当然还会慢慢再降LR, 虽然这很蛋疼.
+ LR在可以工作的最大值下往小收一收, 免得ReLU把神经元弄死了. 当然, 我是个心急的人, 总爱设个大点的.
判断过拟合, 训练是否足够, 是否需要early stop的依据, 这都是中规中矩的原则, 不多说了.
CV的任务, context window是很重要的. 所以你对自己模型的receptive field的大小要心中有数. 这个对效果的影响还是很显著的. 特别是用FCN, 大目标需要很大的receptive field. 不像有fully connection的网络, 好歹有个fc兜底, 全局信息都有.
简短的注意事项:
预处理: -mean/std zero-center就够了, PCA, 白化什么的都用不上. 我个人观点, 反正CNN能学习encoder, PCA用不用其实关系不大, 大不了网络里面自己学习出来一个. shuffle, shuffle, shuffle. 网络原理的理解最重要, CNN的conv这块, 你得明白sobel算子的边界检测. Dropout, Dropout, Dropout(不仅仅可以防止过拟合, 其实这相当于做人力成本最低的Ensemble, 当然, 训练起来会比没有Dropout的要慢一点, 同时网络参数你最好相应加一点, 对, 这会再慢一点). CNN更加适合训练回答是否的问题, 如果任务比较复杂, 考虑先用分类任务训练一个模型再finetune. 无脑用ReLU(CV领域). 无脑用3x3. 无脑用xavier. LRN一类的, 其实可以不用. 不行可以再拿来试试看. filter数量2^n. 多尺度的图片输入(或者网络内部利用多尺度下的结果)有很好的提升效果. 第一层的filter, 数量不要太少. 否则根本学不出来(底层特征很重要). sgd adam 这些选择上, 看你个人选择. 一般对网络不是决定性的. 反正我无脑用sgd + momentum. batch normalization我一直没用, 虽然我知道这个很好, 我不用仅仅是因为我懒. 所以要鼓励使用batch normalization. 不要完全相信论文里面的东西. 结构什么的觉得可能有效果, 可以拿去试试. 你有95%概率不会使用超过40层的模型. shortcut的联接是有作用的. 暴力调参最可取, 毕竟, 自己的生命最重要. 你调完这个模型说不定过两天这模型就扔掉了. 机器, 机器, 机器. Google的inception论文, 结构要好好看看. 一些传统的方法, 要稍微了解了解. 我自己的程序就用过1x14的手写filter, 写过之后你看看inception里面的1x7, 7x1 就会会心一笑..
作者:随机漫步的傻瓜
https://www.zhihu.com/question/25097993/answer/951804080
1、首先,调参的时候你要整理好自己的心情。别误会,我的意思是让你狂躁一点。因为这玩意有时候的确是个玄学,经常调半天毛用都没有,然后只是换一个初始值,分分钟给你干到95%以上。是的,你其实啥也没做,但大部分时候这玩意儿跟人很像,“出身”很重要。
作者:京东白条
https://www.zhihu.com/question/25097993/answer/651617880
相信很多刚开始接触深度学习朋友,会感觉深度学习调参就像玄学一般,有时候参数调的好,模型会快速收敛,参数没调好,可能迭代几次loss值就直接变成Nan了。