第5名方案:一千个Epoch与疯狂的Transformer
第5名方案:一千个Epoch与疯狂的Transformer
作者: NikhilMishra (Grandmaster), maverick (Master)
比赛: Ventilator Pressure Prediction
排名: 第5名
首先恭喜在本次比赛中取得优异成绩的各位。现在请读完本文不要逃跑:
我们的解决方案中没有任何魔法 😂
@sahil711 和我在最后一周为此疯狂工作,希望大家喜欢,如有疑问请随时提出。
让我们深入了解我们解决方案的关键特性:
- 序列长度为40而不是80:
我们不明白为什么大家不尝试这一点(或者可能尝试过但我们错过了 :))。在 u_out==0 的 breath_id 中,最大序列长度为35,因此我们可以轻松地将序列长度减半。这帮助我们在最后一周节省了大量时间,可以进行更快的实验并获得更快的结果。使用完整序列长度或减半后的序列长度在交叉验证分数上没有区别。事后看来,也许具有完整序列长度的模型可以为我们最终的解决方案增加一定程度的多样性。
- 分类任务而非回归任务:
@cdeotte 的回归公共Transformer非常简单且出色,但尽管如此,回归Transformer对我们不起作用。
实际上,我们在各种架构中都尝试过回归,但效果不佳。在我们的实验中,分类效果要好得多,所以我们坚持使用它直到最后。
- 损失函数:我们尝试了很多损失函数,例如:
- 交叉熵 (CE)
- 平滑 CE (Smoothened CE) (链接)
- 有序 CE (Ordinal CE,这里也尝试了平滑 :p)
- Focal Loss
但最终 CE 效果最好。老实说,我们本可以对损失函数进行更多实验,但由于时间限制,我们只是朝着看起来更有希望的方向前进。
- 可学习的前端:
我们最初的直觉是,类似于过去的几次音频比赛,这里的一维CNN也将发挥重要作用。因此,我们尝试了多种基于一维CNN的前端,但无法击败手工特征的性能。
因此,我们将两者结合起来,即我们既使用了手工特征,也连接了在数值特征之上应用的一维CNN层的输出。
前端架构很简单:

- 具有重度Dropout的高度参数化深度Transformer:
最初我们从一个简单的Transformer(2层深,嵌入尺寸32)开始。但即使在训练损失上,它也无法匹配LSTM的性能,因此我们开始对模型进行过度参数化,首先增加嵌入尺寸和头的数量。这帮助很大,使训练和验证损失都下降了。下一步是通过增加编码器层数来增加深度,此时模型开始过拟合,为了解决这个问题,我们引入了轻微的dropout,这有助于改善验证损失。那时我们不知道,我们会一直调整编码器层数和dropout直到比赛结束。我们的最终模型有20个编码器层,128个头,注意力层和全连接层的dropout均为0.8。我发誓,如果比赛再持续两周,我们可能会把dropout调到接近1 😂
这种过度参数化(特别是具有大量头)加上重度Dropout,我们认为是我们顶级高性能模型的最大关键。
另一个帮助我们训练Transformer的好主意来自论文 ReZero。
与其直接将上一层的输出添加到当前输出,您可以引入一个额外的参数alpha来权衡当前层的输出。这有助于网络决定要保留多少当前信息,至少我们在直觉上是这么理解的。根据论文和我们的结果,这随着深度的增加改善了收敛性。
PS:尽管复制了相同的架构,我们无法使用PyTorch获得相同的性能
- “想要成为”的Conformer:
我们想用Transformer尝试一些不同的东西。最初的想法是使用Conformer,但我们无法获得像使用简单的Transformer编码器层那样的性能水平。所以,我们懒惰地在Transformer编码器层旁边应用了一些卷积,结果非常好。通常我们将最后一个编码器层的输出馈送到下一个,即:
Input_Encoder(N) = Output_Encoder(N-1)
相反,我们做了:
Input_Encoder(N) = Concat([Output_Encoder(N-1), 1D_Conv(Ouputut_Encoder(N-1)]).
仅此操作就使我们的CV直接提升了0.01。
- 多头输出:
这个想法受到 <a href="https://www.kaggle.com/hengck23" target="_blank