CVPR 2020 AliProducts Challenge: 3/688 Place Solution

  4月底的时候心血来潮,想打个比赛玩玩,然后就找到了天池的AliProducts Challenge[链接]。比赛过程中的体验,和整天在实验室的服务器上跑实验还是有很大区别的。不仅学到了很多tricks,每天调参时的“摸奖”也很刺激。

  开放测试集以后我们合租了一台四卡的服务器打这个比赛,真是下了血本了。。。 最后拿到了Top3,而且把很多想法都做work了,还是很有成就感的。

  这里推荐一下mistGPU,有多种GPU型号可供选择,价格公道(比大部分云服务器都便宜),可以按量付费也可以包月,简直是学生党的福利~~

mistGPU

  代码开源在 https://github.com/misads/AliProducts。欢迎围观和star~

  有兴趣也可以看看我们在CVPR Workshop的[Report][Video]

比赛介绍

  这次比赛要解决的是一个大规模的商品分类问题。要求将数十万张图片准确地分为50000类。数据样例如下图所示:

  dataset_preview

  我们知道在学术界,ImageNet是一个众所周知的检测基准,尽管它设计的十分完美,但是很难在工业中应用。虽然图片的标注可能不是百分百正确,但它的确是一个十分高质量的数据集(标注基本正确,类别平衡)。因此在使用这个数据集的时候,只需要专注于算法表现的提升,而不用关心数据的质量。而与工业界中的业务数据却十分不同,数据可能并不是人工标注的(如WebVision比赛),存在许多错误标签和噪声,而且类别与类别之间的图片数量十分不均衡。

  针对本次比赛训练集中的噪声问题,一味地调整模型和算法治标不治本。阿里巴巴一项针对商品分类的研究显示,如果训练数据的精度不到80%,那么训练出来的模型的精度是72%左右,无论模型怎么调整,精度只有2%~3%的提高,无法达到上线要求,因此还是需要从数据源头上解决问题。

数据分析

图像数量

  该数据集十分具有挑战性,数据集的划分如下面的表格所示,其中训练集的图片和类别数量均远大于ImageNet(1k)数据集。并且训练集并不是人工标注的,而是采用网络爬虫等手段获取的,并不是十分可靠。而验证集和测试集是人工标注的,训练集和验证/测试集分布的不同使得训练十分困难。

数据集划分 图像数量 类别
训练集 2,552,385 50,030
验证集 148,387 50,030
测试集 250,130 50,030

类别不均衡和尺度多样性

  训练集中存在着类别不均衡和图像尺寸变化大的问题。如下图所示,一些类别有接近8000张图像,但是绝大多数类别的图像数不到200。甚至有一些类别只有几张图像。而验证集的类别较为均衡一些,与训练集的分布并不相同。

distribution

  图像的尺寸变化范围很大,如下图所示。经过我们的统计,图像的平均长宽比约为1.0,宽和高的平均值都在480左右。


size

错误标注

  如下图所示,数据集中存在着一些明显错误的标注,在类别19999中,大部分的图片是抽纸,但是也存在将手抓饼、红包等标注为抽纸的情况。 wrong_annotations

解决方案

baseline

  该问题仍然是一个图像分类问题,因此基础网络结构我们尝试了一些在ImageNet比赛中获奖的经典结构,如ResNet, ResNeXt等,也尝试了近几年来提出的网络结构,如EfficientNet, iResNet, ResNeSt等等。损失函数仍然采用传统的交叉熵函数。我们的网络结构基于PyTorch搭建,优化器为Ranger (RAdam+Look Ahead),训练代数为20代,学习率遵循cos函数从1e-420代中逐渐衰减到1e-5

  输入图像统一缩放到256×256大小,在输入时使用了数据增强,图像有几率被水平或垂直翻转,并且归一化到相同的均值和方差,网络的输出结点数为50030(和分类总数相同)。 由于数据存在很多噪声,我们提出了一种简单但十分有效的数据清洗方法,并且在实验中证明十分有效,这一部分将在算法流程中介绍。

改进——数据清洗方法

  为了同时解决数据不平衡和数据噪声的问题,我们使用了一个3阶段的训练过程,如下图所示:


training_precedure

  步骤1:预训练。首先,整个网络模型在原始的含有噪声的训练集上进行训练,直到收敛。
  步骤2:数据清洗。然后,我们使用基于loss最小化的数据清洗方法,用步骤1训练的模型对原始训练集进行数据清洗,得到一个样本均衡并且相对更为干净的数据集。
  步骤3:清洗数据微调。最后,我们将步骤1训练的模型在步骤2过滤出的数据集上继续进行训练,直到收敛。

  在步骤1中,由于模型是在含有许多噪声的训练集上训练的,十分难以收敛,因此我们对比了几种模型的效果,最终使用ResNeSt(101)作为基础网络结构。并且使用了ImageNet权重初始化,大batch size,cos学习率衰减,Ranger优化器等训练技巧。

  在步骤2中,我们将训练集继续训练1个epoch,记录所有图像的loss。然后将每个类别的图像loss进行排序,每个类别选取loss最小的5张图像,得到一个样本均衡并且相对更可靠的训练集。如下图所示:


refinement

  为了进行对比实验,我们也尝试了选取loss位于中间的图像(为了挖掘难样本)以及loss处于[a,b]之间的图像。最终发现对loss最小的图像继续训练能够取得最好的效果。

  在步骤3中,我们将步骤1训练的模型在步骤2过滤出的数据集上继续进行训练,此时由于训练集的图像loss都十分小,所以要将loss乘以一个大的常数。另外,我们发现在这一步中标签平滑十分有作用,标签平滑将传统的非0即1的one-hot编码,转变为概率的形式。正样本为1-ε,负样本为 ε/(K-1),其中ε是一个超参数,K是类别数。在我们的实验中ε设为0.2效果最佳。

  值得注意的是,我们提出的3步的训练步骤是一个可迭代的过程。也就是说,步骤3训练的模型可以继续用来对训练集进行清洗,二次清洗过的数据也可以重新用来训练新的模型。


ensemble

  此外,我们还是用了一些其他的技巧来提升精确率。如测试时增强和模型融合,在测试时,我们对图像进行水平和垂直翻转后预测,并对预测的概率取平均值。我们使用相同的配置和不同的随机种子训练了多个模型,并对它们的预测结果取平均值进行模型融合,如上图所示,得到最后的提交结果。

实验结果

backbone选择

  不同模型的训练损失如下图所示:我们对比了ResNet101, ResNeXt101, Res2Net101, iResNet101, ResNeSt101。最终ResNeSt无论在训练集和测试集都能获得最好的结果。


backbone

涨分的提交汇总

  我们的提交结果如下表所示。从表中可以看出:更换一个更好的网络、更换优化器、我们提出的数据清洗方法、标签平滑和数据增强等训练技巧,以及模型融合,都能够明显改善最终的结果。

模型 线上分数
ResNet101+Adam ~0.37
ResNeSt101+Adam ~0.33
ResNeSt101+Ranger ~0.29
+filter label nosie ~0.21
+label smooth / data augmentation ~0.14
+filter label nosie again and fine-tune ~0.11
+5 models ensemble ~0.09

尝试了但是不work的方法

  • Class-aware sampling (无法解决数据噪声问题,训练时间太久)
  • Dynamic Meta Embedding (显存不够)
  • Focal loss / Range loss
  • OHEM
  • Mixup (可能是因为类别过多,类别较少时mixup才有效?)
  • Pseudo label

致谢

主办方:


alibaba

承办方:


tianchi

感谢两位队友的大力支持:

  jklp2

  qxyan

比赛总结

  • 模型融合真的是好用啊,稳定涨分,特别是模型的相关性越低,涨的分越多。
  • 如果能使用一个更好的过滤方式,比如使用聚类和度量学习等,过滤出更干净的训练集,可能会得到更好的结果。但是时间来不及了,有点可惜。

发表评论

电子邮件地址不会被公开。 必填项已用*标注