小林入职第一周,领导让他整理周五的部门例会纪要。他凭印象埋头写了一下午,交上去一看——“预算”那段整整写了三遍,而大家讨论最久的“人员调整”却只字未提。领导又好气又好笑:“你的注意力全都黏在同一个话题上了。”这句话,恰好戳中了 Seq2Seq 模型的痛处:没有记忆的注意力机制,生成时经常在一个词上反复打转,这就是“重复生成”。小林解决问题的办法朴素得像一次整理笔记:拿一支荧光笔,每写完一个要点就把它涂一遍。涂色越深,说明这个要点已经被“覆盖”过了;下一句该写什么,先去看那些还没涂色的要点。这张“涂色清单”,正是 Coverage(覆盖率)机制的直观形态。本文就沿着这条思路,把覆盖率向量怎么维护、覆盖率损失怎么设计、超参数 λ 怎么调,一一道来。

岗位关联

定位并修复生成模型中的重复与遗漏,是 NLP 工程师的日常硬仗;掌握 Coverage 机制,是你从“模型能跑”走向“模型好用”的必备武器。

目录
  1. 可视化演示
  2. 问题缘起:没有勾选表的会议纪要
  3. 覆盖率向量:给每个要点记一笔
  4. 注意力改造:把勾选表交给解码器
  5. 覆盖率损失:重复劳动要扣钱
  6. 超参数调优:扣多扣少有讲究
  7. 效果评估:重复率与BLEU
  8. 应用场景:先划勾再下笔
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示覆盖率向量累积、重复抑制效果对比、Coverage与注意力协同工作。切换模式理解Seq2Seq重复生成问题的解决方案。

本节配有交互动效(进入视口后自动加载,约 3KB)。

覆盖率向量累积与维护 覆盖率向量c_t等于历史所有注意力权重的逐元素累加和,追踪已覆盖的源词位置 已覆盖位置累积值高,引导模型在后续解码步关注未翻译内容 c_t = Σ(s=1 to t-1) α_{t,s} 覆盖率向量是重复抑制的基础

问题缘起:没有勾选表的会议纪要

小林第一次写纪要时,注意力完全是“跟着感觉走”。哪个话题在脑子里印象深,他就多写几句;结果“预算”被反复展开,最后连他自己都忘了“预算”已经写过两遍。这种“注意力偏航”的毛病,本质上是因为他手里没有任何记录——每写一笔,都不知道自己已经写过什么。

在 Seq2Seq 模型里,这个“感觉”就是注意力机制。解码器生成每一个词之前,都会打出一束“探照灯”,在源句的各个词上分配一个注意力权重,然后按照权重抓取信息。可惜这束探照灯只看“现在”,它不记得上一束光打在了哪里。只要解码器当前的状态与上一步相差不大,注意力分布就会几乎原样重演——于是同一个词被反复照到,输出里就出现了“车轱辘话”。

普通注意力打分公式长这样:它把源词表示 $h_i$ 和解码状态 $s_t$ 拼接打分,再经过 softmax 归一化成权重。仔细看,公式里既没有“历史注意力”,也没有“已翻译标记”,这就是重复生成的病根。

小林后来想通了:要治本,先得让“探照灯”记得自己刚才照过谁。于是,一张“勾选表”诞生了——这正是 Coverage 机制的起点。

ait=exp⁡(v⊤tanh⁡(Whhi+Wsst))∑jexp⁡(v⊤tanh⁡(Whhj+Wsst))\displaystyle a_i^t = \frac{\exp\left( v^{\top}\tanh\left( W_h h_i + W_s s_t \right) \right)}{\sum_{j} \exp\left( v^{\top}\tanh\left( W_h h_j + W_s s_t \right) \right)}
这个公式含义是:第 $t$ 步,模型给源句第 $i$ 个词分配多少注意力。打分只由“源词”和“当前状态”决定,与过去的历史完全无关。
  1. 打分函数先计算源词 $h_i$ 与当前解码状态 $s_t$ 的匹配分数,匹配得越接近,分数越高。
    eit=v⊤tanh⁡(Whhi+Wsst)\displaystyle e_i^t = v^{\top}\tanh\left( W_h h_i + W_s s_t \right)
  2. softmax 归一化把这些分数取指数后归一化,变成一组和为 1 的注意力权重。
    ait=exp⁡(eit)∑jexp⁡(ejt)\displaystyle a_i^t = \frac{\exp(e_i^t)}{\sum_j \exp(e_j^t)}
  3. 关键缺陷整个公式没有任何历史记忆项,注意力偏航、重复生成由此而来。
    历史项:无⇒重复生成\displaystyle \text{历史项:无} \Rightarrow \text{重复生成}

覆盖率向量:给每个要点记一笔

领导给了小林一张会议要点清单,上面列着“预算、进度、风险、人员、结论”五个词。小林每写到一个要点,就在它旁边画一道“正”字。写第二遍时,看到“预算”后面已经有两个“正”字,他立刻意识到:这笔写过了,该去看看还没动过的“人员”了。这张清单,就是解决问题的那支“荧光笔”。

在神经网络里,“正”字清单有一个正式的名字:覆盖率向量(coverage vector)。它是一个与源句等长的向量,记作 $c^t$,其中每个分量 $c_i^t$ 表示“源句第 $i$ 个词到第 $t$ 步为止被覆盖了多少”。初始时刻,所有分量都是 0,代表“什么都没写”;每走一步解码,就把这一步的注意力权重加到对应分量上——就像小林每写一个要点就画一道“正”字。

覆盖率向量的维护极其轻量,本质上就是一次向量加法:把上一步的覆盖率向量累加上本步的注意力分布。

有了这张“正”字清单,小林第一次清楚地知道:哪些要点还没写,哪些要点已经写得够多了。下一步,就是把这份清单交到“探照灯”手里。

cit=cit−1+ait\displaystyle c_i^t = c_i^{t-1} + a_i^t
这是一个递推式:第 $t$ 步的覆盖率 = 第 $t-1$ 步的覆盖率 + 第 $t$ 步刚分配的注意力。覆盖率越大,说明这个词越“被写透了”。
  1. 累积更新每一步把新产生的注意力叠加进历史,写成递推式。
    cit=cit−1+ait\displaystyle c_i^t = c_i^{t-1} + a_i^t
  2. 展开形式递推展开后,覆盖率等于过去所有步注意力权重之和。
    ct=∑t′=0t−1at′\displaystyle c^t = \sum_{t'=0}^{t-1} a^{t'}
  3. 直观语义$c_i^t$ 接近 0 表示该词还未被翻译;$c_i^t$ 很大表示已被反复关注。
    cit≈0⇒未覆盖,cit≫0⇒已覆盖c_i^t \approx 0 \Rightarrow \text{未覆盖},\quad c_i^t \gg 0 \Rightarrow \text{已覆盖}

注意力改造:把勾选表交给解码器

以前小林写下一句时,是凭印象在几个要点里“挑一个最熟的”;现在他改成了先扫一眼清单——“正”字少的优先展开。这个小小的动作改变,就是 Coverage 机制的核心改造:把覆盖率向量喂进注意力打分函数,让模型在决定“下一句看哪里”时,先参考“哪里已经看过了”。

技术上,只需在原来的打分公式里多加一项 $w_c c_i^{t-1}$。其中 $w_c$ 是一个可学习的标量权重,模型在训练中会自动学会它的方向:通常它会被学成“负向”,也就是对已覆盖词的分值进行抑制。于是,已经写过两遍的“预算”分数变低,“正”字几乎是空白的“人员”分数相对变高,探照灯自然就被吸引过去。

改造完成之后,注意力变得“喜新厌旧”:总是偏向还没涂色的词。但光改打分还不够,模型在训练时还需要一条明确的“纪律”来约束自己——这就是覆盖率损失。

eit=v⊤tanh⁡(Whhi+Wsst+wc cit−1)\displaystyle e_i^t = v^{\top}\tanh\left( W_h h_i + W_s s_t + w_c\, c_i^{t-1} \right)
相比上一节的普通打分,这里多了 $w_c\, c_i^{t-1}$ 这一项:覆盖率越高,对打分的压制越强。这就像小林写下一句前先扫一眼“正”字清单。
  1. 三项相加打分不再是两个输入,而是源词、解码状态、覆盖率三方共同决定。
    Whhi+Wsst+wc cit−1\displaystyle W_h h_i + W_s s_t + w_c\, c_i^{t-1}
  2. 覆盖权重项$w_c$ 可学习,$c_i^{t-1}$ 是该词的历史覆盖量,乘积实现对已覆盖词的压制。
    wc cit−1⇒已覆盖词降权\displaystyle w_c\, c_i^{t-1} \Rightarrow \text{已覆盖词降权}
  3. 上下文向量变化新的注意力权重重新加权求和源词,得到上下文向量,引导下一个词的生成。
    ctxt=∑iait hi\displaystyle \mathrm{ctx}_t = \sum_{i} a_i^t\, h_i

覆盖率损失:重复劳动要扣钱

领导又加了一条新规矩:同一个要点,展开的篇幅明显超出必要,就要扣绩效。“预算”你要是敢写第三遍,这一遍直接算无效劳动。这条“罚款条款”让小林的注意力在训练中不断被纠正:重复,是要付出代价的。

在模型训练里,这条“罚款条款”叫做覆盖率损失(coverage loss)。它衡量的是:本步注意力 $a^t$ 与历史覆盖率 $c^{t-1}$ 之间的重叠程度。重叠越大,说明模型又在“吃回头草”,罚款就越重。

为什么要用 min 而不是乘法?因为乘法会对所有词都产生惩罚,哪怕这个词是第一次被关注;而 min 只在“注意力超过已有覆盖程度”时才产生惩罚——对还没被覆盖的词,min 的结果是 0,完全不罚。这正是“只罚重复、不罚新词”的精确表达。

有了这条“罚款条款”,模型在训练时被反复提醒:别回头。但罚款的力度不能拍脑袋定,太小了没感觉,太大了又不敢写新东西——这就要说到超参数 λ 的调优。

covlosst=∑i=1Imin⁡(ait,  cit−1)\displaystyle \mathrm{covloss}_t = \sum_{i=1}^{I} \min\left( a_i^t,\; c_i^{t-1} \right)
直觉上,$a_i^t$ 是“这一笔想写多少”,$c_i^{t-1}$ 是“这个词已经写了多少”。两者重叠的部分,就是重复劳动,要扣钱。
  1. min 取小对每个源词,取注意力与覆盖率的较小值,只有重叠部分才计入惩罚。
    min⁡(ait,  cit−1)\displaystyle \min\left( a_i^t,\; c_i^{t-1} \right)
  2. 逐词求和把所有源词的重叠量加起来,得到这一步的覆盖率损失。
    ∑i=1Imin⁡(ait,  cit−1)\displaystyle \sum_{i=1}^{I} \min\left( a_i^t,\; c_i^{t-1} \right)
  3. 极端情形如果本步注意力与上一步完全相同,$a_i^t \approx c_i^{t-1}$,损失约为 1,相当于“整步重复全被罚款”。
    ait=cit−1⇒covlosst≈1\displaystyle a_i^t = c_i^{t-1} \Rightarrow \mathrm{covloss}_t \approx 1

超参数调优:扣多扣少有讲究

小林的部门后来把“罚款条款”制度化,但很快就发现一个问题:罚款比例定多少?定得太轻,“预算”还是忍不住多写;定得太重,小林变得畏手畏脚,连第一次应该写的“人员”都不敢展开,纪要反而更空洞。领导只能拍板:先定个中间值,跑一个月看看数据。

在模型中,这个“罚款比例”就是超参数 λ。总损失由两部分构成:常规的最大似然损失(负责让模型“翻得对”)加上覆盖率损失乘以 λ(负责让模型“不重复”)。λ 越大,模型越不敢重复,但也越容易“过度覆盖”——明明该回头确认某个词,却因为回头会被罚而强行跳过去,导致漏译。

调参技巧是“先小后大”:先用小 λ 让模型稳定收敛,再逐步加大到目标值,观察验证集上重复率下降与 BLEU 不再下滑的那个拐点。罚款力度刚刚好时,小林既不重复,也不漏项——领导终于点头了。

L=Lnll+λ∑tcovlosst\displaystyle \mathcal{L} = \mathcal{L}_{\mathrm{nll}} + \lambda \sum_{t} \mathrm{covloss}_t
这份总损失把“翻译质量”和“不重复纪律”放在同一杆秤上。λ 就是那杆秤的砝码:一边是流畅度,一边是重复率。
  1. 标准损失$\mathcal{L}_{\mathrm{nll}}$ 是常规的负对数似然损失,保证生成的词与标准答案一致。
    Lnll=−∑tlog⁡P(yt∣y<t,x)\displaystyle \mathcal{L}_{\mathrm{nll}} = -\sum_t \log P(y_t \mid y_{<t}, x)
  2. 惩罚求和把每个解码步的覆盖率损失累加,得到全程的“重复罚款总额”。
    ∑tcovlosst\displaystyle \sum_{t} \mathrm{covloss}_t
  3. λ 系数$\lambda$ 控制罚款力度。论文常见取 $\lambda = 1$,实际项目常在 0.1~1.0 之间网格搜索;λ 过大会出现过覆盖、漏译,BLEU 不升反降。
    λ∈[0.1, 1.0],以验证集 BLEU 与重复率联合选取\displaystyle \lambda \in [0.1,\, 1.0],\quad \text{以验证集 BLEU 与重复率联合选取}

效果评估:重复率与BLEU

一个月后,领导用三张“成绩单”检验小林的改进:重复率(同一要点被写了多少遍)、完整率(有没有遗漏)、读者可读性评分。以前小林的重复率那栏红得刺眼,现在终于成了绿色。这三张成绩单,对应到模型评估里就是:n-gram 重复率、BLEU 分数、以及长句专项测试。

重复率是最直观的指标。它统计生成结果里“重复的 n-gram 占总 n-gram 的比例”,本质上是衡量“车轱辘话”有多少。Coverage 机制的核心收益就在这里:它从源头掐断了重复,所以重复率会大幅下降。相比之下,BLEU 的提升往往是“小幅”的——因为 BLEU 衡量的是整体翻译质量,覆盖率损失只是众多改进之一。

值得注意的是,覆盖机制的收益在长句上最明显——生成越长,注意力越容易“走回头路”,而没有 Coverage 的模型重复概率会随长度指数上升。实验里常见的结果是:重复率大幅下降,BLEU 小幅提升 0.2~0.5 分。所以评估时要重点盯着重复率这张“成绩单”,不要只盯着 BLEU。

Rrep=Ntotal−NdistinctNtotal×100%\displaystyle R_{\text{rep}} = \frac{N_{\text{total}} - N_{\text{distinct}}}{N_{\text{total}}} \times 100\%
$N_{\text{total}}$ 是生成文本中所有 n-gram 的数量,$N_{\text{distinct}}$ 是其中不重复的种类数。两者差得越多,重复现象越严重。
  1. 去重计数统计生成结果中不重复的 n-gram 数量。
    Ndistinct=∣{ n-gramk }∣\displaystyle N_{\text{distinct}} = \left| \{\, \text{n-gram}_k \,\} \right|
  2. 占比差异用总量减去做去重后的数量,得到重复掉的部分。
    Ntotal−Ndistinct\displaystyle N_{\text{total}} - N_{\text{distinct}}
  3. 归一化除以总量再乘 100%,得到可横向对比的重复率。
    Rrep=Ntotal−NdistinctNtotal×100%\displaystyle R_{\text{rep}} = \frac{N_{\text{total}} - N_{\text{distinct}}}{N_{\text{total}}} \times 100\%

应用场景:先划勾再下笔

小林的“荧光笔法”被写进了公司《纪要写作手册》,各部门很快发展出自己的花样:翻译组用它防止同一个词被翻译两遍;摘要组用它保证新闻要点一条不落;文案组用它治理长文里的“车轱辘话”。核心纪律始终只有一条:先划勾,再下笔。

技术上的“花样”主要有三种。第一种是软覆盖,也就是前面讲的把覆盖率向量注入注意力打分,让模型“倾向于”不看已覆盖词;第二种是硬覆盖,直接禁止模型再关注覆盖率超过阈值的词,把“倾向”变成“强制”;第三种是与指针生成网络(Pointer-Generator)结合,在文本摘要中同时抑制重复和遗漏。

但也要记得 Coverage 的适用边界:创意写作、诗歌、修辞性重复等“需要重复”的场景,不要盲目套用。手册首页那句话始终是对的——先划勾,再下笔,它救的是“该说没说、不该说反复说”的机器翻译和摘要系统。

ait=softmax(eit)⋅1(cit−1<τ)\displaystyle a_i^t = \mathrm{softmax}(e_i^t) \cdot \mathbb{1}\left( c_i^{t-1} < \tau \right)
这个“硬覆盖”公式的意思是:如果某个词的历史覆盖率 $c_i^{t-1}$ 已经超过了阈值 $\tau$,就把它当“违禁词”直接排除在注意力候选之外。它比软覆盖更激进,适合重复特别严重的场景。
  1. 指示函数$\mathbb{1}(\cdot)$ 是一个开关,条件为真取 1,为假取 0——相当于把超标的词“拉黑”。
    1(cit−1<τ)\displaystyle \mathbb{1}\left( c_i^{t-1} < \tau \right)
  2. 阈值判断$\tau$ 是覆盖率阈值,超过它,该词本轮禁止参与注意力分配。
    cit−1≥τ⇒ait=0\displaystyle c_i^{t-1} \geq \tau \Rightarrow a_i^t = 0
  3. 乘回 softmax把开关乘到原有注意力分布上,再重新归一化,得到无重复的分布。
    ait←ait∑jajt,仅保留未超标词\displaystyle a_i^t \gets \frac{a_i^t}{\sum_j a_j^t},\quad \text{仅保留未超标词}

AI 应用场景

场景一:神经机器翻译平台的防重复优化

阶段:模型训练与调优

解决的问题:长句翻译中,模型常把同一个源词反复翻译(如将 “the report“ 翻译成”报告报告“),同时漏掉句子后部的关键信息。传统做法只能靠 beam search 的长度惩罚”事后补救“,治标不治本;Coverage 机制在训练阶段就让注意力”记得”已翻译的词,从源头抑制重复,同时用覆盖率损失避免遗漏。

具体案例:某跨境电商的英译中翻译接口,在处理 30 词以上的长句时重复率高达 12%。接入 Coverage 后,将覆盖率向量加入注意力打分、并在损失函数中加入 $\lambda \sum \mathrm{covloss}_t$(λ 在 0.3~0.8 间搜索),重复率降至 3% 以下,长句 BLEU 提升 0.4 分。

场景二:新闻摘要系统的要点全覆盖

阶段:后训练与解码优化

解决的问题:摘要生成模型在压缩长新闻时,经常“揪着一句话没完没了地改写”,而真正重要的另一段却从未被提及。Coverage 的软覆盖 + 覆盖率损失组合,能保证模型在有限的摘要长度内尽量“雨露均沾”地覆盖原文要点。

具体案例:某资讯 App 的摘要模型采用 Pointer-Generator + Coverage 架构(参考 “Get To The Point“ 论文)。上线后,摘要的 4-gram 重复率下降约 70%,人工评估的”要点覆盖率”从 61% 提升到 82%,点击率有明显回升。

场景三:长文案生成的“车轱辘话”治理

阶段:生成策略与评估

解决的问题:大模型写产品介绍、周报范文时,越长的输出越容易出现语义重复的段落,影响可读性。Coverage 机制可以作为解码阶段的后处理约束(如硬覆盖阈值 $\tau=0.5$),在兼顾流畅度的前提下强制模型去覆盖“还没写过的内容”。

具体案例:某办公软件的长文档续写功能,对 500 字以上的生成内容做 Coverage 硬约束后,用户反馈中“内容重复啰嗦”的投诉量减少约一半,生成文本的信息密度评分上升。

Python 演示

python58 行
import numpy as np # 四个源词(会议要点),用 8 维向量表示source = np.array([    [1, 0, 1, 0, 0, 0, 1, 0],   # 要点0:预算    [0, 1, 0, 1, 0, 0, 0, 1],   # 要点1:进度    [0, 0, 0, 0, 1, 1, 1, 0],   # 要点2:风险    [1, 0, 0, 1, 0, 1, 0, 1],   # 要点3:人员], dtype=float)  class CoverageDecoder:    """极简 Coverage 机制演示:注意力打分 + 覆盖率累积"""     def __init__(self, use_coverage=True, penalty=5.0):        self.use_coverage = use_coverage        self.penalty = penalty        self.coverage = np.zeros(len(source))     def attention(self, query):        scores = source @ query                    # 原始注意力打分        if self.use_coverage:                      # Coverage 改造:            scores = scores - self.penalty * self.coverage   # 已覆盖词降权        probs = np.exp(scores - scores.max())      # 数值稳定的 softmax        return probs / probs.sum()     def step(self, query):        att = self.attention(query)        self.coverage = self.coverage + att        # 累积覆盖率向量        return int(np.argmax(att))     def decode(self, queries):        self.coverage = np.zeros(len(source))        return [self.step(q) for q in queries]  def coverage_loss(attention, coverage):    """covloss = sum(min(a_i, c_i)):重复部分越大,惩罚越大"""    return float(np.sum(np.minimum(attention, coverage)))  queries = np.array([    [1, 0, 1, 0, 0, 0, 1, 0],   # 解码第 1 步:状态偏向要点0    [1, 0, 1, 0, 0, 0, 1, 0],   # 第 2 步:解码状态几乎没变(重复高发)    [1, 0, 1, 0, 0, 0, 1, 0],   # 第 3 步:依然没变    [0, 1, 0, 1, 0, 0, 0, 1],   # 第 4 步:状态转向要点1    [0, 0, 0, 0, 1, 1, 1, 0],   # 第 5 步:转向要点2    [1, 0, 0, 1, 0, 1, 0, 1],   # 第 6 步:转向要点3]) plain = CoverageDecoder(use_coverage=False).decode(queries)covered = CoverageDecoder(use_coverage=True).decode(queries)print("无覆盖机制:", plain)print("带覆盖机制:", covered)print("前3步重复聚焦要点0的次数:", plain[:3].count(0), "vs", covered[:3].count(0)) att1 = CoverageDecoder(use_coverage=False).attention(queries[0])print("完全重复上一轮注意力时的覆盖率损失:", round(coverage_loss(att1, att1), 3))
目的:用 NumPy 实现一个“玩具版” Coverage 解码器,演示覆盖率向量如何让困在同一个词上的注意力“被迫”转向未覆盖词,并展示覆盖率损失 min(a,c) 的计算。
  1. scores = source @ query计算解码状态与各源要点的相似度,相当于“探照灯”的原始打分。
  2. scores = scores - self.penalty * self.coverageCoverage 改造:已覆盖词被打分降权,对应公式中的 $w_c c_i^{t-1}$。
  3. self.coverage = self.coverage + att更新覆盖率向量,等价于公式 $c^t = c^{t-1} + a^t$。
  4. np.sum(np.minimum(attention, coverage))覆盖率损失:min 只计算注意力与覆盖率的重叠部分,重复越多惩罚越大。

常见误区

误区“覆盖率损失是额外惩罚,强行不让模型回头看,BLEU 肯定会掉。我试过一次,效果变差了,所以 Coverage 是个负优化。”

正解这只是 λ 设置不当的锅。在合适的 λ 下,Coverage 并不会显著损害 BLEU——论文和工业实践中表现为“BLEU 持平或小幅提升,重复率大幅下降”。类似小林调“罚款比例”:罚款过重才会让人不敢干活,比例合适时重复少了,纪要反而更完整。

为何常见:很多人第一次实验就选了很大的 λ,观察到过覆盖、漏译等问题,于是把“参数没调好”误判成“机制本身不行”。

误区“理想的覆盖率向量应该是均匀的,每个源词都被同样地覆盖一遍,这样才说明没有遗漏。”

正解覆盖率只是“已翻译多少”的指示牌,不是训练目标。不同词本来就该被覆盖得不一样——虚词可能只需轻轻扫过,关键词可能被多次回看。硬求均匀反而会扭曲注意力对齐,相当于强迫小林每个要点必须写一模一样的字数,那反而写不好。

为何常见:把“覆盖”误解成“均匀分配注意力”,忽略了覆盖率是累积的副产品,而非需要被优化的对象。

误区“训练时把覆盖率损失加进总损失就行了,推理时把注意力公式换回原来的,省一点计算量。”

正解Coverage 机制包含两个独立组件:覆盖率向量注入注意力打分(推理时也要用)和覆盖率损失(仅训练时使用)。推理时去掉覆盖率向量,模型又变回没有记忆的“探照灯”,训练时学到的“不回头”习惯就使不上了。

为何常见:混淆了“机制”与“损失”两个层次,以为 Coverage 只是加了一个 loss 项。

误区“min 还要判断大小,太麻烦。直接用 $a_i^t \cdot c_i^{t-1}$ 作为惩罚不也能衡量重叠吗?”

正解乘积会对所有词都产生惩罚——哪怕这个词从没被覆盖过($c=0$ 时不罚,但正常关注时 $a$ 和 $c$ 都中等就会误伤)。min 的语义是“只罚超出已有覆盖的那部分重复”,这才能精准打击“车轱辘话”。用乘积就像对小林说“你写的每个字都扣钱”,他当然一个字都不敢写了。

为何常见:直觉上认为“重叠=乘积”,忽略了 min 提供的是“只算多出来的那部分”的精确语义。

误区“模型用了 Coverage,输出里就不可能出现重复词了,可以直接上线。”

正解Coverage 大幅降低重复,但不能保证绝对零重复——解码策略(如 beam search 的长度惩罚不足)、训练目标与解码方式不一致(曝光偏差)都会制造新的重复。实践中常把 Coverage 与长度惩罚、重复惩罚(repetition penalty)配合使用,而不是孤军奋战。

为何常见:把单一机制当成万能药,忽略了 Seq2Seq 重复生成是多因素共同作用的结果。

面试题

Q1. Coverage 机制主要解决 Seq2Seq 的哪个问题?

单选题 · easy

  • A.训练速度慢
  • B.重复生成与遗漏← 正确答案
  • C.词表规模过大
  • D.梯度消失问题

答案:B。Coverage 机制通过累积历史注意力来标记“已覆盖”的源词,从而抑制模型反复关注同一词(重复)并引导关注未翻译词(防遗漏)。它不解决训练速度、词表或梯度问题,就像小林靠“正”字清单解决的是“重复写和漏写”。

Q2. 覆盖率向量 c 的初始值是什么?

单选题 · easy

  • A.全 1 向量
  • B.全 0 向量← 正确答案
  • C.随机初始化
  • D.与首步注意相同

答案:B。解码尚未开始时,没有任何源词被覆盖,所以覆盖率向量初始化为全 0。这对应小林拿到空白“正”字清单时的状态——每个要点都还没动笔。

Q3. 覆盖率向量的更新方式是什么?

单选题 · mid

  • A.c^t = c^{t-1} - a^t
  • B.c^t = c^{t-1} × a^t
  • C.c^t = c^{t-1} + a^t← 正确答案
  • D.c^t = softmax(c^{t-1})

答案:C。每一步解码产生的注意力权重会叠加进覆盖率向量,即 $c^t = c^{t-1} + a^t$。这是“每写一个要点就画一道正字”的数学形式:新画的笔画(注意力)加在已有的笔画(覆盖率)上。

Q4. 注意力打分公式中 w_c·c_i 项的作用是什么?

单选题 · mid

  • A.放大源词长度
  • B.使已覆盖词降权← 正确答案
  • C.加快收敛速度
  • D.替代位置编码

答案:B。$w_c$ 是可学习权重,与历史覆盖率 $c_i$ 相乘后加入打分,模型会学到“对已覆盖词压低分数”,让注意力转向未覆盖词。它不处理长度、收敛或位置信息,就像小林写下一句前先看哪个要点“正”字最少。

Q5. coverage loss 中 min(a_i, c_i) 的语义是什么?

单选题 · mid

  • A.惩罚所有源词
  • B.仅惩罚重复部分← 正确答案
  • C.鼓励模型重复
  • D.加快梯度更新

答案:B。当注意力再次大量投向已覆盖词时,min 取到的是两者的重叠部分,这才是“重复劳动”;对未覆盖词,min 结果为 0 不产生惩罚。因此它精准打击“吃回头草”,而不是一刀切地禁止关注。

Q6. 超参数 λ 设置过大会导致什么?

单选题 · hard

  • A.重复率反而升高
  • B.过覆盖与漏译← 正确答案
  • C.训练必然崩溃
  • D.注意力全部为零

答案:B。λ 过大时,模型为了躲避覆盖率惩罚而“不敢回头”,即使需要回看已翻译词来生成准确译文也会强行跳过,导致漏译、过覆盖,BLEU 不升反降。这就像罚款太重,小林连该写的要点都不敢展开。

Q7. 推理阶段使用 Coverage 机制的正确方式是?

单选题 · hard

  • A.仅训练时使用
  • B.推理时也注入覆盖率打分← 正确答案
  • C.固定注意力为均匀分布
  • D.推理时禁用注意力

答案:B。覆盖率向量注入注意力打分属于“机制”,训练和推理时都应保留,模型才能沿用不重复的习惯;覆盖率损失才是只在训练时使用的“纪律”。推理时删掉覆盖率注入,等于让小林把“正”字清单扔掉再写纪要。

Q8. Coverage 机制可以应用于哪些任务?

多选题 · easy

  • A.机器翻译← 正确答案
  • B.文本摘要← 正确答案
  • C.长文本生成← 正确答案
  • D.图像裁剪

答案:ABC。机器翻译防重复翻译、文本摘要保证要点全覆盖、长文本生成治理“车轱辘话”,都是 Coverage 的典型应用。图像裁剪属于视觉任务,与序列到序列的注意力覆盖问题无关。

Q9. 关于覆盖率损失的说法,正确的有?

多选题 · mid

  • A.min 衡量重复← 正确答案
  • B.λ 控制惩罚强度← 正确答案
  • C.直接优化 BLEU
  • D.加入总损失训练← 正确答案

答案:ABD。覆盖率损失用 min(a,c) 计算重叠惩罚,乘以 λ 后加入总损失共同训练。但它是“翻译质量”的辅助纪律,并不直接优化 BLEU——BLEU 是评估指标而非训练目标,直接通过损失优化 BLEU 既不可微也不现实。

Q10. Seq2Seq 重复生成的原因包括哪些?

多选题 · hard

  • A.注意力无历史记忆← 正确答案
  • B.状态相似分布相近← 正确答案
  • C.词表过大导致稀疏
  • D.训练解码不一致← 正确答案

答案:ABD。注意力打分不含历史信息,解码状态相邻步接近时注意力分布趋同,加上训练时用真实词、解码时用生成词造成的曝光偏差,都会引发重复。词表过大会导致稀疏性问题,但不是重复生成的直接原因。