陆陆续续两个月的赛程结束了,从初赛A榜27到B榜第4,再到决赛A,B双榜第一,有过断断续续排名下降即将无缘现场决赛的失落,也有过现场决赛等待被超越的12小时,心情跌到起伏像极了今年来的股市。
下面进入正题,介绍MTM在这个比赛的相关工作,该方案来自MTM里面的两只年轻滚滚biubiubiu以及lcy。初赛选手及未参加的同学建议全篇阅读,决赛选手建议阅读集成与模型中LGB模型这两个小节,来快速温习我们取胜的关键。
代码开源地址:由于主办方要求,代码暂时无法开源,在此我们尽量将方案描述清楚
注:MTM将第一时间在将一些比赛方案,Baseline,解题锦囊发布在公众号,知乎(https://zhuanlan.zhihu.com/p/201389840)偏向于赛后分享与讨论。
如果有问题请在知乎提问,或者在github发一个issue。
本次赛题旨在使用手机中的加速度传感器数据(包含重力加速度(acc_xg, acc_yg, acc_zg)和不含重力加速度(acc_x, acc_y, acc_z)),来进行不同场景下(站立,行走,坐卧)的行为(刷抖音,玩游戏...)预测,以期智能检测手机端的金融诈骗行为。详细介绍请参考官方网站。
初赛提供了7500左右的训练数据与7500条的测试数据,做一个人19分类,决赛数据量大约是初赛的两倍,做一个20分类,类别较初赛有所增删。
注意:初赛数据,训练集与测试集分布差异较大(可以通过一些特征选择方法看出,猜测很可能是是按采集数据所用的设备id,或者按采集数据的志愿者id划分的),而采样点数据分布相对集中,集中在60左右。决赛数据分布差异则不太明显(猜测是按照样本id随机划分的,另外可进一步推测决赛AB榜也是按照样本id随机划分的),但是采样点数据分布差异很大,中值22,最大值60+,最小值只有2。另外,决赛数据精度要比初赛数据高。
采样点数量与训练集测试集分布这两点的变化是决赛破题的关键。
决赛数据采样点数量分布
决赛数据train test分布差异很小
初赛时间:6.17-8.7,形式为线上A,B榜,B榜前30名,提交docker复现,取前10名现场决赛,现场决赛分代码比拼跟现场答辩两部分。
其中代码比拼赛制与初赛一样,时长25小时,共50次提交机会,很多选手不分昼夜,持续作战。有许多队伍决赛逆袭,甚至一战登顶。非常适合临场发挥稳定的选手参加。另外,决赛提供一块V100(16G),不允许使用额外的算力,不允许使用初赛数据训练和预训练。这非常考验初赛模型的鲁棒性与轻便性,以及参赛选手的临场发挥能力。
我们着眼的这个题的难点在于:1.在保证特征交互的同时下对时序建模2.有效解决采样点数量差异(决赛)
初赛模型以OTTO开源的baseline为基础,做了如下几个调整:
def add_features(df):
print(df.columns)
df['acc'] = (df.acc_x ** 2 + df.acc_y ** 2 + df.acc_z ** 2) ** .5
df['accg'] = (df.acc_xg ** 2 + df.acc_yg ** 2 + df.acc_zg ** 2) ** .5
df['thetax']=np.arctan(df.acc_xg/
np.sqrt(df.acc_yg*df.acc_yg+df.acc_zg*df.acc_zg))*180/np.pi
df['thetay']=np.arctan(df.acc_yg/
np.sqrt(df.acc_xg*df.acc_xg+df.acc_zg*df.acc_zg))*180/np.pi
df['thetaz']=np.arctan(df.acc_zg/
np.sqrt(df.acc_yg*df.acc_yg+df.acc_xg*df.acc_xg))*180/np.pi
df['xy'] = (df['acc_x'] ** 2 + df['acc_y'] ** 2) ** 0.5
df['xy_g'] = (df['acc_xg'] ** 2 + df['acc_yg'] ** 2) ** 0.5
df['g'] = ((df["acc_x"] - df["acc_xg"]) ** 2 +
(df["acc_y"] - df["acc_yg"]) ** 2 + (df["acc_z"] - df["acc_zg"]) ** 2) ** 0.5
print(df.columns)
return df
train=add_features(train)
test=add_features(test)
LSTM模型,采用与CNN2d相同的分组提取的思路,LSTM模块中添加LayerNormalization与DropOut层可以明显提升模型线上效果(初赛),SelfAttentionLayer收益不大,另外,需要对数据预先进行标准化处理(即对原始DataFrame按列标准化),否则模型很难收敛到很好的效果。决赛沿用了与初赛相同的模型,复赛线上77。
作为梯度提升模型永远的神,LightGBM模型结合统计特征对时序进行建模具有很强的可解释性及出色的泛化能力。在决赛GPU资源有限的情况下,充分利用CPU资源不得不说是一个非常好的发力点。在初赛过程 LightGB的表现并不抢眼(73左右),而在决赛数据中却大放异彩(768)。我们考虑可能的原因如下:
整个决赛对该模型的调试过程如下:
['min', 'max', 'mean','sum','median',"skew",'kurt', 'mad','std','var','q10', 'q20', 'q25', 'q30', 'q40', 'q60', 'q70', 'q75', 'q80', 'q90','entropy_values',"range_value","root_mean_square"]
得益于树模型与NN的模型差异,我们将此树模型集成收益高到2个百以上,具体请参考下一小节。
赛后了解到很多队伍使用了blending(加权融合),有些队伍使用了stacking进行集成。
不难发现这一常识,对于序列长度较短的样本,使用LightGBM训练统计特征可以取得很好的效果,而且泛化能力较强,而序列长度较长的样本,依赖拟合能力更强的NN模型(CNN,LSTM等)来在保证充分进行特征间交互的前提下,充分提取时序特征,因此设计不同的专家模型是解决序列长度不一的好方法。需要注意的是,本文训练的模型,并不是说直接按照序列长度进行划分,直接训练不同的模型,而是分别使用全量的数据训练不同的模型(1树模型与deep模型本身可以独立的解决该问题,2更多的数据可以有效提高模型的泛化能力,所以使用全量数据训练,集成学习做专家选择)。下面介绍我们的集成方案:
我们有三个模型,一个CNN2d(线上78,本小节分数皆为决赛A榜成绩),一个LSTM(线上77)一个LGB(线上768),(不难发现单模成绩并不高,)将三个模型的概率(按照stacking的模式)与sample number特征进行拼接,第二层学习器使用LGB进行集成,即可以达到808,明显地可以看到较单模最高成绩有近三个百分位的提升,而很多模型比我们好的队伍,集成并没有取得很好的效果,追究原因,我觉得可以从下面几个角度跟大家分享:
在举个例子,某mtm想解决一个问题,于是找来一个数学家,一个历史学家,一个实验物理学家,一个经济学家,然后你有一个问题,并且你知道它属于哪个领域。使用blending,就是按照偏好给各个科学家(学者)权重(所有样本统一的权重,而不能case by case),然后让他们投票,自然不能很好地利用术业有专攻这一先验知识。另一方面,知道该问题是哪个领域非常关键,这解决影响mtm偏好于听取哪位学者的意见。
看似侥幸的胜利,实际上我们花了好多心思,非常感谢队友的努力,感谢初赛期间MTM-zhangqibot提供的机器。在成为MTM的道路上,有一群志同道合的小伙伴,真的是一件很幸运的事情。在比赛的过程,有幸结识了很多大佬,见识了他们比模型还deep的脑洞,非常开心。希望以后还可以在赛场上正面battle。