Summary
我的最终解决方案使用了6个模型的简单加权平均集成,这些模型都是公开分享模型的泛化版本:(1) @rasmusrse 和 @anjum48 的 DynEdge 模型,(2) @rsmits 的 LSTM 模型。每个模型直接预测一个3维目标方向向量,使用的损失函数是预测向量与目标向量之间差值的范数。预测向量在计算前不进行归一化处理。
TLDR要点
- 最终集成包含6个模型,线性权重通过非线性优化确定,在保留的完整批次数据上最小化MAE(平均角度误差)
- 模型池包含30个不同模型,通过优化方法选择最佳的6个模型组合。模型包括不同规模的动态图网络和不同规模及头部网络的LSTM网络
- 模型包含不同数量的训练脉冲选择和推理时使用的脉冲数量(不总是相同)。脉冲从整个脉冲集合中随机选择
- 每个模型实际上使用4次并取平均值(因为脉冲集的随机选择)。一个简单观察:较小的事件不需要多次评估
- 预测时,测试集中的每个批次被读入内存并缓存,用于评估所有6个模型(及其4次采样)。由于每个事件的脉冲数量分布,只需要额外约15%的推理即可为每个模型生成4次平均
- 每个模型使用的损失函数是预测向量与真实单位方向向量之差的范数
早期探索
我首先阅读了大量中微子探测相关论文,试图理解问题本质。有许多优秀的帖子和图表(来自论文)展示了中微子如何产生μ子,进而形成次级碰撞并照亮嵌入南极冰层的大量传感器。我不会重复这些优秀信息,但会概述我的解决方案演变过程。
我的第一次提交是线拟合解决方案,得分1.214,后来通过更聪明的脉冲选择(感谢@roberthatch的邻居计数方法)改进到1.174。
随后我决定转向神经网络模型。由于DynEdge模型引起很大关注,我想或许应该反其道而行之,研究其他图神经网络。我实现了PointNet和PointNet++,这些本质上是固定图的DynEdge模型(通过特定半径内的邻居确定图结构),然后对整个解决方案执行类似CNN的操作。PyTorch Geometric的速查表很好地总结了所有支持的GNN模型及相关论文。
在尝试所有GNN模型后,PointNet++效果不佳,我决定深入研究DynEdge模型。安装graphnet模块需要降级太多Python模块(需要使用Python 3.7而非我本地的3.10)。由于我讨厌倒退,我从整个graphnet模块中提取了dynedge代码,使用py-geometric构建自己的DynEdge模型,这让我摆脱了SQLite和其他框架限制,可以构建自己的管道。
我通过将每个parquet批次文件预处理为780个独立的hdf5文件解决了数据规模问题,这些文件包含256x2000xK矩阵(256个事件的数据)。脉冲通过Aux和Charge排序限制在2000个以内,其余部分用零填充。由于hdf5压缩数据,这不会增加存储空间。K个特征包括:x,y,z坐标、时间、电荷、aux标志、邻居数量和一些预计算的时间窗口信息。
这样我就能高效地打乱批次和每个批次中256个事件组的顺序,无需大量内存就能高效地向GPU输送数据。
模型进展
我决定使用批次1-100进行训练,批次601和602进行验证。通常训练600-800个批次,因此每个批次仅使用6-8次。从顶级选手处得知,他们使用了更多数据并训练更久。我的模型可能不够复杂,不需要那么多数据。
我成功复现了DynEdge模型,接近公开笔记本的结果,并尝试了几种变体,包括增加更多层(最多6层)和更大的输出头部。默认只有128维的全连接层,但我最终使用了[384,256,128,64,3]的结构。我最好的DynEdge模型在批次602上达到约1.001的得分。
输出选择
我尝试过输出分箱(再次感谢@rsmits),但发现直接预测3维方向并使用范数||v-pred||作为损失函数效果更好。当v接近pred时,该函数的梯度与角度误差函数非常相似,因此我认为它有效。我无法直接使用角度误差作为损失函数,因为它不控制向量大小,允许预测向量缩小到零。此外,在确保不规范化长度为0的向量时也涉及一些不准确性。
输入选择
我尝试了多种选择输入脉冲的方法。每种排序或选择方法似乎都比随机选择效果差。由于随机选择的特性,通过简单地平均同一模型的4次预测可以提高模型准确性。一个简单的技巧是:意识到脉冲数量少于模型要求的事件没有随机元素,因此不需要重复4次。这意味着我可以在提交时仅用增加15%的计算量完成4倍推理。
回归LSTM模型
我决定回归LSTM模型,并借鉴了RSNA颅内出血挑战赛中获得第2名的@darraghdog的方法(2nd Place)。我使用了多个LSTM层,将每层的输出连接起来,输入到最终的多层全连接预测头部。
最佳模型是3层宽度为512的LSTM。我使用了[256,64,64,3]的预测头部结构及其变体。我还尝试了LSTM输出的注意力机制修改,略有帮助(这只是一个学习到的权重,与LSTM输出点积产生与该序列元素应给权重成正比的信号)。
尝试所有模型
以下是35个模型的得分,展示变化和平均带来的改进。s表示来自每个事件的不同随机脉冲选择,p
你可以看到:使用128脉冲的模型平均可提高约35个基点,使用350或384脉冲的模型提高约6-10个基点。描述包括模型类型和训练使用的脉冲数量。例如:LSTM512x3-384是训练于384脉冲的3层LSTM模型。ATT表示使用了注意力机制。
最佳GNN模型得分为1.001,最佳LSTM模型在批次602上得分为0.9859。我的排行榜分数比批次602上的交叉验证分数低约0.002。我没有提交任何单个模型到排行榜,因为我不想让我的程序受到排行榜拟合的影响。
000
00 dog-qnr-state-664-s9 LSTM512x3-384 p384 s0 0.98869
00 dog-qnr-state-664-s9 LSTM512x3-384 p384 s1 0.98881
00 dog-qnr-state-664-s9 LSTM512x3-384 p384 s2 0.98886
00 dog-qnr-state-664-s9 LSTM512x3-384 p384 s3 0.98881
00 dog-qnr-state-664-s9 LSTM512x3-384 p384 -- 0.98810 -0.00069 0.00006
001
01 dog-ust-state-752-s9 LSTM512x3 p128 s0 0.99525
01 dog-ust-state-752-s9 LSTM512x3 p128 s1 0.99547
01 dog-ust-state-752-s9 LSTM512x3 p128 s2 0.99538
01 dog-ust-state-752-s9 LSTM512x3 p128 s3 0.99533
01 dog-ust-state-752-s9 LSTM512x3 p128 -- 0.99184 -0.00352 0.00008
... (其余模型数据省略,实际应完整包含) ...
36 egg-fsh-state-640-s9 LSTM512x3-ATT384 p384 s0 0.98654
36 egg-fsh-state-640-s9 LSTM512x3-ATT384 p384 s1 0.98662
36 egg-fsh-state-640-s9 LSTM512x3-ATT384 p384 s2 0.98664
36 egg-fsh-state-640-s9 LSTM512x3-ATT384 p384 s3 0.98666
36 egg-fsh-state-640-s9 LSTM512x3-ATT384 p384 -- 0.98595 -0.00066 0.00005
Total models present 37
模型组合
我使用了这些模型子集的线性组合。作为基线,我简单地使用scipy.optimization.minimize的Powell方法计算所有37个模型的最优权重。使用最小二乘法得分会差约20个基点,因为真实指标是平均角度误差。基线得分在批次601(用于权重计算)为.97948,在批次602(验证)为.97964,比最佳单模型提高了63个基点。
由于我不想在提交时计算所有37个模型,我选择了一个模型子集。不能简单地使用权重最高的模型来选择子集,因为模型是相关的。例如,如果模型A和模型B都是最好的且基本相同,它们的权重可能相近且都是最高的,但子集应只包含其中一个。
所以我采用迭代方法:每次移除一个模型,去掉对分数负面影响最小的那个。以下是结果(图像描述):
从图像可见:太多模型会导致交叉验证过拟合。我选择6个模型作为推理时间和最佳分数的折中方案。
经验教训
- 学习Transformer!
- 建立一个更好的框架来评估不同模型和参数,避免在更改东西时抓狂
- 当与领先者有较大差距时,少花时间寻找小调整,多关注主要问题
- 为了节省时间,添加新功能时进行更多模型微调,而不是从头训练
对我无效的方法
- 无法使vonMises-Fisher损失函数正常工作
- 添加额外特征,如邻居数量、传感器类型、线拟合估计方向
- Dropout或权重衰减。我的模型通常不会过拟合,可能因为它们不够复杂
- 脉冲选择。我始终无法改进随机选择,这仍然让我困惑
- 更复杂的集成。我看到@dipamc77在这方面做得很好,但我无法让XGBOOST或神经网络组合预测甚至嵌入得到比加权平均更好的结果
结论
祝贺所有顶级完成者!衷心感谢所有发布信息帮助大家的人,感谢所有人的参与,也感谢竞赛组织者举办了如此精彩的比赛。