深度学习工程师被称为“炼丹工程师”,自然是因为在日常工作中需要各种各样的调参工作。虽然因为Google的研究使得AutoML这两年大热,但是对于大部分人来说,还没有机器玩得起AutoML,而且手动调参数也是一门必备的技能。
试问:连调试参数都要交给电脑了,就你那三脚猫的python语言基础和弱不禁风的数学基础,端得起一碗高薪的饭吗!
1任务选择
要学习调试参数,必须有一个比较好的任务,它一定是要有一定的难度,但是不能太难。它能体现出不同参数的差异,但又不能太敏感。
这里我给大家选了一个任务,细粒度图像分类,方法选择双线性网络,参考git链接
https://github.com/gy20073/compact_bilinear_pooling。
所谓细粒度图像分类,就是要将不同子类区分,通常来说,有不同种类的猫,不同种类的花等等,这里我们选择了一个公开数据集,选择的数据集为Caltech-UCSD Birds-200-2011,它包括200类鸟,共11788张图片,每一个类约60个样本,图片的分辨率大小不等,长度都在400分辨率左右。
将数据集均匀分为训练集和测试集,各10597和1192张图。
它的任务就是要区分上面的鸟,特点就是有效的信息只存在于很细小的局部区域中。关于分类任务,更多的信息请关注我们上一篇文章,图像分类绝对不是一个简单的任务,请重视。
【技术综述】你真的了解图像分类吗?
话不多说,开始吧。
2开始调参
深度学习参数真的太多了,这个参数不是说神经元的参数,而是说用于训练网络的参数。
上图只是展示了其中一些比较重要的参数,实际上随便数数20个以上是没有问题的。咱们时间机器有限不可能所有的都调试,今天就来调试其中的几个最重要的,迁移学习,分辨率以及正则项。
2.1 迁移学习
如果你想快速训练好一个任务,那么请从迁移学习开始,不要从头开始训练,尤其是新手。
一个好的初始化太重要了,迁移学习就是给你提供了一个绝佳的初始化。
咱们这个任务是非常难的,因为类别多,数据少,而且类内方差很大,所以我们开始进行迁移学习的时候,不妨保守一点,只学习全连接层。
注意这个任务的最后几层如上,分别是一个双线性网络层和两个归一化层,一个全连接层,训练参数如下,完整的网络配置请参照git。
test_iter: 300
test_interval: 600
display: 100
max_iter: 60000
lr_policy: "multistep"
base_lr: 0.1
gamma: 0.25
stepvalue: 20000
stepvalue: 30000
stepvalue: 40000
stepvalue: 50000
momentum: 0.9
weight_decay: 0
snapshot: 10000
snapshot_prefix: "snapshot/ft_last_layer"
net: "ft_last_layer.prototxt"
iter_size: 4
经过了60000次迭代后,查看下训练的准确率迭代曲线和损失迭代曲线如下
可以看出,网络发生了过拟合,这也是在预料之中,因为训练集中每一类的图像只有60张左右,而数据增强只做了随机裁剪,而且是在全图经过了缩放之后的裁剪操作。
最后,我们对数据集进行了测试,准确率为74.5%。
我们再放开所有网络层进行学习,具体配置如下
test_iter: 300
test_interval: 100
display: 100
max_iter: 20000
lr_policy: "fixed"
base_lr: 0.001
momentum: 0.9
weight_decay: 0.0005
snapshot: 10000
snapshot_prefix: "snapshot/ft_all"
net: "ft_all.prototxt"
结果如下
可以看到,损失继续降低,同时精度也继续提升,20000次迭代后准确率从74.5%提升到86.8%。当然,模型仍然是过拟合的,这是因为样本数据集是在太小,只有增加数据集,实验更多的数据增强方法才能更好的解决这个问题。
关于数据集和数据增强方法,请查看往期文章。
【数据】深度学习从“数据集”开始
[综述类] 一文道尽深度学习中的数据增强方法(上)
【技术综述】深度学习中的数据增强(下)
那可不可以直接对所有层进行学习呢,没问题,可以收敛的。
但是效果就要差一些了,最终只能到0.79。
那不用双线性模型,直接使用分类模型如何?我的实验结果是很差,惨不忍睹,这里就不放出来了,而且非常难调参。
从这一次的调参至少可以得到一个结论,迁移学习是很重要的,妥妥的提升性能。而且其中的技巧非常多,只能多去练手了,看文章是学不到的。
2.2 输入输出分辨率
如果你的模型没毛病,但是效果始终不好,不如提高分辨率,当然这意味着更大的计算量。
通常来说,更大的输入分辨率总是可以取得更好的效果,尤其是对于检测和分割等任务。在我们这个任务中,还可以调整双线性网络的输出特征维度大小,这可以认为是输出维度,也可能是一个比较关键的参数。
所以我们同时对输入分辨率和双线性网络的输出层的维度进行一系列实验,输入尺度分别选用448,336,224这3个,输出维度分别选用8192,4096,2048,1024,保持其他参数不变,迭代60000次,测试结果如下:
可以看出,图像的分辨率对模型性能的影响非常大,从448降低到224之后,准确率下降将近10%。双线性输出特征层的维度,从8192降低到1024后,只有微小的下降,几乎对性能没有影响,当然这并不意味着其他的任务也是如此,事实上对于图像分割和目标检测任务来说,最后一层卷积输出的特征图大小是最重要的参数。
2.3 正则化因子
当模型在训练集上的表现明显优于测试集的时候,说明发生了过拟合,缓解过拟合最简单的方法是增加数据。当增加数据的方案行不通的时候,可以通过添加L1,L2,dropout等正则化方案,这分别是隐式正则化和显式正则化方法。
在caffe框架中,通过调整Weight_decay来实现,默认使用的是L2正则化方法。Weight_decay是乘在正则化项的因子,这一般可以提高模型的能力,一定程度上缓解模型的过拟合,但是视不同任务而定,我们在前面训练模型的时候没有加正则项。
分别比较weight_decay=0,weight_decay=0.00001, weight_decay=0.001对结果的影响,其中weight_decay=0对应的就是第一个训练的基准模型。
没有取得我们预期的效果,可能是wr的参数试的不够多,可能是其他的参数需要调试。
wr=0.001的时候曲线如上,可以看到模型相比于上面的一些更好的模型,提前收敛了,但是却收敛到了不好的效果,过拟合情况更加严重。
这个时候应该怎么做呢?在数据集不能变的情况下,调节学习率?还是继续调节正则化因子,只有实验结果才能验证了。
除去上面这些参数,还有学习率大小与迭代方法,batch size大小,初始化方法与各种优化方法,数据增强等各种参数,其中有一些参数对结果还是很有影响的,就留着读者自己去调试吧。