这是本人写的第一篇博客,小白一枚,如有错误的地方,欢迎大佬们批评指教。
首先这次的竞赛让人受益匪浅,那庞大的数据量,让人感叹这是一场有钱人的游戏。感谢学校的服务器,几乎没休止的转了一个多月,哈哈哈。
虽然最后成绩不咋地,但是这次成长还是很大的,特此总结以下经验。
问题描述
这次比赛的任务是寻找相似人群,其实就可以看成是CTR问题。
关注官方竞赛群
一般只要是比较正式的比赛都会有官方的交流群,大家在这里交流,同时这里也是你成长的关键地方,如果比赛的等级够高的话,会有一堆大佬,在群里给小白指点,但是同时也要擦亮眼睛,因为有个别的人,会给小白错误的指导,所以最好找那种比较知名的大佬,有些大佬很热情,但是有的就比较冷淡了。而且不要问一些很low的问题。。。最重要的是每年都会有baseline代码,你如果错过了,你在起跑线上就已经输了。。。
充分利用github
像这样每年都会举办的比赛,每年github都上会出现一堆源码,也许每年给的数据特征以及数据量都不一样,但是有些强特是公用的。而且对于一些典型的问题,比如CTR预估,已经有一些典型的模型,和其他人写好的源码,你不用就浪费了。
数据处理与特征工程
首先这种类型的竞赛,数据就是根本,应该充分了解你的数据,才能无往不利。如何了解你的数据呢?plot,plot,plot,重要的事说3遍。对于ctr的数据,都有一个特点就是长尾数据。至于什么是长尾数据,请自行百度。对于这种类型的数据,我主要对其进行的操作是,对尾部的数据数据设置成一个新的类别,至于尾部数据的阈值,可以plot之后自己调一下。通过这种方式我们组造了一个强特,有一个appInstall字段,这个字段代表的是60几天的安装的app,我们对这个字段进行了统计,统计了每个用户在这几天里app安装的数量,然后发现这是长尾数据,也就是大多数是这几天里没有安装app的,部分是安装了特别多app的,这部分结合实际的话,其实是安装app来刷单赚钱的人,对这部分人进行单独的分类处理效果不错,在初赛这个特征提升了2个千分点。还有就是正负样本的比例问题,对于此类问题,因模型而异,对于lgb模型的话,如果正负样本差的很多的话,可以采取少采一些样本的方式比较多的类型的样本,比如ctr中正样本极少,所以我们就抽了90%的负样本和全量的正样本训练,训练我们的lgb模型,效果也是在初赛提升了2个千分点。但是对于ffm这样的流式训练的模型的话,不建议这么做,这样做会降低模型的效果。至于其他的强特,都是从github源码中挖掘出来的。
模型的选择与调参
初赛的数据量1000万条数据,在未处理的情况下是4个多G的数据。复赛的数据翻了5倍,大约5000万条数据,在未处理的情况下是20G。
初赛我们使用的模型是lgb和FFM模型。复赛的话,用的是DeepFFM,Deepmvm,lgb等等。
lightGBM
刚刚开赛几天后,就有一个0.73的baseline上线,这个baseline非常的暴力,因为给的特征都是类别型的所以他对所有的特征都进行了onehot之后进行,对于数据量特别大的情况下,一定要记得onehot之后一定要用sparse矩阵,要不然肯定爆内存,这个0.73的baseline,峰值用了服务器大约40G的内存。当然这是因为没有做内存优化的原因。其实当你数据量很大,但是手头计算资源匮乏的时候,内存优化是不可缺少的一部分工作。至于调参工作,在数据量很大的时候有两个方法,一个是按比例抽样出小的数据集用以调参gradsearchCV是一个选择,git上也有别人写好的调参轮子,但是这个时候有可能会使你调出来的参数离最优参数很远。还有一种方法就是控制变量法,其参数不变,每次只调一个参数,这个方法比较慢,但是能取得比较接近最优参数的结果。还有至于为什么要选择lgb而不是xgb,其实很简单,数据量太大,lgb的内存优化,能让我们的服务器能够承受得住。在lgb与xgb相同的参数时,lgb模型40G足够,但是xgb模型64G也不够。同时速度也是一个方面,lgb的话,据说速度比xgb快10倍。但是lgb的GPU加速部分,我尝试了一下,其实基本速度没什么提升,显存的占用也是很低。复赛的时候,由于数据量大大增加,所以我们将数据分成5分,分别训练一个模型之后,进行融合。随后进行了内存的优化,可以分两份,各训练一个模型然后融合,模型的效果又有提升。
FFM
台大的一个队伍开源的模型,git上有开源的源码,其中libffm抛弃了一次项,速度快,make一下就可以用,由于是流式训练,所以8g的笔记本都可以跑起来。模型的效果也是相当可观的,与lgb的表现相近,但是还是与lgb差一点。这个模型的调参的话是相当重要的,最开始没调参的时候,模型的线上效果才0.6,调完参数之后0.741,最好用上面的控制变量法调参。要是想用gradsearchCV调参的话,你可以用python重写ffm,并且按照sklearn的标准编写函数。顺带一提北京大学信息科学技术学院开发的xlearn,支持ffm,并且没有抛弃一次项。
DeepFFM
一到复赛,打比赛的方式就变了,可以说和初赛完全不一样,首先是复赛的数据是初赛的5倍,这么庞大的数据量,一次性全加载到内存是不现实的。所以最好利用python的yield,训练一部分数据,加载一部分数据。当然这只适用于流式训练的模型。lgb的话,处理方法上文已经说过,不再赘述。至于什么是DeepFFM请自行百度。接下来我说一下在编写神经网络时的一些心得,我主要用的框架是pytorch以及tensorflow,怎么说呢?两个框架各有利弊,首先说一下pytorch吧,这个框架极易上手,编程模式也是命令式编程,但是有益处当然也有很多的坑,其中我在这次比赛中遇到的坑就是pytorch里最好不要用python的for循环,用也最多只用一层,不然速度能慢死你,能用向量化优化的地方尽量优化一下,还可以用矩阵乘法来代替for循环,这种方式是最快的。pytorch还有一点好的地方就是你可以很轻松的配置多GPU并行加速训练。接下来是tensorflow,这个框架就是申明式编程,一种你不熟悉的编程方式,有的时候很别扭,但是很多优化的地方你都不需要做,直接调用api即可。但是tensorflow还有一个磨人的地方就是,你要是想多GPU并行运算的话,需要自己去写,并不能直接像pytorch那样,千万别以为tensorflow占用了你所有的GPU资源,显存也占满了,他就是在充分利用资源。这只不过是tensorflow的贪心特性,默认占用所有可用的最好的计算资源,当然可以配置取消这种特性。
还有最重要的一点:在这种数据量超大的情况下,在编写神经网络的时候,一定要弄一个小的线下训练集,这样方便调试bug,开发速度也快,切记切记!!!
模型融合
这次的竞赛我并没有用stacking和blending这两种常见的模型融合方法,感兴趣的自行百度。我是直接用的结果取平均的方式,加权的方式我也试过,但是效果不如直接取平均好。还有就是融合的模型之间在原理上相差越多,融合的效果就越好,简单的理解就是过拟合的部位不一样,一取平均就减缓了过拟合的状况。
总结
参加竞赛一定要一心一意扎进去,全心全意投入去做,才会有提升,切忌心浮气躁,最好不要双开,除非你是大牛。希望你永远保持着,大智若愚,求知若饥的心态。