第11名方案:嵌套Transformer
概览
我们将我们的网络架构称为“嵌套Transformer”,因为它包含两个层级的Transformer:
- 单元格Transformer(Cell transformer):一个用于编码单元格Token的Transformer编码器,这可以是一个典型的用于NLP的Transformer。
- 笔记本Transformer(Notebook transformer):一个具有单元格*单元格自注意力机制的Transformer编码器,用于学习单元格之间的交互。
源代码:https://github.com/ShinSiangChoong/kaggle_ai4code_nested_transformers
有效的方法
修改单元格Transformer的输入格式
- 输入采用以下格式:
<code><sep><source_tokens> 或 <mark><sep><source_tokens>
- 感谢 @cabbage972 验证了这个想法的有效性。
单元格特征
- 代码单元格的顺序是已知的,而Markdown单元格的顺序是未知的,因此笔记本Transformer中直接的位置嵌入方案无法正常工作。单元格特征旨在告知模型已知的代码单元格位置/顺序。
- 我们为每个单元格使用2个特征,即单元格类型(代码 -> 1,Markdown -> 0)和代码单元格中的百分位排名:如果单元格是Markdown单元格,此特征 = 0。
- 这2个特征通过全连接(FC)层进行“扩展”,使其表示为与单元格Token嵌入具有相同维度的嵌入向量。
- 然后将这些单元格特征嵌入与Token嵌入连接起来,一起传递到聚合注意力层。
聚合注意力
- 我们认为不同的Token(以及单元格特征)在表示单元格时具有不同的重要性。聚合注意力层用于学习每个Token嵌入(以及单元格特征嵌入)的权重。
- 权重通过Softmax层进行归一化,使得最终的单元格嵌入是其Token和特征嵌入的加权平均值。
- 感谢 @cabbage972 验证了这个想法的有效性。
双头架构
- 逐点头:输出每个单元格的百分位排名。应用L1损失。
- 成对头:对于每对单元格A和B,预测单元格B是否是单元格A的下一个单元格。应用交叉熵损失。
- 我们在推理时只使用逐点头,即单元格根据预测的百分位排名进行排序。
- 推理期间不使用成对头,然而,在我们的实验中,包含成对头有助于将验证分数提高约0.03。
代码顺序修正
- 由于我们的模型预测每个单元格(包括代码单元格)的百分位排名,因此可能会违反代码单元格的顺序(这是已知的)。
- 如果发生这种情况,我们根据给定的顺序交换代码单元格。
- 这个想法仅略微提高了分数。实际上,在给定单元格特征的情况下,模型能很好地学习代码顺序。
无效的方法
- 以贪婪的方式利用成对头预测,同时满足代码顺序约束,即通过选择预测得分最高的单元格来持续确定下一个单元格。
- 将成对头预测用作距离矩阵,然后使用LKH求解序列排序问题(带优先约束的TSP)。
- 端到端地一起训练2个单元格Transformer骨干网络,依靠聚合注意力来聚合来自2个骨干网络的Token嵌入。
补充说明
- 最终模型是4个不同单元格Transformer骨干网络的集成,即CodeBERT、Deberta-large