545. IceCube - Neutrinos in Deep Ice | icecube-neutrinos-in-deep-ice
首先,我要向主办方和Kaggle团队组织如此引人入胜的比赛表示衷心感谢。此外,我还想感谢那些通过发布笔记本和参与讨论分享宝贵见解的贡献者。
特别感谢以下非常有帮助的笔记本和讨论:
我的模型结构很简单,将EdgeConv和Transformer连接在一起。我旨在将EdgeConv和Transformer结合到模型中,以高效地收集信息。图神经网络(GNN)用于捕获局部邻域信息,而Transformer则用于收集全局上下文,从而确保对数据的全面理解。这个简单的模型作为单模型,在公开排行榜上的得分是0.9628,在私有排行榜上的得分是0.9633。
在原始论文中,每一层都会动态地计算边,但这种边选择是不可微的,因此无法训练。在原始论文的分割任务中,这仍然效果很好,因为同一分割中的点在潜在空间中被训练得很接近。然而,在这个任务中情况不同,所以我认为动态选择边没有意义。因此,在EdgeConv中使用的边选择在输入时计算。
使用EdgeConv时,dom_i的潜在参数\\({x}_i\\)利用差值\\({x}_j-{x}_i\\)进行更新,其中\\({x}_j\\)是dom_i的第k近邻dom_j的潜在参数。这对于x、y、z和时间来说没有问题,但对于电荷和辅助信息,绝对值是有意义的,所以我让\\({x}_i\\)不仅使用\\({x}_j-{x}_i\\),还使用\\({x}_j\\)来更新。
VMFLoss是一个很好的稳定损失函数,但θ是以余弦形式出现的:
VMFLoss = -κ*cos(θ) + C(κ)
# θ是真实值与预测值之间的夹角,κ是3D预测向量的长度
另一方面,本次比赛的指标是角度θ本身。为了最小化θ本身,我将损失函数定义如下:
MyLoss = -θ - κ*cos(θ) + C(κ)
与VMFLoss相比,这种简单的改进带来了0.005的显著提升。
在Transformer中,计算复杂度与序列长度的平方成正比,因此减少序列长度至关重要。因此,将序列长度相似的数据分组并创建小批量是有效的。这种方法加快了计算速度,并进一步减少了GPU内存使用,从而允许使用更大的小批量大小。
这可以通过修改DataLoader的collate_fn轻松实现:
def collate_fn(graphs, split_list=[0.8, 1.0]):
graphs = [g for g in graphs if g.n_pulses > 1]
graphs.sort(key=lambda x: x.n_pulses)
batch_list = []
for minp, maxp in zip([0]+split_list[:-1], split_list):
min_idx = int(minp*len(graphs))
max_idx = int(maxp*len(graphs))
this_graphs = graphs[min_idx:max_idx]
this_batch = Batch.from_data_list(this_graphs)
batch_list.append(this_batch)
return batch_list
注意:即使对batch_list中每个长度偏向的小批量单独计算梯度,也可以通过之后集体更新权重来减轻负面影响。
由于数据量巨大,难以将所有数据放入内存,我尝试每个时期加载一个批次。伪代码如下:
class IceCubeDataset(Dataset):
def reset_batch(self):
# 获取下一个批次ID
self.this_batch_id = self.get_next_batch_id()
# 读取下一个批次的数据
self.this_batch = pd.read_parquet(f"{BATCH_DIR}/batch_{self.this_batch_id}.parquet")
# 过滤元数据
self.this_meta = self.meta[self.meta.batch_id == self.this_batch_id]
def __len__(self) -> int:
return len(self.this_meta)
# 其他方法...
class IceCubeModel(Model):
def __init__(self, dataset, ...):
...
self._dataset = dataset
def training_epoch_end(self, outputs):
...
# 每个时期重置批次
self._dataset.reset_batch()
以下是用于堆叠的基模型的一些信息:4层结构,600万参数,似乎比其他顶级解决方案更小。
由于使用了6000个序列,推理时间相对较慢。
堆叠的框架主要基于原始基模型。主要区别在于模型被替换为一个3层MLP。通过堆叠,取得了+0.003的提升。
推理笔记本可在 这里 获取。