返回列表

1st Place Solution

463. chaii - Hindi and Tamil Question Answering | chaii-hindi-and-tamil-question-answering

开始: 2021-08-11 结束: 2021-11-15 自然语言处理 数据算法赛
第一名解决方案

第一名解决方案

作者:Darek Kłeczek
发布时间:2021-11-16

感谢 Kaggle 和主办方举办这场比赛!感谢我在论坛和讨论区交流过的每一位社区成员,我从你们那里学到了很多。

交叉验证设置

在我写这篇总结时,我只知道我的公共排行榜排名,所以这一段可能会变得有些“苦涩”。在这次比赛中,我决定完全信任公共排行榜,甚至没有跟踪本地 CV(交叉验证)。训练数据集很小且被证实存在噪声,而公共排行榜数据量更大,包含 3 路标注,这意味着质量更高。我预计公共排行榜和私人排行榜之间的相关性,要比我的本地 CV 和私人排行榜之间的相关性更高。

架构

我所有的模型都是标准的问答模型(AutoModelForQuestionAnswering),后处理直接复用了 Sylvain Gugger 的 HF 示例笔记本中的代码,我在公开的 EDA 中也使用了该代码。我使用了 XLM-Roberta Large、MURIL Large 和 Rembert,并混合了每个骨干网络中几个模型的预测结果。在下一阶段,我在 3 个骨干网络之间使用了词级别的多数投票,来决定哪些词会进入最终预测。

为了增加多样性,我提交了另一个不混合单一模型的集成,只进行多数投票。它在公共排行榜上的分数较差,但在私人排行榜上是一样的——我选定的两个提交在私人排行榜上都是 0.787。我最好的私人提交是 0.796。我还有一个单模型/折(MURIL),在公共排行榜上得分 0.802,在私人排行榜上得分 0.783。

数据配方

像大多数其他参赛者一样,我开始比赛时使用的是 Deepset 在英文 SQUAD 上预训练并在 chaii 数据上微调的 XLM-Roberta Large。后来,我开始预训练我自己的骨干模型(我指的是 QA 预训练,而不是 MLM)。我专注于 TyDi 数据集,因为主办方提到 chaii 数据的收集方式与之类似。我进行了几次不同的预训练和微调协议实验,关键的发现是预训练骨干模型的性能往往超过其微调版本。基于这一观察,我决定放弃两阶段方法,改为单阶段训练。然而,我想控制向模型提供不同数据集的顺序。我称之为数据配方,因为这感觉像是在烹饪。

这是我在最终实验中使用的一个数据配方示例:

  1. 选取 TyDi 数据集的英语、孟加拉语和泰卢固语子集,以及 2/3 的 chaii 训练数据集。使用序列长度 256 对其进行标记化,并移除 90% 的负样本(负采样)。加入标记化的英文 SQUAD 以及 MLQA 和 XQUAD 的印地语部分。将所有内容混合在一起并放在一边。
  2. 重复步骤 1,但用 Natural Questions 的子集替换英文 SQUAD。使用序列长度 384 进行标记化(渐进式调整大小,见下文)。
  3. 将步骤 1 和 2 中收集的数据连接起来。
  4. 开始训练。

更多细节:

  • 因为我将数据组合/打乱逻辑移到了数据集中,所以我使用了顺序采样器和 1 个 epoch 进行训练。HuggingFace 的 datasets 库让这一切变得超级简单。
  • 我对 TyDi、chaii 和 NQ 数据集使用了负采样(通常为 0.1),因为它们包含较长的上下文。
  • 我最初尝试了一些自动翻译的数据集,如泰米尔语 SQUAD,但它们对我的性能没有帮助,所以最后我只使用了原始语言数据集和人工翻译的数据集(印地语 MLQA/XQUAD)。
  • 我尝试了 TyDi 中的各种语言,发现英语/孟加拉语/泰卢固语效果最好。
  • 我想增加更多数据,所以我选取了包含短答案的 Google Natural Questions,并训练了一个简单的 Roberta-base 分类器来区分 NQ 数据和 TyDi 英语数据集。我选择了与英语 TyDi 最相似的 NQ 子集。
  • 由于我不跟踪 CV,我最初使用了所有 chaii 数据。后来,我转为 3 折设置——为了多样性和早停。如果中间检查点的 CV 比最终检查点好很多,我通常会在公共排行榜上测试它。

类图像增强

这部分深受 fastai 的启发——在一次深度学习课程中,@jhoward 谈到了他将预训练方法从计算机视觉迁移到 NLP(ULMFiT)的工作,并提到遵循这种方法还有许多其他机会。我专注于增强技术。

随机裁剪

这是 CV 中标准的增强手段,但我没见过它应用于 NLP,尽管它在这里非常合适:我们需要将很长的文本分块成固定标记长度的片段。与其每个 epoch 只做一次并展示相同的例子,为什么不把它变成动态的随机裁剪呢?最初,我实现了一个函数,对正样本取答案文本周围带有填充的随机裁剪,对负样本取随机裁剪。当我转向上述数据配方时,我意识到通过在每次将数据集添加到配方时使用不同的步长和负采样,可以更简单地实现同样的效果。

同比赛其他方案