一台对话问答机的解剖 — 四个部件
这一章讲三件事: CMRC 模型的部件图;每个部件上各家试过哪些路数、各死于什么;综述读出的三条规律。 读完你就有了全套词汇——第 06–08 章的三个自研模型,都是往这台机器的某个部件里插新设计。
1. 全景图:一条流水线,四个部件
一台对话式问答机(CMRC 模型)的完整流水线是这样的1:
对话历史 H(此前所有问答对)
│
▼
① 历史选择模块 从 H 里挑出相关的 H′(丢掉无关轮)
│
▼
② 编码器(+历史建模) 把 H′、文章 C、当前问题 Q 变成向量;
│ 「历史建模」=决定用输入格式上的什么花招
│ 把历史塞进这串向量里
▼
③ 推理模块 在向量上做上下文融合,推出「答案在哪」
│
▼
④ 输出预测器 给出答案 A(一段原文/自由文本/动作标记)
图说:①② 是 ConvQA 比单轮 MRC 多出来的部分,③④ 与单轮机共享。
第 06 章的新设计插在①,第 07 章贯穿①②,第 08 章重构①并在前面再加一级检索。
原书把这套部件图归功于 Qu 等人 2019 年的工作:在一次一问的 MRC 的「编码—推理—解码」之上,新增历史选择与历史建模两个模块,从此任务有了 CMRC 这个名字2。正式定义再念一遍:给定文章、一串历史问答对、当前问题,预测当前答案;答案可以是文中一段原文(span),也可以是带证据的自由文本3。
下面逐个部件拆。
2. 部件一:历史怎么选
这一节的问题:512 个位置很贵(第 03 章),历史该挑哪些进 去?
先把动机钉死:相关轮次有用,无关轮次是噪声,会拉低模型表现——所以「谨慎挑选」很关键4。三大路数:
路数一:固定选 K 轮。 不管三七二十一,取最近 K 轮拼进去。SDNet、BiDAF++、ORConvQA 等一批模型都这么干5。简单,但对话题转移无能为力——上一章的 Malayali 对话里,该带的可能是隔了好几轮的 Q1。
路数二:选「紧挨着」的几轮。 有实验发现紧邻两轮就很有用(BERT 2-ctx);另一个模型 BERT-HAE 说要五到六轮才够。但两个模型都观察到同一件事:轮数继续加,性能急剧下滑6——512 墙加上噪声,两头夹击。
路数三:动态选择。 原书引 Yatskar 的观察:话题回归、话题转移这些对话现象,和「选紧邻的轮次」根本对不上7——回归要的是老早之前的轮,转移面前紧邻轮恰是噪声。于是出现了两个方向:
- 按贡献打分(HAM):给每轮按「对答当前题的贡献」赋权,在词级或句级上做注意力,再与当前轮的表示合并——这是软选择的雏形:不丢轮,只是让重要的轮占比大8;
- 当决策问题做(Env-ConvQA):把「挑历史」当成一个逐步决策过程,模型从最近的轮开始一轮轮回溯,逐个判断「这轮相关吗」,不相关就丢——用强化学习(答对了给分,拿分数教策略)的奖励信号训练这个回溯策略9。
硬选择(丢掉无关轮次)与软选择(加权)这对概念请记住:第 07 章的自研模型就是把两者组合起来。
3. 部件二:选出的历史怎么塞进输入
这一节的问题:选好了轮次,用什么格式写进输入串?
原书把「历史建模」单列为一个模块讲,同时明说:它实际发生在编码器里,单独列出只是为了讲得清楚10。三种花招:
花招一:直接拼。 最常见——把选出的问答对拼在当前问题前面。细分还有「拼完整问答对」和「只拼问题、另编码轮次编号」两种;BiDAF++ 的作者报告过,把轮次编号放进输入实测更好11。朴素,但吃 512 预算。
花招二:在文章里做标记(HAE)。 给文章的每个词额外加一个标记位:这个词是不是上一轮答案的一部分。好处是给模型一个指针——「上轮答案就在这附近,当前问题多半和它有关」12。后继版 POS-HAE 再进一步,把「那轮答案离当前问题隔几轮」的位置信息也编进去13。
花招三:不塞原文,塞中间结果。 让模型把对话的「流动」压缩成一串隐表示(向量状态),后续轮次处理时读这份状态而不是原始文本——这一类叫流式方法,下一节还会遇到14。
4. 部件三:推理的四代
这一节按技术代际过一遍推理模块。模型名不必背,要记的是每代解决了什么。
先交代推理模块本身在干什么:把编码后的向量融合若干层,产出「历史感知」的表示——单步推理过一层就出答案,多步推理融合多层15。按技术代际分四代: