361. TensorFlow 2.0 Question Answering | tensorflow2-question-answering
感谢 Kaggle 和 Kaggle 社区举办了这场精彩的比赛。我学到了很多东西。在最后一周,我们尝试了很多 PyTorch 的新东西,虽然没能成功运行起来,但过程非常有趣。
我们目前的方案是基于 @yihdarshieh 的这个优秀内核 https://www.kaggle.com/yihdarshieh/inference-use-hugging-face-models 构建的 TF 2.0 解决方案。起初,我尝试对官方的 BERT joint 基线进行微调,但效果提升不明显。在接下来的几周里,我完成了比赛的 TPU 环境搭建,并准备好了在开发集上进行训练和验证的流程。
所有的实验都是在 Google Colab 的免费 TPU 上进行的。这是我第一次认真使用 TPU,不得不说,感觉太棒了。因为它们非常快。使用 TPU 大大缩短了我的实验时间。
我们的方案是以下 2 个模型的简单融合:
这是我们的融合代码,我们使用了简单的加权平均融合。
nq_logits = bert_nq(nq_inputs, training=False)
base_nq_logits = base_bert_nq(nq_inputs, training=False)
(start_pos_logits, end_pos_logits, answer_type_logits) = nq_logits
(base_start_pos_logits, base_end_pos_logits, baseanswer_type_logits) = base_nq_logits
start_pos_logits = (0.2 * start_pos_logits + 0.8 * base_start_pos_logits)
end_pos_logits = (0.2 * end_pos_logits + 0.8 * base_end_pos_logits)
answer_type_logits = (0.2 * answer_type_logits + 0.8 * baseanswer_type_logits)
在尝试了多个单一模型后,我开始专注于后处理以提高模型性能。最初,我使用了 @prvi 的这个优秀内核 https://www.kaggle.com/prokaj/bert-joint-baseline-notebook 提供的后处理方法,这帮助我的单一模型得分达到了 0.56-0.58 的范围。为了进一步提高,我深入研究了模型的预测和真实值。在这里我发现我们的模型预测了重复的答案跨度。因此,我在后处理中添加了去重逻辑,这帮助公开 LB 分数提高了 0.01,开发集提高了 0.02。我还观察到,如果我的模型不预测任何“YES/NO”答案,分数会有所提高,因此在我的最终方案中,我的模型实际上只输出了答案跨度和空答案。
确定阈值是预测有效答案的重要事项之一,但我没有过多地调整答案阈值。最初,我在验证集上使用 5 个不同的答案阈值 [1.5, 3.0, 4.5, 6.0, 7.5] 运行推理,发现长答案为 1.5 和短答案为 3.0 的组合验证分数最高,我在最终方案中保持了这个设置。
来自 @prvi 内核的后处理只查看当前的 512 序列来选择开始和结束索引,但由于我们使用长度为 128 的步幅,每 2 个连续序列之间存在重叠。所以我决定从每 2 个连续序列中追加前 k 个开始和结束索引来选择一对开始和结束索引。在这种情况下,对于重叠的开始和结束索引,我得到了 4 个可能的分数值,其中我只保留最大分数值并丢弃其余 3 个。这种后处理并没有提升我们当前最佳模型在公开 LB 上的表现,但对于一个较弱的模型,它帮助提升了 0.17。