加入极市专业CV交流群,与6000+来自腾讯,华为,百度,北大,清华,中科院等名企名校视觉开发者互动交流!更有机会与李开复老师等大牛群内互动!
同时提供每月大咖直播分享、真实项目需求对接、干货资讯汇总,行业技术交流。关注 极市平台 公众号 ,回复 加群,立刻申请入群~
导读:这篇论文整理了CNN分类任务中一些常用的Tricks,如改善模型结构,训练过程中的一些Refinements如修改损失函数,数据预处理等,有较大工程意义。
这篇论文的全名是:Bag of Tricks for Image Classification with Convolutional Neural Networks 。论文地址见附录。这篇论文是亚马逊团队对CNN网络调优的经验总结,实验基本是在分类网络实验上做的。目前,论文的复现结果都可以在GluonCV找到,地址为:https://github.com/dmlc/gluon-cv。可以将这篇论文理解为一堆经验丰富的工程师的调参技巧汇总,无论你是在做比赛,做学术,还是已经工作的AI开发者,相信都能从中受益。
下面的Table1展示了本文的一系列Tricks被用在ResNet50网络做分类任务上获得的结果。
可以看到使用本文的技巧,Top1准确率从75.3%提升到了79.29%。所以这一系列技巧还是非常给力的,接下来我们就一起来探索探索。
既然涉及到调参,那么第一步就得有一个BaseLine的结果作为参考,这一BaseLine并非直接截取之前对应的论文的结果,而是作者基于GluonCV复现的。关于复现的细节作者在论文2.1节中说的很清楚,包括数据预处理的方式和顺序,网络层的初始化方法,迭代次数,学习率变化策略等等。
下面的Table2展示了作者复现的ResNet-50,Inception-V3,MobileNet三个BaseLine。
介绍完BaseLine,接下来就来看看作者的优化方法。论文从加快模型训练,网络结构优化以及训练参数调优三个部分分别介绍如何提升模型的效果。
关于模型训练加速,论文提到了2点,一是使用更大的Batch Size,二是使用低精度(如FP16)进行训练(也是我们常说的混合精度训练)。关于使用更大的Batch Size进行训练加速,作者指出一般只增加Batch Size的话,效果不会太理想,例如FaceBook这篇大名鼎鼎的论文有证明:
Accurate, Large Minibatch SGD: Training ImageNet in 1 Hour
然后本文总结了几个重要要的调参方案,如下:
epoch
)
,假设训练阶段的初始学习率是L,那么在第
个batch的学习率就设置为
。
作者将上面的Tricks结合在一起进行训练,下面的Table3展示了使用更大的Batch Size和16位浮点型进行训练的结果,可以看到这俩Tricks相比于BaseLine训练速度提升了许多,并且精度也更好了。
而下面的Table4则进一步展示了这些Tricks的消融实验,证明确实是有效的。
这一小节以ResNet-50为例子展开,下面的Figure1表示ResNet网络的原始结构图,简单来说就是一个输入流加4个stage和一个输出流。其中输入流和每个stage的详细结构在Figure1中间那一列显示,而残差结构则在Figure1中最右边进行显示。
论文在网络结构部分进行改进获得的3种结构如Figure2(a),(b),(c)所示:
最终关于这些改进的网络结构的效果如Table5所示,可以看到效果提升还是有的。
这部分作者提到了4个调参技巧:
而Figure3(b)则表示2种学习率衰减策略在效果上的对比。
new_labels = (1.0 - label_smoothing) * one_hot_labels + label_smoothing / num_classes
完整的Pytorch代码如下:
import torch
import torch.nn as nn
class LabelSmoothing(nn.Module):
"""
NLL loss with label smoothing.
"""
def __init__(self, smoothing=0.0):
"""
Constructor for the LabelSmoothing module.
:param smoothing: label smoothing factor
"""
super(LabelSmoothing, self).__init__()
self.confidence = 1.0 - smoothing
self.smoothing = smoothing
def forward(self, x, target):
logprobs = torch.nn.functional.log_softmax(x, dim=-1)
nll_loss = -logprobs.gather(dim=-1, index=target.unsqueeze(1))
nll_loss = nll_loss.squeeze(1)
smooth_loss = -logprobs.mean(dim=-1)
loss = self.confidence * nll_loss + self.smoothing * smooth_loss
return loss.mean()
具体细节和公式可以再阅读原文,这里展示一下Lable Smooth的效果。
总结就一句话,one-hot编码会自驱的向正类和负类的差值扩大的方向学习(过度的信任标签为1的为正类),在训练数据不足的情况容易过拟合,所以使用Label Smooth来软化一下,使得没那么容易过拟合。
epoch
。式子中的
是一个超参数,用来调节合成的比重,取值范围是
。
最终,在使用了这4个Tricks后的消融实验结果如Table6所示。
当把上面的Tricks迁移到目标检测和语义分割任务同样是有效的,实验结果如Table8和Table9所示。
总的来说,这篇论文给了我们非常多的炼丹技巧,我们可以将这些技巧放迁移到我们自己的数据集上获得效果提升,是非常实用的一篇论文了。
推荐阅读:
极市独家福利
40万奖金的AI移动应用大赛,参赛就有奖,入围还有额外奖励
△长按添加极市小助手
△长按关注极市平台,获取最新CV干货
觉得有用麻烦给个在看啦~