前言
我之前回答了一个深度学习调参的问题,整理了从2019年月1到12月的一些经验,没想到这几天竟然火起来了,2天之内涨了快300赞同,看来大家还是比较关注这方面的。然后昨天晚上,旷世的akkaze-郑安坤也发表了他的调参技巧,也是非常的实用和精炼,因此在取得了他的授权后,我在这篇推文转载他的回答同时附上我自己这一年所总结的技巧。我觉得这些方法应该让更多人看看,给大家一些帮助,一些启发,所以就有了这篇文章。文章一共分为两部分,一部分为akkaze的调参技巧,另一部分为BBuf的调参技巧,均总结在2020年元旦前。
akkaze 调参技巧
网络能深则深,在保持比较小宽度的时候,要想办法加深网络,变深的过程中网络慢慢变胖。
使用小卷积核,小卷积核有利于网络走向更深,并且有更好的识别鲁棒性。下采样在网络前几层的密度大一些,(这样能尽可能用微弱精度损失换取速度提升) 越往后下采样的密度应该更小,最终能够下采样的最大深度,以该层的感受野以及数据集中最大的有意义物体尺寸决定(自然不可能让最大有意义的物体在某一层被下采样到分辨率小于1,但是网络依然可以work,只不过最后几层可能废弃了(相信cnn的学习能力,因为最大不了它也能学出单位卷积,只有中心元素不为0的卷积核),更准确的说这是最大感受野的极限,最大感受野覆盖最大有意义的物体)。所以一般做法是前面几层下采样频率高一点,中间层下采样频率降低,并使用不下采样的方法提高深度。
原网址:https://www.zhihu.com/question/25097993/answer/951697614
shortcut connection里,找不到concat,用add凑合吧,反之亦然。先训一个大模型然后裁剪,也许比直接训一个小模型性能好。网络最后面完全可以使用不采样的空洞卷积来做,对于分割尤其如此。
最后面不要再下采样了,考虑使用aspp来融合不同尺度的感受野
转置卷积完全可以使用上采样+卷积来替代。
能用可分离卷积替代的卷积一定要替代,一般除了第一个卷积,都能替代,替代完后考虑给替代可分离的通道数乘以2,因为可分离卷积的参数和计算量都是线性增长的,这样做依然有速度增益。同样的道理适用于2+1分离卷积。
计算量线性增长,可以控制通道数和depth multiplier,代价小
inception或者shortcut connection或者dense connection其实都相当于ensemble模型,考虑结合使用,shortcut connection的使用几乎是无痛的。
感受野也不是越大越好(大感受野意味着更多的语义信息),对于某些low-level的任务而言,比如图像降噪,感受野可能也就局部patch大小,对于low-level而言,下采样的意义更小,尽可能少使用下采样。
对于low-level而言,感受野不用太大,具体指去噪,去马赛克,图像增强,和关键点等任务。
各种魔改的softmax能更好的增大类间差距
Buff调参技巧
先声明,我只是一个入行刚一年的民工,深度自然和广度自然没有akkaze那么强,所以不免有错误或者没有描述清楚之处,有任何问题请联系我。
做工程
- 卷积是CNN的主流组件。平时有设计一些解决分类,回归任务的网络,里面的卷积核基本都设置为,要说原因的话应该去问问
VGG16
吧。两个的卷积核堆叠能获得卷积核的感受野并且参数比卷积核少,所以是大量推荐使用的。 - 可以适当使用卷积。为什么要提这一点呢,这是因为卷积可以减少计算量,并且卷积可以在某个方向强调感受野,也就是说假如如果你要对一个长方形形状的目标进行分类,你可以使用的卷积核搭配的卷积核对长边方向设定更大的感受野,或许可以获得泛化性能的提升。
- ACNet结构。这个研究来自于ICCV2019,可以在卷积的基础上加上和的旁路卷积核,最后在推理阶段把三个卷积核都
fusion
到卷积核上,在许多经典CV任务上都可以获得大概1个点的提升。大家可以看看这篇文章解读,来自公众号AI科技评论。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个步骤,第一个是减均值,第二个是除以方差。这样做下来最后的输入值域为[-1,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
加3*3
卷积代替反卷积做上采样得到的结果更平滑,并且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。
END