在文本生成任务中,机器翻译的出的句子各种各样那如何去评价不同翻译结果的好坏呢?2002年IBM提出一个重要评价指标Bleu,该论文引用近万,发表于ACL。原文题目是“BLEU: a Method for Automatic Evaluation of Machine Translation”,是NLP从业者的必读文章之一。这篇笔记就从原理介绍,公式解析,再到代码实现来全面展示Bleu的实现。
BLEU全称为Bilingual Evaluation Understudy,其意思是双语评估替补,所谓Understudy (替补),意思是代替人进行翻译结果的评估。一开始这项指标是为了翻译而发明的,但是后来它又被证明可以用来评估一组自然语言处理任务生成的文本。
论文地址:https://www.aclweb.org/anthology/P02-1040
我们首先来看一下n-gram, n-gram将一个句子中连续n个元素作为一个整体,长度为4的句子有4个1-gram,每个单词都是一个1-gram,有3个2-gram,有2个3-gram,1个4-gram,这个4-gram就是句子本身,我们看一下例子:
predictions = "My name is John"
Counter({('My',): 1, ('name',): 1, ('is',): 1, ('John',): 1, ('My', 'name'): 1, ('name', 'is'): 1, ('is', 'John'): 1, ('My', 'name', 'is'): 1, ('name', 'is', 'John'): 1, ('My', 'name', 'is', 'John'): 1}
那么n-gram precision代表prediction中的n-gram在所有的reference translation中出现的概率
predictions = ['the cat is on mat']
reference1 = ‘there is the cat on the mat'
reference2 = 'a cat is on the mat'
我们以the举例,the在reference1中出现的概率为2次,在reference2中出现的概率为1次,那么这个the的频率就是2次
而最后的计算就是用prediction和reference dictionary中共同出现的n-gram个数除以prediction中总的n-gram个数,而这操作也是精确率的求法。
上述算法中存在问题:同一个n-gram在不同的reference中重复出现,计算时次数累加,这样的算法显然是不合理的,如下例
prediction: the the the the the the the.
Reference 1: The cat is on the mat.
Reference 2: There is a cat on the mat.
prediction的1-gram precision是1,显然是不合理的。所以有了做了修正,其modified-gram precision为2/7,其中2=min(7,2)。即prediction和reference dictionary中共同出现的n-gram个数,从这一步修正开始,一个n-gram出现的频率不仅受references中出现频率的制约,也同时受prediction的制约,相当于取两者中的最低值作为min。
介绍完以上这些基础知识,下面我们正式来剖析一下公式:
p n = ∑ C ∈ P r e d i c t i o n ∑ n − g r a m ∈ C C o u n t c l i p ( n − g r a m ) ∑ C ′ ∈ P r e d i c t i o n ∑ n − g r a m ′ ∈ C ′ C o u n t ( n − g r a m ) p_n = \frac{\sum_{C\in{Prediction}}\sum_{n-gram\in C}Count_{clip}(n-gram)}{\sum_{C^{'}\in{Prediction}}\sum_{n-gram^{'}\in C^{'}}Count(n-gram)} pn=∑C′∈Prediction∑n−gram′∈C′Count(n−gram)∑C∈Prediction∑n−gram∈CCountclip(n−gram)
C o u n t c l i p Count_{clip} Countclip这是代表的n-gram既在prediction中出现又在references中出现,而且秉承着modified的原则,公式是:
C o u n t c l i p = m i n ( c o u n t , M a x _ R e f _ c o u n t ) Count_{clip} = min(count, Max \_ Ref \_ count) Countclip=min(count,Max_Ref_count)
先放公式:
B L E U = B P ∗ e x p ( ∑ n = 1 N w n l o g P n ) BLEU = BP * exp(\sum_{n=1}^N w_n logP_n) BLEU=BP∗exp(n=1∑NwnlogPn)
我们一一来剖析这个公式的组成元素。
我们假设一下,如果一个句子只翻译出一个the,而这个the在标准译文中又存在,那么其BLEU就会是1,但是这合理吗?不合理。而这种情况会让机器倾向于去翻译短句子,因为这样得分会更高,为了防范这种情况,就需要加入一个惩罚因子BP。其公式为:
B P = { 1 i f c > r exp ( 1 − r / c ) i f c < = r BP = \begin{cases} 1 \quad if \quad c>r \\ \exp(1-r/c) \quad if \quad c <=r \end{cases} BP={1ifc>rexp(1−r/c)ifc<=r
c为候选句子中的n-gram的个数,r代表的是答案译文中的与c最接近的译文单词的个数。
当c大于r时,不需要惩罚,但是当c小于r是,就要加一个小于1的系数作为惩罚因子。
这是权重系数,赋给不同n的gram的权重,比如说n取4,那么pn就有四个值代表1-gram,2-gram,3-gram,4-gram。
最后就可以实现BLEU的计算。
首先我们来看一下r和c的计算过程
pred_len += len(prediction)
这边的pred_len就是c的总长度
references_len_list = [len(reference) for reference in references]
references_len_diff = [abs(len(prediction) - length) for length in references_len_list]
min_index = references_len_diff.index(min(references_len_diff))
references_len += references_len_list[min_index]
r的长度比较复杂,因为机翻和人翻的数目对比是1对多,多个答案译文我们计算长度时只能挑选,那么就使用references_len_diff这个变量去计算——,在众多reference中,其n-gram数目和对应的prediction最为接近的那个数目,我们将其纳入references_len中。
pred_counter: Counter = get_n_gram(prediction, n_gram)
使用counter来获取prediciton中所有的n-gram
reference_counter: Counter = Counter()
for reference in references:
reference_counter |= get_n_gram(reference, n_gram)
这里就很有意思,references中有多句答案译文,参照上文,我们要挑选出数目最大的加入counter中,也就是min-max公式的max部分,那么使用counter 的 |= 来实现这一目的。
counter_clip = pred_counter & reference_counter
这一步就是实现min-max 的min的过程。
for counter in counter_clip:
precision_matches[len(counter) - 1] += counter_clip[counter]
for counter in pred_counter:
precision_total[len(counter) - 1] += pred_counter[counter]
这一步就是将每一次计算到的counter_clip和counter保存下来
precision_score = precision_matches / precision_total
precision_score = tensor(ngram_weights) * torch.log(precision_score)
brevity_penalty = _get_brevity_penalty(pred_len, references_len)
bleu = brevity_penalty * torch.exp(torch.sum(precision_score))
最终完成BLEU的计算。