8月23日开始参赛,9月9日结束,初赛排名 23 / 613。源码地址:ymlgithub/hw-garbage战绩

赛题介绍

本次比赛选取40种生活中常见的垃圾,选手根据公布的数据集进行模型训练,将训练好的模型发布到华为ModelArts平台上,在线预测华为的私有数据集,采用识别准确率作为评价指标。这次比赛中有很多容易混淆的类,比如饮料瓶和调料瓶、筷子和牙签、果皮和果肉等外形极为相似的垃圾,因此此次竞赛也可看作是细粒度图像分类任务。

可回收物指适宜回收和资源利用的废弃物,包括废弃的玻璃、金属、塑料、纸类、织物、家具、电器电子产品和年花年桔等。厨余垃圾指家庭、个人产生的易腐性垃圾,包括剩菜、剩饭、菜叶、果皮、蛋壳、茶渣、汤渣、骨头、废弃食物以及厨房下脚料等。有害垃圾指对人体健康或者自然环境造成直接或者潜在危害且应当专门处理的废弃物,包括废电池、废荧光灯管等。其他垃圾指除以上三类垃圾之外的其他生活垃圾,比如纸尿裤、尘土、烟头、一次性快餐盒、破损花盆及碗碟、墙纸等。

参赛思路

浏览数据集

入手分类任务,首先要浏览数据集。下图横坐标是类标号,纵坐标是每个类的样本数量。很容易看出,每个类之间的样本量差异很大,如果不做类均衡处理,很有可能会导致样本量多的类过拟合,样本量少的类欠拟合。常见的类均衡方法有:多数类欠采样,少数类过采样;数据增强;在损失函数中设置类权重。在本次比赛中,类均衡与否对训练结果几乎没有影响。 官方数据分布

数据集划分

训练集/验证集的划分对指导本地模型训练有重要影响,合理的数据集划分可以使本地验证集准确率与线上准确率保持一致,在本地就能看到模型效果。我们对原始数据集按照4:1的比例划分出训练集和验证集,并且采用分层采样,保证训练集和验证集保持同分布。另外,对原始数据集进行划分也保证了独立性。这样独立同分布的划分使得线上和线下的准确率相差不超过1个百分点。很多新手数据增强之后再划分训练集和验证集,出现原始样本出现在训练集、增强样本出现在验证集或相反的情况,结果训练集和验证集准确率都达到99%以上,线上准确率却很低,起不到验证集应有的作用。

验证集能拟合线上数据的一个重要前提是线上和线下数据集独立同分布,幸运的是本次比赛的数据集基本满足这一前提。在之前参加的Kaggle地震预测赛中,线上和线下数据分布极不一致,导致我们验证集得分1.9,公榜得分1.3,私榜得分2.6,炸榜现象严重。验证数据集分布是否一致的方法有KS-检验(Kolmogorov-Smirnov test) -- 检验数据是否符合某种分布对抗验证--adversarial validation。如果线上线下数据分布不一致,就需要先从原始数据集中选取与线上一致的子集,再划分训练集和验证集。

数据增强

数据集划分完之后,就可以酌情对训练集进行数据增强,常用的图像数据增强方法可以参考imgaug。值得注意的是,并非所有数据增强方法都有效,要保证数据增强后目标仍可肉眼分辨,且不改变图像所属类别。我们这次比赛只用到了水平和垂直翻转,其它方法都没能提升模型效果,过多的数据增强也会延长模型训练时间,得不偿失。至于为什么其他数据增强方法没有效果,我们浏览了官方数据集中的图像,发现很多图像都是对同一物体不同角度的观察,可以看作这些图像已经做过数据增强,如下图所示。 同一物体不同角度的观察

数据增强也分为在线增强和离线增强,在线增强是在指训练过程中对输入的图像随机增强,能保证模型在每个Epoch中训练的图像基本不同,使模型泛化性能更好,但也会延长每个Epoch的时长。离线增强则是在模型训练前就将训练集进行扩充,增强后的图像放回训练集,但也使每个Epoch训练的样本量变大,也延长了每个Epoch的时长。因此最好的选择是采用多线程技术并行在线数据增强。

这次比赛不限制使用外部数据,也就是说可以通过自己拍照、网上爬取等方式获得更多的训练数据,但比较费时耗力。自己找的数据集质量也不够好,与华为公布的数据集分布不同,我们尝试过爬取一些额外数据,最终效果都不好,甚至降低了分数,因此放弃了这种方法。

图像预处理

输入图像通常不是标准的正方形,因此就有两种方法将长方形图像变为正方形,一种是直接通过伸缩变换将两边缩放到同样的尺寸,另一种是先将较短边以固定值填充到与较长边同样大小、再缩放到目标尺寸,分别如下图a、b所示。两者没有优劣之分,都可以尝试。 图像缩放的两种方法

图像分类任务通常不会从零开始训练一个模型,而是先加载在ImageNet、Ciffar等数据集上预训练好的模型权重,再针对当前数据集进行微调,其中一个最重要的问题就是图像预处理方式。我们的图像预处理一定要与预训练模型训练时的一致,有的模型是将图像归一化到0 ~ 1之间,有的中心化到-1 ~ +1之间,也有的减均值后除以方差(全局对比度归一化),不一致的数据处理方式会降低模型收敛速度和任务效果。

迁移学习

虽然Zhiqiang Shen等人通过直接训练模型达到与使用预训练模型同样的效果,但从零开始训练一个分类网络需要耗费大量的时间、精力和技巧,因此使用预训练模型做迁移学习和微调仍是主流也是最便捷的方法。下图是一些常用网络的参数数量和计算量的对比,EfficientNet系列在各方面都具有巨大优势,这个代码库提供了EfficientNet系列的keras版模型结构和预训练权重。预训练模型的选择也不是top-1准确率越高越好,需要根据自己的算力、时间和应用于当前数据集的实际效果决定。 常见网络参数数量和计算量对比

推荐一篇关于迁移学习的博文:Transfer learning from pre-trained models

模型调优

入手任何比赛,基准代码必不可少。基准代码定义了从输入到输出的完整流程,可以验证自己对赛题的理解是否正确,不必考虑模型得分,是后续模型调优的基础。

模型优化可以从改变锁层数量、优化器、学习率、网络结构等角度出发。经过大量的对比试验,我们使用了Efficient-B5作为模型backbone,锁定其block1~block4;使用Adam优化器,初始学习率设为1e-4,每当验证集准确率在3个epoch后无提升,学习率就设置为原来的一半,直到降到1e-5;设置early stopping, 验证集准确率多次无提升后就终止训练;在backbone与分类的全连接网络之间加入了额外的全连接层、BatchNormalization和Dropout层。在文件src_yj/EfficientNet-B5-9.5.14-2.ipynb可以查看最优提交的实现细节。

模型优化可以通过自动调参和手动调参两种方式实现。常用的自动调参算法有网格搜索,随机搜索和贝叶斯调参。网格搜索遍历整个参数空间,适合参数量少,单次运行时间短的模型;随机搜索随机选取参数空间,相比网格搜索更高效;贝叶斯调参则根据历史参数信息,不断更新先验,迭代次数少,速度更快。手动调参需要记录每个参数的改变带来的影响,相比贝叶斯调参可以加入更多的直觉和主观性,但消耗太多精力去思考。本次比赛我们选择了手动调参,很不明智的选择。下次比赛可以试试贝叶斯调参,就不必随时守着代码了。

减少随机性

数据预处理和模型训练过程中都包含一定的随机性,影响模型结构和参数的效果,为避免随机性带来的影响,我们设置了固定的随机数种子,使试验结果可复现。

单次的数据划分也并不能保证训练集和验证集完全独立同分布,检验参数改动效果的最佳方式是交叉验证,但消耗过多的时间和计算资源。另外,通过分层采样、5折划分得到的验证集分数与线上分数相差不超过1个百分点,表现稳定,因此我们并没有采用交叉验证。比赛最后几天,我们把数据集进行了五折划分,分别选取fold 0、fold 3、fold 4作为验证集,训练出三个模型,用这三个模型的预测结果进行投票。期间华为更换了训练集和测试集,强制终止了部分模型的运行;赛事临近结束时判题系统没能撑过压力测试,很多模型被迫终止;直至比赛结束,三模型融合的方案也没能运行成功,效果无从得知,成为了这次比赛中最大的遗憾。

测试时数据增强(Test Time Augmentation, TTA)

在图像分类竞赛中,对测试图像进行数据增强也可以提升模型预测准确率。通过随机裁剪、旋转等数据增强方式,得到一组同一目标的相关图像,最后采用投票的方式确定最终预测结果。线上预测时TTA倍数不宜过多,否则模型会运行超时。TTA也不是倍数越多越好,下图是我们做的一组对比实验,不难看出,TTA倍数不是越高越好,过多的TTA甚至会降低预测准确率;只对图像旋转180度效果最好,能提升1.7个千分点,在竞争激烈的线上有显著的排名提升。 TTA效果

我们也观察到另外一个现象,在其他扩充方式不变的情况下,是否翻转图像几乎不影响预测结果,可能是因为训练时就对图像有翻转增强操作,卷积网络已经学习到了图像的翻转不变性,因此可以认为,训练时数据增强越多,卷积网络就能习得图像的平移、缩放、拉伸等各种不变性,TTA效果就会越不明显。

总结及感想

这次比赛结果不是很理想,但与以前参加的比赛相比,排名进步了不少,同时也学到了很多。这种人工智能比赛,拼的就是时间、算力、财力、精力。调参消耗大量时间,更强大的算力也意味着更多的时间,没有财力也得不到充足的算力,同时具备以上条件,就需要花费大量的精力去优化模型、调节参数、甚至提出创新性的模型。我目前的水平还很有限,需要更加努力学习,争取在未来冲上top10、top5、top1。本文也存在一些不清晰、不完善、不准确的地方,我会持续更新的,欢迎大家留言批评指正。

相传,使用同样的模型和几乎一模一样的参数,pytorch比keras效果要好上很多。pytorch具有很高的灵活性和可定制性,正成为学术界的首选,新提出的模型大多有用pytorch训练出的预训练权重,方便迁移学习,以后可以学习下pytorch。竞赛过程中要多参考相关论文、竞赛和GitHub上的相关代码,探索不同tricks对模型的影响,总会有提升点的。试验也很重要,别人论文和代码里的参数设置只是针对他们面临的问题更有效,并不一定适合我们的任务和模型,重要的是他们的思路和方法;没有万能的模型提升方法,即使是数据增强,也要研究不同增强方法的实际效果。

华为举办这次比赛的目的更多的是宣传ModelArts、找一批廉价的劳动力找出系统BUG、做压力测试。建议新手选择参加Kaggle上更纯粹的算法赛,这种使用ModelArts等不成熟平台的比赛很容易让人在处理平台Bug和琐碎细节的过程中迷失。ModelArts平台目前还很不完善,UI、UX极差,平台经常崩溃,参赛选手也怨声载道,用过了就再不想用。 不提他了