想象一下,一家新公司刚入职了四名员工:小猫、喜欢、吃、鱼。HR 今天最头疼的任务是:确定每个人的直属上司,画出一张全员汇报关系图——谁是 CEO?谁向谁汇报?谁管着谁?对自然语言处理来说,每个句子就像一个迷你公司,每个词是一名员工,而“句法分析”就是帮这个“句子公司”画出组织架构图。 2017 年,Dozat 和 Manning 提出了 Deep Biaffine Attention 模型,相当于给 NLP 界打造了一套超级智能的 HR 系统:它给每个词发两张“名牌”——一张当老板用的、一张当下属用的,然后通过一个叫“双仿射”的配对打分器,计算任意两个人搭班的和谐度,最后选出最合理的上下级关系,形成一棵结构清晰的“组织树”。这套模型至今仍是依存句法分析领域的经典基线与教科书级架构。这篇文章,我们就用“给每个词找老板”的故事,把 Deep Biaffine 的任务、原理、架构、训练和应用一次讲透。
掌握 Deep Biaffine,你就在 NLP 句法分析领域拿到了“经典驾驶执照”——复现论文、搭建信息抽取管线、面试谈架构设计时,都能直接加分。
可视化演示
展示Dozat & Manning 2017提出的Deep Biaffine Attention依存句法分析模型:四层架构(输入→BiLSTM→投影→Biaffine)、弧评分矩阵计算、以及依存句法树构建。
本节配有交互动效(进入视口后自动加载,约 3KB)。
'+captions.arch+'
任务定义
HR 面前是一团乱麻:小猫、喜欢、吃、鱼四个人都互相认识,但没人说得清谁该向谁汇报。HR 的任务很明确——画一张图:图上每个员工只能有一个箭头指向自己的直属老板,全公司只能有一个人头顶上没有箭头,那就是 CEO。这张图,就是句法分析领域说的“依存树”:节点是词,有向弧是“谁支配谁”。
从技术上讲,给出一句词序列 $w_1, w_2, \dots, w_n$,依存句法分析要输出三样东西:哪些词对之间需要连一条有向弧、弧的指向(谁是“头”谁是“依存”)、以及弧上贴着什么关系标签。所有弧合在一起,必须构成一棵以唯一根节点为顶点的树——因为一个员工不能同时向两个老板汇报,也不能让整个公司出现“你管我、我管你”的循环。
为了保证这一点,模型在数学上强制了两条约束:每个非根词恰好有一个“老板”(单一父节点),整个图连通且无环。实际系统中,人们还会给句子加一个“虚拟根”节点,让真正的核心动词都指向它,这样树就有了统一的顶点,打分矩阵也更好构造。
所以 Deep Biaffine 模型干的事情,说白了就是“组织架构图自动生成”。HR 先给每个员工准备好名牌,再用一套打分系统决定谁是谁的老板——下面我们就去看看,这套系统中的“岗位惯例”和“打分规则”分别是什么。
- 句子词集合 V$V = \{w_1, w_2, \dots, w_n\}$ 表示把句子拆成 n 个词组成的集合,每个词就是公司里的一名“员工”。
- 入度 deg⁻$\deg^{-}(i)$ 统计指向词 i 的弧的数量,也就是这个员工头上顶着的“老板人数”。
- 单一父节点约束$\forall\, i \neq r:\ \deg^{-}(i) = 1$ 表示除了根以外,每个词恰好有一个老板,不能多也不能少。
- 唯一根节点$\deg^{-}(r) = 0$ 表示恰好存在一个“无人领导”的 CEO;配合“连通无环”,整张图就是一棵标准组织树。
依存语法基础
光画出汇报关系还不够,HR 还得在每条弧上贴一个“岗位标签”:这是直线汇报(部门主管),还是项目虚线汇报(横向协作)?语言学家早就为句子里的上下级关系写好了一本“岗位手册”,这便是依存语法。
手册的第一条铁律叫“动词中心”:一个句子的骨架通常由核心谓词(谓语动词)搭起来。比如“小猫喜欢吃鱼”里,“喜欢”是总经理、“吃”是部门经理,名词、副词、形容词都挂在它们周围。句法树的根节点,绝大多数情况下就是那个核心动词——所以模型其实有个隐含预期:CEO 该由句子里的骨干动词来当。
手册的第二条是“关系类型”:弧上需要标注具体是哪种上下级关系。常见的有 nsubj(主语关系,如“小猫”之于“喜欢”)、obj(宾语关系,如“鱼”之于“吃”)、det(限定关系,“这条鱼”的“这”)、advmod(状语关系,“开心地吃”的“开心地”)等等。每条弧带着标签,组织架构图的信息量立刻翻倍。
手册里还有一条温柔的规律叫“投影性”:正常情况下,把弧画在词上方时它们不会互相交叉——就像大公司的管理线总是层级分明、很少出现“隔层乱报”的混乱局面。这为后面的解码算法提供了很好的先验。
有了这本岗位手册,HR 给每条弧贴职称时就有了标准答案。但真正难的是:面对一个全新的句子,怎么自动算出“谁该向谁汇报”?这就要靠下面这套神经网络流水线了。
- 根标记$\mathrm{root}(\text{喜欢})$ 表示“喜欢”是整棵树的根节点,对应公司里那个没有老板的 CEO。
- 主谓关系$\mathrm{nsubj}(\text{小猫} \to \text{喜欢})$ 表示“小猫”以主语身份挂在“喜欢”下面,是它的直接下属,弧上贴着“主谓”标签。
- 动宾关系$\mathrm{obj}(\text{鱼} \to \text{吃})$ 表示“鱼”是“吃”的宾语——“鱼”是“吃”管着的对象,标签为“动宾”。
模型架构
新句子入职,HR 的流程分三段:前台登记信息(词嵌入),秘书通读全公司档案(BiLSTM),主管给每个人发两种角色的名牌(双 MLP)。三段各司其职,共同完成“看懂句子、分饰两角”的准备工作。
第一段是词嵌入。每个词 $w_t$ 被映射成一个稠密向量 $\mathbf{x}_t$。Dozat 和 Manning 的原始实现里,输入通常由三部分拼接而成:随机初始化的词向量、词性标注(POS)向量、以及预训练好的词向量——相当于前台上传了员工的三份材料:姓名、职位、历史履历。
第二段是 BiLSTM 编码。双向 LSTM 先从左往右读一遍句子,再从右往左读一遍,然后把两个方向的隐状态拼起来,得到每个位置 $t$ 的上下文表示 $\mathbf{h}_t$。这一步让每个词“见过全公司所有人”——“小猫”知道自己是主语还是宾语,不再只是孤立的名字。
第三段是双 MLP 角色分派。对同一个 $\mathbf{h}_i$,用两套独立的多层感知机各压一次:$\mathrm{MLP}_{\mathrm{head}}$ 产出“老板牌”表示,$\mathrm{MLP}_{\mathrm{dep}}$ 产出“下属牌”表示。这两个 MLP 还会把向量维度从几百维压缩到一百维左右,既减少参数,又强迫表示只聚焦“这个人适不适合当老板/当下属”这一件事。
到这一步,HR 手上已经有了全体员工的两份档案:一份考察他当老板的资质,一份考察他当下属的适配度。接下来的核心问题就是:怎么用这两份档案,给任意一对“下属 × 老板”打出和谐度分数?答案就是本篇文章的主角——Biaffine 打分器。
- BiLSTM 编码$\mathbf{h}_t = \mathrm{BiLSTM}(\mathbf{x}_1, \dots, \mathbf{x}_n)_t$ 表示把第 t 个词放进双向循环网络,输出一个同时看过左右邻居的上下文向量。
- 老板视角$\mathbf{r}_i^{\mathrm{head}} = \mathrm{MLP}_{\mathrm{head}}(\mathbf{h}_i)$ 用一套参数把 $\mathbf{h}_i$ 压成低维向量,得到“当老板的简历”。
- 下属视角$\mathbf{r}_i^{\mathrm{dep}} = \mathrm{MLP}_{\mathrm{dep}}(\mathbf{h}_i)$ 用另一套参数得到“当下属的简历”,两套参数互不共享。
- 维度压缩两个 MLP 的输出维度远小于 $\mathbf{h}_i$ 的维度,迫使表示丢掉无关细节、聚焦“角色适配度”。
Biaffine核心
HR 手里有一本厚厚的“双向偏好辞典” $\mathbf{W}$。辞典里记录着规则:老板牌的某个特质和下属牌的某个特质搭配在一起,该给多少分。打分时,把下属牌向量和老板牌向量送进辞典翻查,翻出来的数值就是这对组合的和谐度——这就是“双仿射”这个名字的来历:先把向量做一次线性变换(仿射),再做一次两两交叉(双线性),合称“双仿射”。
为什么不能像普通注意力那样直接做点积?因为点积只允许“老板牌的第 k 个维度”和“下属牌的第 k 个维度”自己跟自己比,太死板。Biaffine 用矩阵 $\mathbf{W}$ 做中介,允许“下属牌的第 k 个维度”与“老板牌的第 l 个维度”任意两两交互——这正是判断“两个人性格合不合”最需要的建模能力。
还有一个优雅的小技巧:把每个向量末尾拼接一个常数 1,也就是 $[\mathbf{r}; 1]$。这样一来,原本需要单独写的偏置项就被悄悄吸收进 $\mathbf{W}$ 的最后一列和最后一行里,公式变得极其简洁。展开后它其实包含三部分:双线性交叉项 $a^{\top}\mathbf{W}_1 b$、只依赖下属的线性项、只依赖老板的线性项,以及全局偏置。
把所有“下属 i × 候选老板 j”的组合都算一遍,就得到一张 $n \times n$ 的得分矩阵。每一行取最大值,就圈定了每个员工独一无二的老板。但打分器不是天生就会打分的——它需要经过严格培训,这就是下一节“训练与解码”要讲的事。
- 下属牌向量$\mathbf{r}_i^{\mathrm{dep}}$ 是词 i 的“当下属”表示,也就是配对中的一方。
- 老板牌向量$\mathbf{r}_j^{\mathrm{head}}$ 是词 j 的“当老板”表示,也就是配对的另一方。
- 拼接常数 1$[\,\cdot\,; 1]$ 把向量维度加 1 并固定填 1,这样偏置项就被吸收进 W,无需单独声明。
- 双仿射矩阵$\mathbf{W}$ 是维度为 $(d+1)\times(d+1)$ 的“双向偏好辞典”,储存所有角色特征两两组合的权重。
- 整体二次型$(a)^{\top}\mathbf{W}\, b$ 展开后等于 $a^{\top} W_1 b + u^{\top}a + v^{\top}b + c$——双线性交叉、单方偏好、全局偏置一次算清。
训练与解码
HR 系统上岗前要培训:拿一堆历史公司“已经验证过的正确组织架构图”当标准答案,反复练习“把正确答案排到第一名”。每次练习,就是让打分器对每个词的所有候选老板做一个 softmax 分类,然后要求真实老板对应的概率尽量接近 1——这个目标,正是交叉熵损失。
公式里,$y_i$ 是词 i 的真实老板编号(标准答案),$s_{i,j}$ 是上一节算出的 Biaffine 分数。模型把第 i 行的分数压成概率分布,再用负对数似然让“真实老板”成为高概率事件。对句子里的每个非根词都这么做,然后把所有词的损失加起来,就是整句的损失。
推理时没有标准答案,模型采用贪心解码:对每个词,直接选分数最高的那个位置当老板。这里有个细节值得注意:贪心选出来的结果可能违反树结构——比如 A 认为 B 是老板,B 又认为 A 是老板,两人都不向根汇报,形成“管理循环”。为了保证永远输出合法组织树,可以改用最大生成树(MST)解码,在整张得分图上选一棵全局最优的树。Dozat 和 Manning 在论文中证明了一个有趣的结论:加上合适的训练约束后,贪心解码在多数语言上已经足够好,MST 带来的提升很小。
培训让打分器越来越精准,解码规则又保证了输出永远是合法组织架构图。那怎么衡量 HR 画得准不准呢?答案就是下一节要讲的准确率指标——UAS 和 LAS。
- 真实头索引$y_i$ 表示训练语料中词 i 的标准答案老板编号,相当于 HR 培训教材里的正确答案。
- softmax 归一化$\frac{\exp(s_{i,y_i})}{\sum_{j}\exp(s_{i,j})}$ 把第 i 行分数压成概率分布,表示每个候选老板“当选”的可能性。
- 负对数似然$-\log(\cdot)$ 让真实老板概率越接近 1,损失越接近 0——这就是 HR 的“奖励正确、惩罚错误”机制。
- 全句求和$\sum_{i=1}^{n}$ 把所有词的损失加起来,形成整句的训练信号,驱动梯度下降更新打分矩阵 W。
应用价值
组织架构图画好之后,下游部门就可以放心使用了:法务部拿它抽取人脉关系(信息抽取),翻译部拿它调整语序(机器翻译),人事部拿它判断谁承担什么职能(语义角色标注)。一张清晰的汇报关系图,让整个 NLP 流水线少走很多弯路。
在信息抽取场景中,依存树直接给出主谓宾骨架:从“小猫喜欢吃鱼”可以稳定抽取出“喜欢”的主语是“小猫”、宾语是“吃鱼”这样的三元组,支撑知识图谱构建和事件抽取。传统正则表达式面对千变万化的句式极易漏抽,而依存句法分析天然具备泛化能力。
在机器翻译与语义理解场景中,句子内部的修饰关系、否定关系、程度副词都藏在依存弧里。翻译长定语从句时,可以依据依存树整体搬移子树来调整语序;语义角色标注则以动词为根,给每个论元贴上“施事”“受事”等角色。近年来还有一些工作把句法信息注入预训练模型,进一步增强模型的泛化能力。评估这套 HR 系统的“画图准度”,最常用的指标就是 UAS:
回到公司的比喻:Deep Biaffine 之所以经典,是因为它把“谁向谁汇报”这件看似琐碎的事,变成了一套高效、可训练、可评估的流水线。无论下游是知识图谱、机器翻译还是智能客服,这张组织架构图都能作为地基,让上层建筑盖得又快又稳。
- 指示函数$\mathbb{1}[\cdot]$ 在括号内条件成立时取 1、否则取 0,相当于一句“对不对”的计数器。
- 预测头与真实头$\hat{y}_k$ 是模型预测的第 k 个词的老板,$y_k$ 是标注里的真实老板。
- 平均正确率对全部 N 个待预测的词取平均,得到 UAS;若还要求弧标签正确,则记作 LAS。
AI 应用场景
金融舆情事件抽取
阶段:数据预处理与信息抽取
解决的问题:传统做法靠人工写正则抽取“谁收购了谁”的事件,句式一变就漏抽,扩展性极差。用 Deep Biaffine 先做依存句法分析,再沿 nsubj/obj 弧抽取主谓宾三元组,可以快速搭建通用的事件抽取管线。
具体案例:某券商 NLP 团队需要对 10 万篇公告做并购事件抽取。句子“甲公司收购了乙公司 30% 股权”经过依存分析后,得到“甲--nsubj-->收购”和“乙--obj-->收购”两条关键弧,直接产出结构化三元组(收购,收购方=甲,被收购方=乙),准确率远超规则模板。
机器翻译中的语序调整
阶段:特征工程与解码优化
解决的问题:中文和英文的语序差异大,长定语、嵌套状语让序列到序列模型顾此失彼。借助依存树标记核心动词与修饰成分之间的关系,解码时按树结构整体搬移子树,显著减少“逐词硬译”造成的语序混乱。
具体案例:翻译“昨天在公园里开心地唱歌的小女孩”这类长定语从句时,先用依存树理清“唱歌”是核心、其余成分都是它的修饰节点,再按树结构重排为英文语序,翻译流畅度明显提升。
智能客服的语义角色理解
阶段:意图识别与参数抽取
解决的问题:客服问题中常见的否定、程度、对象等语义信息常以修饰和宾语关系出现,平面分类容易误判。依存树帮对话系统定位“动词+宾语+状语”结构,避免把“不要退款”误解为“要退款”。
具体案例:用户输入“我想申请延迟发货”,依存分析得到“申请”支配“发货”,且“发货”被“延迟”修饰,系统据此正确抽取意图为“修改发货时间”,参数为“延迟”,而不是直接触发退款流程。
Python 演示
import numpy as np class BiaffineParser: """极简 Deep Biaffine 依存句法分析器(玩具版)""" def __init__(self, vocab, dim=8): self.vocab = vocab self.dim = dim self.emb = {} for w in vocab: self.emb[w] = np.random.randn(dim) * 0.1 self.W_bia = np.random.randn(dim + 1, dim + 1) * 0.1 self.W_head = np.random.randn(dim, dim) * 0.1 self.W_dep = np.random.randn(dim, dim) * 0.1 def _encode(self, words): # 简化版 BiLSTM: 前向平均 + 后向平均拼接 x = np.array([self.emb[w] for w in words]) h = [] for t in range(len(words)): left = x[:t + 1].mean(axis=0) right = x[t:].mean(axis=0) h.append(np.concatenate([left, right])) return np.array(h) def score_matrix(self, words): h = self._encode(words) n = len(words) r_head = np.hstack([np.tanh(h @ self.W_head), np.ones((n, 1))]) r_dep = np.hstack([np.tanh(h @ self.W_dep), np.ones((n, 1))]) return r_dep @ self.W_bia @ r_head.T def nll_loss(self, words, heads): S = self.score_matrix(words) loss = 0.0 for i in range(len(words)): if heads[i] < 0: continue row = S[i] - S[i].max() p = np.exp(row) loss += -row[heads[i]] + np.log(p.sum()) return loss / len(words) def train(self, corpus, steps=800, lr=0.03): for _ in range(steps): words, heads = corpus[np.random.randint(len(corpus))] n = len(words) h = self._encode(words) z_head = h @ self.W_head z_dep = h @ self.W_dep r_head = np.hstack([np.tanh(z_head), np.ones((n, 1))]) r_dep = np.hstack([np.tanh(z_dep), np.ones((n, 1))]) S = r_dep @ self.W_bia @ r_head.T dW = np.zeros_like(self.W_bia) dH = np.zeros_like(self.W_head) dD = np.zeros_like(self.W_dep) for i in range(n): if heads[i] < 0: continue row = S[i] - S[i].max() p = np.exp(row) / np.exp(row).sum() g = p.copy() g[heads[i]] -= 1 for j in range(n): dW += g[j] * np.outer(r_dep[i], r_head[j]) grad_rh = self.W_bia.T @ r_dep[i] dH += g[j] * np.outer(h[j], grad_rh[:self.dim] * (1 - np.tanh(z_head[j]) ** 2)) grad_rd = self.W_bia @ r_head[j] dD += g[j] * np.outer(h[i], grad_rd[:self.dim] * (1 - np.tanh(z_dep[i]) ** 2)) self.W_bia -= lr * dW / n self.W_head -= lr * dH / n self.W_dep -= lr * dD / n def predict(self, words, root_idx): S = self.score_matrix(words) heads = [] for i in range(len(words)): if i == root_idx: heads.append(-1) continue row = S[i].copy() row[i] = -1e9 heads.append(int(np.argmax(row))) return heads def main(): vocab = ["小猫", "喜欢", "吃", "鱼", "我", "猫"] parser = BiaffineParser(vocab) corpus = [ (["小猫", "喜欢", "吃", "鱼"], [1, -1, 1, 2]), (["我", "喜欢", "猫"], [1, -1, 0]), (["小猫", "吃", "鱼"], [1, -1, 1]), ] sent = ["小猫", "喜欢", "吃", "鱼"] print("训练前损失:", round(parser.nll_loss(sent, [1, -1, 1, 2]), 4)) print("训练前预测:", parser.predict(sent, 1), "期望 [1, -1, 1, 2]") parser.train(corpus, steps=800) print("训练后损失:", round(parser.nll_loss(sent, [1, -1, 1, 2]), 4)) print("训练后预测:", parser.predict(sent, 1), "期望 [1, -1, 1, 2]") if __name__ == "__main__": main()
self.W_bia = np.random.randn(dim + 1, dim + 1) * 0.1打分矩阵 W 比向量维度多一行一列,专门用来吸收偏置项。r_head = np.hstack([np.tanh(h @ self.W_head), np.ones((n, 1))])用一套 MLP 得到“老板牌”向量,末尾拼 1 留出偏置通道。r_dep = np.hstack([np.tanh(h @ self.W_dep), np.ones((n, 1))])用另一套 MLP 得到“下属牌”向量,两套参数互不共享。return r_dep @ self.W_bia @ r_head.T一次矩阵乘法算出所有 (下属 i, 老板 j) 组合的 Biaffine 分数。row = S[i] - S[i].max()减最大值再取 exp,是 softmax 的数值稳定技巧,防止指数溢出。g = p.copy(); g[heads[i]] -= 1交叉熵对 logits 的梯度恰好是“预测概率减真实 one-hot”,是本次更新的核心信号。dW += g[j] * np.outer(r_dep[i], r_head[j])把每个候选老板的梯度累加到打分矩阵 W 上,等价于“答错了就调整偏好辞典”。heads.append(int(np.argmax(row)))贪心解码:每个词直接选分数最高的位置当老板。parser.train(corpus, steps=800)在迷你语料上训练 800 步,观察损失下降与预测逼近真实头节点。
常见误区
误区我一开始以为 Biaffine 就是把两个向量做点积再加一个 bias,跟普通 attention 没多大区别。
正解Biaffine 的关键在“双线性交叉项”:$(\mathbf{r}^{\mathrm{dep}})^{\top} \mathbf{W}\, \mathbf{r}^{\mathrm{head}}$。这里的 W 是一个矩阵而不是一个标量,它允许“下属牌的第 k 个维度”和“老板牌的第 l 个维度”两两交互,这才是“配对兼容度”的数学化表达;线性项和偏置只是锦上添花。没有矩阵交叉项,模型就无法建模“下属的 A 特质 × 老板的 B 特质”这种组合效应。
为何常见:因为它确实属于注意力家族,展开后也有形如“向量内积 + 偏置”的项,只盯局部形式就容易忽略矩阵 W 带来的二阶交互能力。
误区我以为模型给每个词准备了两套词向量,一套专门当老板,一套专门当下属。
正解实际上所有词共享同一份词嵌入、同一个 BiLSTM。只是在 BiLSTM 输出 $\mathbf{h}_i$ 之后,用两个不同的 MLP 把同一份上下文投射成 $\mathbf{r}^{\mathrm{head}}$ 和 $\mathbf{r}^{\mathrm{dep}}$。就像同一份员工档案,HR 从“管理者”和“执行者”两个角度各写一份点评——信息来源相同,解读视角不同。
为何常见:概念名称是成对出现的(head/dep),又确实存在两套 MLP 参数,容易被想象成两套独立的输入通道。
误区既然每个词都选分数最高的老板,那结果自然是每人只有一个老板,应该永远是树吧?
正解每个词只有一个老板只满足了“单父”条件,但可能出现循环指认:A 认为 B 是老板,B 又认为 A 是老板,两个人都不向根汇报。真正的树还需要“连通”和“无环”。Deep Biaffine 在多数语言上可以直接用贪心解码,是因为训练中加入了非树结构的软约束惩罚,让循环分数天然偏低;但严格保证树结构,仍需要 MST 之类的全局解码。
为何常见:把“局部约束”误当成“全局约束”,这是刚接触图结构建模时最常见的直觉偏差。
误区我以为句法分析无非是给句子画一棵树,依存树就是短语结构树换个画法。
正解短语结构树关心“哪些词组成了一个短语”(NP、VP 的层次嵌套),依存树关心“词与词之间的支配关系”(谁是谁的头)。同一个句子,两种树的形状完全不同。Deep Biaffine 输出的是后者:图上只有节点和有向弧,没有短语边界节点。它给出的信息是“这个动词支配了哪个主语、哪个宾语”,而不是“这几个词组成了一个名词短语”。
为何常见:中学英语课接触的大多是短语结构分析,先入为主地把“句法树”默认成了“短语树”。
面试题
Q1. Deep Biaffine 模型主要解决哪类任务?
- A.依存句法分析← 正确答案
- B.文本主题分类
- C.神经机器翻译
- D.词向量预训练
答案:A。Dozat 和 Manning 2017 年提出的 Deep Biaffine 是依存句法分析模型,任务是为每个词找到它的头节点。选项 B、C、D 分别是分类、翻译、表示学习任务,与句法分析无关。用公司比喻说,它专门负责画“全员汇报关系图”。
Q2. 依存树中“单一父节点”约束指的是什么?
- A.每个词只能有一个下属
- B.每个词至多有一个头节点← 正确答案
- C.句子只能有一个动词
- D.所有词必须连接根节点
答案:B。在依存树中,除根节点外每个词恰好有一个“老板”(头节点),这保证组织架构不会出现“一个员工向两个老板汇报”的混乱。选项 A 把方向说反了,C 是无关的语言学常识,D 只描述了连通性而忽略了“老板唯一”这层约束。
Q3. 与普通点积注意力相比,Biaffine 打分公式额外包含什么?
- A.循环门控与记忆单元
- B.双线性项与偏置线性项← 正确答案
- C.位置编码与多层拼接
- D.卷积核与归一化层
答案:B。Biaffine 的核心是双线性项 $a^{\top}\mathbf{W}b$,让两个向量的不同维度两两交叉,再叠加线性项和偏置。普通点积注意力只做同维度对齐。GNN 门控、位置编码、卷积都不是 Biaffine 的增量,故 A、C、D 均不选。
Q4. 模型产生 head 与 dep 两种角色表示的方法是什么?
- A.两个独立 MLP 分别变换← 正确答案
- B.一个共享 MLP 重复两次
- C.两个 BiLSTM 输出拼接
- D.对词向量做奇异值分解
答案:A。同一个 BiLSTM 输出 $\mathbf{h}_i$ 分别经过 $\mathrm{MLP}_{\mathrm{head}}$ 和 $\mathrm{MLP}_{\mathrm{dep}}$ 两套独立参数变换,得到“老板牌”和“下属牌”。共享 MLP 会让两种角色毫无区分度,两个 BiLSTM 和 SVD 都不是论文架构,故排除 B、C、D。
Q5. 贪心解码逐一取最高分头节点,主要风险是什么?
- A.分数过低无法完成解码
- B.无法处理根节点选择
- C.可能出现环破坏树结构← 正确答案
- D.损失函数无法继续优化
答案:C。每个词独立选分数最高的头,可能出现 A 把 B 当老板、B 又把 A 当老板的循环,违反树的“无环”要求。分数低、根节点选择是工程细节而非贪心特有风险,损失函数在训练阶段计算、与解码无关,故 A、B、D 错误。
Q6. 关于 Biaffine 矩阵 W 的说法正确的是哪一项?
- A.它的维度与词典大小相同
- B.它只编码词频统计信息
- C.它替代了序列位置编码
- D.它捕捉角色向量的二阶交互← 正确答案
答案:D。W 的维度是 (d+1)×(d+1),只与向量维度有关,与词典大小无关,A 错;它编码的是“角色特征如何组合打分”而非词频,B 错;位置编码解决词序问题,与 W 无关,C 错。双仿射的 $a^{\top}\mathbf{W}b$ 正是二阶交互,D 正确。
Q7. 句子“小猫喜欢吃鱼”的根节点通常是谁?
- A.第一个名词小猫
- B.核心动词喜欢← 正确答案
- C.第二个动词吃
- D.最后一个名词鱼
答案:B。依存语法遵循“动词中心”原则,核心谓语动词通常是整棵树的根。这里“喜欢”是全句的核心谓词,“吃”是它的从属动词,“小猫”和“鱼”分别是主语和宾语,故根节点是“喜欢”,即全公司的 CEO。
Q8. 下列哪些是依存句法分析的典型下游应用?
- A.信息抽取与关系抽取← 正确答案
- B.机器翻译词序调整← 正确答案
- C.语义角色标注任务← 正确答案
- D.正则表达式匹配文本
答案:ABC。依存树能提供主谓宾骨架,支撑信息抽取;能按子树整体搬移辅助翻译调序;也能为语义角色标注提供论元结构。正则表达式是规则匹配工具,与句法分析无直接关系,D 不选。
Q9. 关于 Deep Biaffine 的训练与评测,下列说法正确的有哪些?
- A.对每个词在候选头上做 softmax← 正确答案
- B.采用交叉熵损失进行训练← 正确答案
- C.UAS 统计弧与标签均正确率
- D.输入常拼接 POS 等额外特征← 正确答案
答案:ABD。训练时对每个词的得分行做 softmax 并用交叉熵优化,A、B 正确;输入拼接词向量、POS 向量和预训练向量是论文标准做法,D 正确。UAS 只看弧头是否预测正确,标签也正确才算的是 LAS,故 C 错误。
Q10. 下列哪些做法能提升 Biaffine 句法分析效果?
- A.拼接预训练词向量← 正确答案
- B.加入词性标注特征← 正确答案
- C.采用双向 LSTM 编码← 正确答案
- D.训练时完全不使用标注
答案:ABC。预训练词向量提供丰富的语义先验,POS 特征提供句法类别信号,双向 LSTM 让每个词看到全文上下文,三者都是论文采用或通用的增强手段。D 去掉了训练用的头节点标注,模型无从学习,必然失败,故不选。