kaggle竞赛之Shopee比赛经验与感受

本文主要记录自己在第一次参加kaggle比赛时踩过的坑以及一些参赛经验体会,希望能够对大家有些帮助。

1. 比赛内容和规则

本章简要介绍shopee比赛内容和规则,能够让新手快速了解kaggle竞赛的大致流程。

1.1 比赛内容

Shopee竞赛是一项具有奖金的kaggle竞赛,前三名能够获得奖金,前10 + 0.2%的队伍能获得金牌,前5%的队伍能够获得银牌,前10%的队伍能够获得铜牌。本次我们参赛得分为0.723,获得了铜牌
在这里插入图片描述

Shopee的比赛内容是通过图片来判断这两个商品是否为相同商品,也就是图像匹配的问题或者说是分类问题。此次比赛,训练集有3万多张图片,测试集有7万张图片,而测试集又分为公有测试集和私有测试集,公有测试集中图片数量占比为40%,私有测试集中图片数量占比为60%

当然训练集除了图片外,还有一个train.csv文件,里面包含的信息如下所示:
在这里插入图片描述
总共有五列,官方解释如下:
在这里插入图片描述

第一列为posting_id,是参与匹配的图像编号,最后在提交的测试集匹配结果也是以图像编号的形式输出。第二列为image,是训练集中图像的文件名,可以看到第一列的unique values的数量是大于第二列的unique values的数量的,这说明存在相同的图片文件名对应不同的posting_id(注意并不是数据缺失,此次竞赛所有数据均完整)。第三列为image_phash,是图片的感知哈希值,如果感知哈希值是相同的,那么图片也就是相同的,可以看到它的unique values的数量进一步减少,说明有图片文件名不同但是图片内容是完全相同的。第四列为title,是对图片的描述,通过描述也能够大致区分出两张图片是否为同一产品。第五列为label_group,相同label_group的posting_id就属于同一类。

而测试集的test.csv文件只有最后一列没有,前四列和train.csv文件相同。而最后需要提交的是一份名为“submission.csv”的文件,它只有两列,第一列为测试集中各张图片的posting_id,第二列为与之匹配的其他图片的posting_id(包括它本身)。范例如下所示:
在这里插入图片描述

最后的评分依据F1 score,即:计算每一行的F1 score,然后取平均值。

更加详细的竞赛内容可以参看Shopee - Price Match Guarantee.

1.2 比赛规则

和大多数kaggle竞赛一样,Shopee比赛是通过notebook来提交代码的,通常竞赛会限制代码的GPU运行时间,因此不能选择参数较多的神经网络模型,并且在模型融合的时候也不能选用过多的模型。

首先需要点击如下按钮创建一个新的notebook
在这里插入图片描述
接着在下面的notebook的cell中输入你所写的代码,然后点击“Run All”保证代码能够正常运行,当然右侧的Add Data可以添加你所需要的数据集。接着再点击“Save Version”保存notebook版本,完成这两步后,就可以正式提交代码了。

在这里插入图片描述

提交自己的代码只需要点击下图中的Submission(因为比赛已经结束了所以是late submission),然后选择notebook版本就能提交到kaggle进行评分测试了。
在这里插入图片描述

以上就是整个Shopee竞赛的比赛内容和比赛规则,kaggle上大多数的比赛流程都和这个类似。

2. 算法思路

可以看到Shopee比赛需要用到两部分的关键信息,一部分是图片,如何做特征提取和聚类的问题;另一部分是图片标题,如何将相同意思的文字进行匹配。显然这是一个CV+NLP的竞赛。

2.1 文本处理

由于我和小组的J同学都只对CV有一些了解,对NLP并不了解,所以在做预测的时候直接使用了TDIDF模型,关于此模型的基本原理可以见维基百科:tf-idf,文本预测代码如下所示:

在这里插入图片描述
比赛结束后我阅读了得分前几名的代码,他们基本上都做了一些NLP的技巧处理,而不是单纯地使用某一个模型进行预测,这是我们组只拿到铜牌的重要原因之一。

从此次竞赛来看,文本的信息甚至比图像的信息更管用,因为同一产品他们的图像差异会巨大,但是文本介绍会是相似的,以kaggle中的两张图片为例,以下两张图片属于同一类,可以看到这个背景干扰巨大,但是他们的文本信息一个是KIRIM SETIAP HARI!! GLUTA COLLAGEN SOAP BEAUTETOX CHOCOWHITE WHITEMILKY,一个是GLUTA COLLAGEN SOAP (ready) free jaring sabun,可以看到都有关键词GLUTA COLLAGEN SOAP ,因此文本信息会比图片信息更加有用。

在这里插入图片描述

在这里插入图片描述

2.2 图像检测

在比赛中,我们直接使用timm库中的现有预训练模型(什么是timm库?可以点击链接了解: 视觉Transformer优秀开源工作:timm库vision transformer代码解读.)

在github的timm库中,作者列出了库中各种模型在imagenet中的表现,选取部分截图如下所示:
在这里插入图片描述

虽然有这个准确度排行榜,但是我们并不能按照上面的排行顺序进行模型选择,第一是kaggle竞赛方限制代码的运行时间不超过2个小时,因此如果选用过多参数的模型,可能在对测试集图片进行特征提取时就会超时。第二是在imagenet中取得很好效果的模型不一定在此次竞赛中就能取得很好效果。

经过多次尝试,我们选择了三个模型,分别是:eca_nfnet_l0eca_nfnet_l1tf_efficientnet_b5,这三个模型的参数量都较少,且能够在此次竞赛中取得较好的效果。

接着讲述训练模型的思路:

  • 首先做好准备工作,用class Config将各种需要的参数设为公有变量

  • 用pd.read_csv读取训练集和验证集,用Loader技术读取训练集和验证集的图片(链接: Pytorch数据读取(Dataset, DataLoader, DataLoaderIter)

  • 创建ShopeeModel神经网络模型(即ShopeeModel类),如果处于训练阶段,此模型的forward方法输出loss,而这个loss采用arcface loss的方式,它能够训练模型使得模型具有更好的类区分度,即增大类间距,减少类内距(关于 arcface loss的介绍可以参看链接: 盘点在人脸识别领域现今主流的loss,或者原CVPR论文)。如果在验证或者测试阶段,此模型的forward方法输出提取到的图片特征。ShopeeModel类的主要思路如下图所示:
    在这里插入图片描述

  • 设置adam优化器和学习率更新器scheduler。这部分虽然有些Public notebook使用了一些其他的优化器声称取得了较好的效果,但是从我自己的测试结果来看,和adam优化器相差不大,没有很明显的优劣之分。

  • avg_loss_train = train_fn(model, trainloader, optimizer, scheduler, epoch)开始训练模型。五步:读取数据,优化器梯度置零,计算arcface loss(并输出),误差反向传播,优化器步数更新

  • 对验证集进行测试,用训练好的模型进行特征提取,然后用最近邻算法NearestNeighbors对特征进行聚类,然后进行配对(关于什么是NearestNeighbors算法,可以参看链接: Nearest Neighbors.)。接着再与文本匹配的结果取并集,最后输出配对的f1score得分。

  • torch.save保存模型,Epoch += 1

  • 如果Epoch达到给定值则训练结束,否则从avg_loss_train = train_fn(model, trainloader, optimizer, scheduler, epoch)开始继续训练模型。

我们提交在kaggle上对测试集进行测试的代码思路:

  • 读取已训练的模型.pt文件,主要是图像特征提取的三个模型,然后将三个模型提取的特征torch.cat([feat1, feat2, feat3], dim=1)拼接在一起得到一个合并特征(这是模型融合的一种方式,当时还采取了特征相加取平均的方式,但是没有这个方案好)

  • 然后对提取到的特征进行K近邻聚类,得到图片匹配结果

  • 然后使用TFIDF进行文本匹配得到文字匹配结果

  • 将两个匹配结果取并集,就是如果图片匹配认为A与B,D是一类,文字匹配认为A与B,C是一类,那么取并集后的结果就是A与B,C,D是一类

  • 最后输出匹配结果。

以上讲述了训练的notebook(训练代码)和推理的notebook(测试代码)的思路,但是这里要说几个在比赛中踩到的坑。

1. 1. 1.关于K折交叉验证中训练集和验证集的数据划分问题

因为在我们的模型中涉及到较多的超参数,比如KNN中的k值,arcface loss中的margin值,文本匹配的阈值等等,所以我们很自然地想到使用K折交叉验证的方式来确定这些超参的最优值,当初我们为了尽可能让验证集测试集具有相同或者相近的分布,想了两种划分方式对训练集的数据划分。第一种划分是:以均匀化数据集种类为目标进行划分,即每一折都尽量更多种类的图片。具体做法是,如果一个种类中图片数量小于等于3,那么就把它们放在5折中的一折中,如果一个种类中图片数量大于3小于等于5,那么就把它们放在5折中的两折中,其中一折为2张,另一折为2张或3张图片,如果一个种类中图片数量大于5小于等于7,那么就把它们放在5折中的三折中,其中一折为2张,下一折为2张,下下一折为2张或3张图片,依次类推,如果有图片数量超过10张的种类,那么这个种类会在每一折中出现。注意将图片放到折里面是按照轮流顺序放置的,这样也就能够保证每折的图片数量大致相同。

这样做的好处是在交叉验证中,验证集的图片种类尽可能多地在训练集中出现过。

第二种划分是:同一种类的照片放在一折里,保证验证集中的种类与训练集中的种类毫无关系。

具体采用哪种方式进行k折交叉验证(k=5)取决于测试集的情况,经过我们的测试发现,第二种划分方式更加合理,k折交叉验证得到的分数和在公开测试集中得到的分数贴近,这也说明测试集中出现的图片训练集基本是没有的。

2. 2. 2.关于K折交叉验证的有效性问题

上面我们绞尽脑汁地想让验证集和测试集的分布类似,但是实际上在比赛后期我们发现无论怎么调超参都调不对,我们在K折交叉验证中得到的参数对f1 score影响的规律总是和实际测试集中参数与f1 score的关系相反。后来发现原因是测试集样本有7万张图片,公开测试集中图片有2.8万张,训练集只有3万张,可以看到训练集和测试集的图片数量几乎相同,验证集无论怎么去划分,都不能很好地拟合测试集的情况。在这个调超参的方向上,我们花费了大量的时间,结果发现,用K折还不如不用,直接提交到kaggle上看模型在测试集上的得分更加靠谱

3. 3. 3.Moco算法替代arcface loss算法,对timm库中的模型训练

arcface loss算法是用于有标签的有监督学习,而这个比赛的label_group参数只是用来标记图像是不是同一类,因此它本质上是一个无监督的聚类问题,它的标签并没有实际含义,并且在对测试集进行测试的时候我们也不需要预测出他们的标签然后再配对,是直接提取特征再进KNN聚类配对的,因此我们当时想arcface loss算法可能并不是最好的loss方法。

之后我们找了何凯明的CVPR论文Moco算法(论文链接: Momentum Contrast for Unsupervised Visual Representation Learning.)来替代arcface算法。Moco算法要解决的问题是无监督学习的特征学习问题,我感觉它确实更加符合我们的这个问题。Moco算法是contrastive learning的改进,contrastive learning是通过两个encoder,一个encoder q,一个encoder k,一张图片A输入到q中得到其特征,一批图片输入到k中得到他们的特征,在一批图片中有一张图片和A是相似的,而其他图片都是不相似的,也就意味着有1个正样本,很多个负样本,再用contrastive loss反向传播,去训练q和k网络,使得正样本与A的点积越大,而负样本与A的点积越小,这样就能够充分地提取A的特征。当然负样本越多,所提取的特征越好。但是负样本过多,encoder k的训练会变得极慢,甚至会因为显存的限制没办法达到太高,而Moco就是为了解决存储大量负样本训练的问题,它采用延时更新的策略(这有点像强化学习的Q-learning思想),也就是Moco干脆不用梯度反向传播去更新encoder k,而只用contrastive loss去反向传播更新encoder q,这样k的参数没有用梯度去更新,就能够存储大量负样本,但是不意味着k的参数不更新,k的更新方式是直接按比例加上q的参数,即:Para_k=m* Para_k + (1-m) * Para_q,作者发现当m=0.999时效果最好,也就是k的参数更新是非常缓慢的。

一通操作猛如虎,当我们把moco算法用到我们的模型中时发现,训练出来的模型并不work,它几乎总是会把所有类别都归为一类,当时我们调了很久也没有调出来,最后还是选择放弃moco算法了。

比赛结束后看Shopee比赛中的高分代码,他们也没有人使用moco去训练模型,而是用arcface loss,cosface loss等方法进行模型训练,哎所以参加kaggle还是不要乱找论文啊,多看看讨论区还是很有必要的,

3. 经验总结

总结一下此次kaggle竞赛,主要有以下几点提醒一下没参加过kaggle的小伙伴:

1.不要自己去随便找论文,特别是新手,非常不建议这么做。多看kaggle的讨论区,讨论区中的方案多半是可行的,对讨论区中的方案进行改进是很好的提分手段

2.一定要首先搞清楚训练集和测试集样本之间的关系,像此次比赛两者样本数量几乎接近,那就基本可以放弃K折交叉验证了,如果两者样本分布相近,那么K折交叉验证是很好的调超参数的手段。

3.注意kaggle上对代码运行时间的限制,尽可能地选择多的模型进行融合。

4.此次竞赛NLP的知识很重要,高分的队伍基本都有很好的NLP处理方式。

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值