§1.2.19

BLEU/ROUGE/METEOR/CIDEr/BERTScore 的计算与缺陷?

手写练习
  • 用 sacrebleu 计算 BLEU,手写 ROUGE-L 的 LCS

核心概念

这些指标是用于评估自然语言生成(NLG)任务(如机器翻译、文本摘要、图像描述)质量的自动化度量标准。它们通过将模型生成的文本(候选句)与一个或多个高质量的人工参考文本(参考句)进行比较来计算得分。

  • BLEU (Bilingual Evaluation Understudy): 主要衡量候选句中 n-gram(连续的 n 个词)在参考句中出现的精确率,并引入简短惩罚项,常用于机器翻译。
  • ROUGE (Recall-Oriented Understudy for Gisting Evaluation): 主要衡量参考句中的 n-gram 在候选句中出现的召回率,因此更适合评估摘要任务,因为它关心摘要是否覆盖了原文的关键信息。
  • METEOR (Metric for Evaluation of Translation with Explicit ORdering): 基于 unigram(单个词)的精确率和召回率的 F-score,但加入了同义词、词干匹配和语序惩罚,试图更全面地衡量语义相似性。
  • CIDEr (Consensus-based Image Description Evaluation): 专为图像描述设计,通过计算候选句和所有参考句之间 n-gram 的 TF-IDF 加权余弦相似度,强调那些在参考句集中达成共识且信息量丰富的词语。
  • BERTScore: 利用预训练语言模型(如 BERT)的上下文词向量,计算候选句和参考句中每个词之间的余弦相似度,从而在语义层面进行评估,而非词汇表面的重叠。

原理与推导

BLEU (Bilingual Evaluation Understudy)

BLEU 的核心思想是“一个好的机器翻译是与专业人工翻译相近的翻译”。它衡量的是“精确率”——生成的词有多少是正确的。

1. 修正的 n-gram 精确率 (pnp_n) 传统的精确率会错误地奖励重复输出正确词语的句子。例如:

  • 候选句 (c): "the the the the the the the"
  • 参考句 (r): "the cat is on the mat" 对于 unigram "the",传统精确率是 7/7 = 1.0,这显然不合理。BLEU 引入了“截断计数”(Clipped Count)。

截断计数: 一个 n-gram 在候选句中的计数,不能超过它在任何单个参考句中出现的最大次数。 在上面的例子中,"the" 在参考句中出现 2 次,所以 "the" 的截断计数为 2。

修正的精确率公式为:

pn=c{Candidates}ngramcCountclip(ngram)c{Candidates}ngramcCount(ngram)p_n = \frac{\sum_{c \in \{\text{Candidates}\}} \sum_{\text{ngram} \in c} \text{Count}_{\text{clip}}(\text{ngram})}{\sum_{c' \in \{\text{Candidates}\}} \sum_{\text{ngram}' \in c'} \text{Count}(\text{ngram}')}

其中分母是候选句中 n-gram 的总数,分子是截断后的计数总和。

2. 简短惩罚 (Brevity Penalty, BP) 只用精确率会导致模型倾向于生成非常短的句子,因为短句子更容易获得高精确率。为解决此问题,引入了简短惩罚。

BP={1if c>re1r/cif crBP = \begin{cases} 1 & \text{if } c > r \\ e^{1 - r/c} & \text{if } c \le r \end{cases}
  • cc 是候选句的总长度。
  • rr 是有效参考句长度。当有多个参考句时,选择与候选句长度最接近的那个参考句的长度。

如果候选句长度大于参考句长度 (c>rc>r),不惩罚 (BP=1BP=1)。如果候选句更短,则惩罚,且长度差越大,惩罚越重。

3. 最终得分 BLEU 分数是不同 n-gram 修正精确率的加权几何平均值,再乘以简短惩罚。通常使用 N=4。

BLEU=BPexp(n=1Nwnlogpn)\text{BLEU} = \text{BP} \cdot \exp\left(\sum_{n=1}^{N} w_n \log p_n\right)
  • wnw_n 是权重,通常取均匀权重 wn=1/Nw_n = 1/N
  • 使用几何平均意味着只要有一个 pn=0p_n=0(例如没有任何 4-gram 匹配),最终的 BLEU 分数就会是 0,这是一种严厉的惩罚。

复杂度: 计算 n-gram 计数的时间复杂度为 O(L)O(L),其中 LL 是语料库的总长度。因此 BLEU 的计算非常快。

ROUGE (Recall-Oriented Understudy for Gisting Evaluation)

ROUGE 关注“召回率”——参考句中的重要信息有多少被候选句覆盖了。

1. ROUGE-N 衡量 n-gram 的召回率。

ROUGE-N=S{Ref sents}gramnSCountmatch(gramn)S{Ref sents}gramnSCount(gramn)\text{ROUGE-N} = \frac{\sum_{S \in \{\text{Ref sents}\}} \sum_{\text{gram}_n \in S} \text{Count}_{\text{match}}(\text{gram}_n)}{\sum_{S \in \{\text{Ref sents}\}} \sum_{\text{gram}_n \in S} \text{Count}(\text{gram}_n)}
  • 分子是候选句和参考句共同拥有的 n-gram 数量。
  • 分母是所有参考句中 n-gram 的总数量。

2. ROUGE-L (Longest Common Subsequence) 不要求 n-gram 连续,只要求词序一致。这能更好地捕捉句子级别的结构相似性。

  • XX 是长度为 mm 的参考句,YY 是长度为 nn 的候选句。
  • LCS(X,Y)LCS(X, Y)XXYY 的最长公共子序列的长度。

召回率 RlcsR_{lcs} 和精确率 PlcsP_{lcs} 分别定义为:

Rlcs=LCS(X,Y)mPlcs=LCS(X,Y)nR_{lcs} = \frac{LCS(X, Y)}{m} \quad P_{lcs} = \frac{LCS(X, Y)}{n}

最终的 ROUGE-L 分数是 F-score:

Flcs=(1+β2)RlcsPlcsRlcs+β2PlcsF_{lcs} = \frac{(1 + \beta^2) R_{lcs} P_{lcs}}{R_{lcs} + \beta^2 P_{lcs}}
  • β\beta 是一个常数,用于调整 P 和 R 的相对重要性。当 β\beta 很大时,F-score 更偏重于召回率 RlcsR_{lcs},这也是 ROUGE 的设计初衷。通常只报告 RlcsR_{lcs}

复杂度: ROUGE-N 复杂度与 BLEU 类似。ROUGE-L 的核心是计算 LCS,使用动态规划的复杂度为 O(mn)O(m \cdot n)

METEOR

METEOR 旨在解决 BLEU 的一些缺陷,如不考虑同义词和词形变化。

  1. 对齐 (Alignment): 在候选句和参考句之间寻找 unigram 的最佳匹配。匹配过程分阶段进行: a. 精确匹配 (Exact match) b. 词干匹配 (Stemmed match),如 "running" 和 "run" c. 同义词匹配 (Synonym match),使用 WordNet 等词典
  2. 计算 Precision 和 Recall:
    • P=匹配上的 unigram 数候选句中的 unigram 总数P = \frac{\text{匹配上的 unigram 数}}{\text{候选句中的 unigram 总数}}
    • R=匹配上的 unigram 数参考句中的 unigram 总数R = \frac{\text{匹配上的 unigram 数}}{\text{参考句中的 unigram 总数}}
  3. 计算 F-mean: 使用加权的 F-score,更看重召回率。 Fmean=PRαP+(1α)R(常见 α=0.15, 对应 10PRR+9P)F_{mean} = \frac{P \cdot R}{\alpha P + (1-\alpha) R} \quad (\text{常见 } \alpha=0.15 \text{, 对应 } \frac{10PR}{R+9P})
  4. 惩罚项 (Penalty): 惩罚语序不佳的情况。如果匹配上的词在原句和译文中是连续成块的,则惩罚小。 Penalty=γ(chunksmatches)θ\text{Penalty} = \gamma \left( \frac{\text{chunks}}{\text{matches}} \right)^\theta
    • chunks 是匹配上的 unigram 形成的连续块的数量。matches 是总匹配数。
    • γ\gammaθ\theta 是超参数,默认分别为 0.5 和 3。
  5. 最终得分: METEOR=Fmean(1Penalty)\text{METEOR} = F_{mean} \cdot (1 - \text{Penalty})

CIDEr

CIDEr 专为图像描述设计,核心思想是“好的描述应该与大多数人的描述相似”。

  1. n-gram 的 TF-IDF 权重:
    • TF (Term Frequency): 计算每个 n-gram 在句子中的频率。
    • IDF (Inverse Document Frequency): 衡量一个 n-gram 的信息量。CIDEr 的 IDF 计算方式很特别,它将整个数据集的所有参考句视为一个大文档集。
    IDF(w)=log(IIkImin(1,C(w,Ik)))\text{IDF}(w) = \log\left(\frac{|I|}{\sum_{I_k \in I} \min(1, C(w, I_k))}\right)
    • I|I| 是数据集中图像的总数。C(w,Ik)C(w, I_k) 是 n-gram ww 在图像 IkI_k 的所有参考描述中出现的次数。这个 IDF 惩罚了在很多图像的描述中都频繁出现的常见 n-gram(如 "a picture of")。
  2. 余弦相似度: 对每个 n-gram 阶数 (n=1, 2, 3, 4),将候选句 cic_i 和参考句 sijs_{ij} 表示为 TF-IDF 加权的 n-gram 向量 gn(ci)g^n(c_i)gn(sij)g^n(s_{ij})。然后计算它们之间的余弦相似度。 CIDErn(ci,Si)=1Mj=1Mgn(ci)gn(sij)gn(ci)gn(sij)\text{CIDEr}_n(c_i, S_i) = \frac{1}{M} \sum_{j=1}^{M} \frac{g^n(c_i) \cdot g^n(s_{ij})}{\|g^n(c_i)\| \cdot \|g^n(s_{ij})\|}
    • Si={si1,...,siM}S_i = \{s_{i1}, ..., s_{iM}\} 是图像 iiMM 个参考句。
  3. 最终得分: 对不同 n-gram 阶数的得分进行平均。 CIDEr(ci,Si)=n=1NwnCIDErn(ci,Si)(通常 wn=1/N)\text{CIDEr}(c_i, S_i) = \sum_{n=1}^{N} w_n \text{CIDEr}_n(c_i, S_i) \quad (\text{通常 } w_n = 1/N)

BERTScore

BERTScore 放弃了词汇匹配,转向语义匹配。

  1. 获取词向量: 将候选句 x=x1,...,xkx = \langle x_1, ..., x_k \rangle 和参考句 y=y1,...,ymy = \langle y_1, ..., y_m \rangle 输入到预训练的 BERT 模型中,提取每个 token 的上下文相关词向量。
  2. 计算相似度矩阵: 计算候选句中每个词向量 xix_i 与参考句中每个词向量 yjy_j 的余弦相似度,形成一个 k×mk \times m 的相似度矩阵。
  3. 贪心匹配:
    • 召回率 (Recall): 对参考句中的每个词 yjy_j,在候选句中找到最相似的词,即 maxi=1kxiTyj\max_{i=1}^k x_i^T y_j。然后对所有 yjy_j 的最大相似度求平均。 RBERT=1mj=1mmaxi=1kxiTyjR_{\text{BERT}} = \frac{1}{m} \sum_{j=1}^{m} \max_{i=1}^k x_i^T y_j
    • 精确率 (Precision): 对候选句中的每个词 xix_i,在参考句中找到最相似的词,即 maxj=1mxiTyj\max_{j=1}^m x_i^T y_j。然后对所有 xix_i 的最大相似度求平均。 PBERT=1ki=1kmaxj=1mxiTyjP_{\text{BERT}} = \frac{1}{k} \sum_{i=1}^{k} \max_{j=1}^m x_i^T y_j
  4. 最终得分: 计算 F1-score。 F1BERT=2PBERTRBERTPBERT+RBERTF1_{\text{BERT}} = 2 \frac{P_{\text{BERT}} \cdot R_{\text{BERT}}}{P_{\text{BERT}} + R_{\text{BERT}}}

复杂度: 主要开销在于 BERT 的前向传播,对于长度为 LL 的序列,复杂度约为 O(L2)O(L^2)。因此,BERTScore 比基于 n-gram 的指标慢得多。

代码实现

使用 sacrebleu 计算 BLEU

sacrebleu 是一个标准化的 BLEU 实现,它能保证不同研究之间比较的公平性,因为它内置了标准的 tokenization 流程。

python
1import sacrebleu
2import numpy as np
3from collections import Counter
4
5# --- sacrebleu 计算 BLEU ---
6# 候选句
7candidate = "the cat is on the mat"
8# 参考句列表 (sacrebleu 要求每个候选句对应一个参考句列表)
9references = ["the cat sat on the mat", "there is a cat on the mat"]
10
11# sacrebleu.corpus_bleu 的输入是候选句列表和参考句列表的列表
12# 即使只有一个候选句,也需要包装成列表
13# refs 的格式: [[ref1_for_cand1, ref2_for_cand1, ...], [ref1_for_cand2, ...], ...]
14cands = [candidate]
15refs = [references]
16
17# 计算 BLEU 分数
18# verbose=True 会打印出贡献 BLEU 分数的各种统计量,如 n-gram 匹配数和句子长度
19bleu = sacrebleu.corpus_bleu(cands, refs, verbose=True)
20print(f"\nSacrebleu BLEU score: {bleu.score:.2f}")
21
22
23# --- 手写 ROUGE-L 的核心 LCS 算法 ---
24def rouge_l_fscore(candidate: str, reference: str, beta: float = 1.2) -> dict:
25 """
26 计算单个候选句和参考句之间的 ROUGE-L 分数。
27 核心是实现最长公共子序列 (LCS) 算法。
28 """
29 # 1. 分词
30 cand_tokens = candidate.split()
31 ref_tokens = reference.split()
32
33 m, n = len(cand_tokens), len(ref_tokens)
34
35 # 处理边界情况:如果任一句子为空,LCS 为 0
36 if m == 0 or n == 0:
37 return {"precision": 0.0, "recall": 0.0, "f1": 0.0}
38
39 # 2. 动态规划计算 LCS 长度
40 # dp[i][j] 表示 cand_tokens[:i] 和 ref_tokens[:j] 的 LCS 长度
41 dp = np.zeros((m + 1, n + 1))
42
43 for i in range(1, m + 1):
44 for j in range(1, n + 1):
45 if cand_tokens[i - 1] == ref_tokens[j - 1]:
46 # 如果当前词匹配,LCS 长度加一
47 dp[i][j] = dp[i - 1][j - 1] + 1
48 else:
49 # 如果不匹配,LCS 长度取两个子问题的最大值
50 dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
51
52 lcs_len = dp[m][n]
53
54 # 3. 计算 Precision, Recall 和 F1-score
55 # ROUGE-L 的召回率
56 recall_lcs = lcs_len / n
57 # ROUGE-L 的精确率
58 precision_lcs = lcs_len / m
59
60 # F-score
61 if recall_lcs == 0 or precision_lcs == 0:
62 f1_lcs = 0.0
63 else:
64 # beta 用于调整 P 和 R 的权重,beta > 1 表示更看重 Recall
65 f1_lcs = (1 + beta**2) * precision_lcs * recall_lcs / (recall_lcs + beta**2 * precision_lcs)
66
67 return {
68 "lcs_len": lcs_len,
69 "precision": precision_lcs,
70 "recall": recall_lcs,
71 "f1": f1_lcs,
72 }
73
74# 示例
75candidate_lcs = "police killed the gunman"
76reference_lcs = "the gunman was killed by police"
77
78# 虽然词序完全不同,但共享了 "the", "gunman", "killed", "police"
79# LCS 应该是 "the gunman" (长度2) 或者 "police" (长度1) 等,取决于具体子序列
80# 正确的 LCS 是 "the gunman"
81# 让我们手动验证一下:
82# cand: p k t g
83# ref: t g w k b p
84# LCS(cand, ref) = "k p" (killed, police) 或 "t g" (the, gunman)
85# 长度都是2
86# 让我们用代码验证
87scores = rouge_l_fscore(candidate_lcs, reference_lcs)
88print(f"\n--- 手写 ROUGE-L (LCS) ---")
89print(f"候选句: '{candidate_lcs}'")
90print(f"参考句: '{reference_lcs}'")
91print(f"LCS 长度: {scores['lcs_len']}")
92print(f"ROUGE-L Precision: {scores['precision']:.4f}")
93print(f"ROUGE-L Recall: {scores['recall']:.4f}")
94print(f"ROUGE-L F1 (beta=1.2): {scores['f1']:.4f}")

工程实践

  • 使用场景:

    • BLEU: 机器翻译(MT)任务的黄金标准,也常用于代码生成、对话系统等。
    • ROUGE: 文本摘要任务的首选(ROUGE-1, ROUGE-2, ROUGE-L),因为它衡量内容覆盖度。
    • METEOR: 在 MT 中作为 BLEU 的补充,与人类判断的相关性通常更高,但计算较慢。
    • CIDEr: 图像/视频描述生成的标准指标,因为它能有效利用多个参考句达成共识。
    • BERTScore: 当语义准确性至关重要,且允许同义词、释义等灵活表达时使用。例如,释义生成、问答系统、高级对话评估。由于计算成本高,常用于最终模型评估,而非开发阶段的快速迭代。
  • 超参数选择:

    • BLEU/ROUGE: n-gram 的阶数 N 通常取 4。对于 BLEU,平滑方法(如 method='exp')可以处理 pn=0p_n=0 的情况。
    • ROUGE: 摘要任务通常同时报告 ROUGE-1, ROUGE-2, ROUGE-L。
    • BERTScore: 关键是选择哪个预训练模型(如 bert-base-uncased, roberta-large)和从哪一层提取向量。通常模型越大、层数越靠后,语义信息越丰富,但计算也越慢。IDF 加权通常能提升性能。
  • 性能/显存/吞吐:

    • BLEU/ROUGE 是最快的,几乎没有计算开销,适合在训练过程中频繁验证。
    • METEOR 速度中等,需要加载 WordNet 等外部资源。
    • BERTScore 是最慢的,需要加载数 GB 的大模型,并且需要 GPU 加速才能获得可接受的吞吐量。在评估大规模测试集时,耗时可能达到数小时。
  • 调试技巧:

    • 指标分数低,但人工看效果不错: 可能是因为你的模型生成了语义正确但用词不同的句子。这时 BLEU/ROUGE 会给出低分。可以尝试用 BERTScore 验证,或者增加更多样化的参考句。
    • 指标分数高,但人工看效果很差: 模型可能学会了“套路”,比如通过重复高频词来刷高 ROUGE-1 分数。此时应仔细检查生成样本,并考虑使用惩罚重复的评估方法。
    • 永远不要只看一个数字: 评估时,除了总分,还应该随机抽取高、中、低分的样本进行人工分析,理解模型的优点和缺点。
    • 使用标准化工具: 为了公平比较,尽量使用 sacrebleu (for BLEU) 和 rouge-score (for ROUGE) 等标准化库,它们处理了 tokenization、大小写等细节。

常见误区与边界情况

  • 误区1: 分数可以跨任务/数据集比较

    • 错误: 在新闻摘要任务上获得的 ROUGE-1=40,和在科技论文摘要任务上获得的 ROUGE-1=35,并不能直接说明前者模型更好。指标分数高度依赖于任务难度、参考句的质量和数量。
    • 正确做法: 只能在相同任务、相同测试集、相同参考句、相同预处理的条件下比较模型分数。
  • 误区2: BLEU 是召回率,ROUGE 是精确率

    • 错误: 这是最常见的混淆。正好相反,BLEU 基于精确率(生成的词有多大比例是正确的),ROUGE 基于召回率(参考句的词有多大比例被生成了)。
  • 误区3: 指标分数越高,模型就越好

    • 错误: 所有自动评估指标都只是人类判断的代理(proxy)。它们无法评估事实性、逻辑性、流畅度之外的微妙之处。一个模型可能通过生成安全但无聊的通用回复来获得高分。
    • 正确做法: 自动评估指标是必要的,但人工评估是最终的黄金标准。
  • 边界情况与失败模式:

    • 同义词/释义: BLEU 和 ROUGE 无法处理同义词。candidate="tiny car", reference="small automobile",BLEU/ROUGE 分数会是 0。METEOR 和 BERTScore 能更好地处理这种情况。
    • 语序和语法: BLEU-N (N>1) 和 ROUGE-L 在一定程度上能捕捉语序,但对长距离依赖和复杂语法结构无能为力。一个语法不通的句子也可能因为包含了正确的 n-gram 而获得不错的 BLEU 分数。
    • 事实性错误: candidate="Obama was born in Kenya", reference="Obama was born in Hawaii"。这些指标只会因为 "Kenya" 和 "Hawaii" 不匹配而轻微扣分,无法识别出严重的事实性错误
    • 重复: BLEU 的截断计数可以惩罚在单个句子内的重复。但如果模型在不同样本间生成大量重复内容,这些指标无法捕捉。
  • 常见面试追问:

    • : "如果你的模型 BLEU 分数很低,但 BERTScore 很高,这意味着什么?你会相信哪个?"
    • : 这通常意味着模型在语义上理解了任务,生成了与参考句意思相同但用词和句式不同的句子。我会更相信 BERTScore 的结果,因为它更好地捕捉了语义相似性。这也表明模型的表达能力比较丰富,没有死记硬背训练数据中的特定短语。但同时,我也会人工抽查样本,确认高 BERTScore 不是由模型缺陷(如生成通用无意义的句子)导致的。
    • : "为什么 BLEU 使用几何平均而不是算术平均?"
    • : 几何平均对低分(尤其是 0 分)的惩罚更重。如果一个模型生成的句子在 1-gram, 2-gram, 3-gram 上匹配都很好(p1,p2,p3p_1, p_2, p_3 很高),但在 4-gram 上完全没有匹配(p4=0p_4=0),几何平均会直接给出 0 分。这符合直觉:一个连像样的短语都生成不了的翻译不是好翻译。而算术平均则会给出一个尚可的分数,掩盖了模型在高阶流畅性上的严重缺陷。
    • : "CIDEr 的 IDF 是如何体现“共识”的?"
    • : CIDEr 的 IDF 是在整个数据集的所有参考句上计算的。如果一个词(如 "a" 或 "is")在几乎所有图像的描述中都出现,它的 IDF 值会非常低。相反,如果一个词(如 "frisbee")只在包含飞盘的图像描述中频繁出现,它的 IDF 值就会很高。因此,当候选句使用了这种具有高 IDF 值的、信息量丰富的词,并且这个词也出现在了当前图像的多个参考句中(即达成了“共识”),CIDEr 就会给出高分。它奖励那些既独特又有共识的描述。
相关题目