BLEU—机器翻译评价方法

Bleu[1]是IBM在2002提出的,用于机器翻译任务的评价,发表在ACL,引用次数10000+,原文题目是“BLEU: a Method for Automatic Evaluation of Machine Translation”。

它的总体思想就是准确率,假如给定标准译文reference,神经网络生成的句子是candidate,句子长度为n,candidate中有m个单词出现在reference,m/n就是bleu的1-gram的计算公式。

BLEU还有许多变种。根据n-gram可以划分成多种评价指标,常见的指标有BLEU-1、BLEU-2、BLEU-3、BLEU-4四种,其中n-gram指的是连续的单词个数为n。

BLEU-1衡量的是单词级别的准确性,更高阶的bleu可以衡量句子的流畅性。

计算公式:

分子释义

神经网络生成的句子是candidate,给定的标准译文是reference。

1) 第一个求和符号统计的是所有的candidate,因为计算时可能有多个句子,

2)第二个求和符号统计的是一条candidate中所有的n−gram,而 [公式] 表示某一个n−gram在reference中的个数。

所以整个分子就是在给定的candidate中有多少个n-gram词语出现在reference中。

分母释义

前两个求和符号和分子中的含义一样,Count(n-gram’)表示n−gram′在candidate中的个数,综上可知,分母是获得所有的candidate中n-gram的个数。

改进版的BLEU计算方法

改进思路:对于某个词组出现的次数,在保证不大于candidate中出现的个数的情况下,然后再reference寻找词组出现的最多次。

评价机器翻译结果通常使用BLEU(Bilingual Evaluation Understudy)。对于模型预测序列中任意的子序列,BLEU考察这个子序列是否出现在标签序列中。

具体来说,设词数为n的子序列的精度为pn​。它是预测序列与标签序列匹配词数为n的子序列的数量与预测序列中词数为n的子序列的数量之比。举个例子,假设标签序列为A、B、C、D、E、F,预测序列为ABB、C、D,那么p1=4/5,p2=3/4,p3=1/3,p4=0。设

lenlabel​和lenpred分别为标签序列和预测序列的词数,那么,BLEU的定义为

$$
\exp \left(\min \left(0,1-\frac{l e n_{\text {label }}}{l e n_{\text {pred }}}\right)\right) \prod_{n=1}^{k} p_{n}^{1 / 2^{n}}
$$
其中 \(k\) 是我们希望匹配的子序列的最大词数。可以看到当预测 序列和标签序列完全一致时,BLEU为 1 。
因为匹配较长子序列比匹配较短子序列更难,BLEU对匹配较长 子序列的精度赋予了更大权重。例如,当 \( p_{n} \) 固定在 \( 0.5 \) 时,随在 \( n \) 的增大, \( 0.5^{1 / 2} \approx 0.7,0.5^{1 / 4} \approx 0.84,0.5^{1 / 8} \approx$ $0.92,0.5^{1 / 16} \approx 0.96 \) 。另外,模型预测较短序列往往会得到 较高 \( p_{n} \) 值。因此,上式中连乘项前面的系数是为了惩罚较短的 输出而设的。举个例子,当 \(k=2 \) 时,假设标签序列为 A 、 B 、 C 、 D 、 E 、 F ,而预测序列为 A 、 B 。虽然 \( p_{1}=p_{2}=1 \) ,但惩罚系数 \( \exp (1-6 / 2) \approx 0.14\) , 因此BLEU也接近 0.14 。

python实现:

def bleu(pred_tokens, label_tokens, k):
    len_pred, len_label = len(pred_tokens), len(label_tokens)
    score = math.exp(min(0, 1 - len_label / len_pred))
    for n in range(1, k + 1):
        num_matches, label_subs = 0, collections.defaultdict(int)
        for i in range(len_label - n + 1):
            label_subs[''.join(label_tokens[i: i + n])] += 1
        for i in range(len_pred - n + 1):
            if label_subs[''.join(pred_tokens[i: i + n])] > 0:
                num_matches += 1
                label_subs[''.join(pred_tokens[i: i + n])] -= 1
        score *= math.pow(num_matches / (len_pred - n + 1), math.pow(0.5, n))
    return score

接下来,定义一个辅助打印函数:

def score(input_seq, label_seq, k):
    pred_tokens = translate(encoder, decoder, input_seq, max_seq_len)
    label_tokens = label_seq.split(' ')
    print('bleu %.3f, predict: %s' % (bleu(pred_tokens, label_tokens, k),
                                      ' '.join(pred_tokens)))

一些注意事项

一般给出的reference是4句话,之所以给出多个句子,是因为单个句子可能无法和生成的句子做很好地匹配。

比如”你好”,reference是”hello”,机器给出的译文是”how are you”,机器给出的词语每一个一个词匹配上这个reference,那么BLEU值是0,这显然是有问题的。所以reference越多样化,匹配成功概率越高。

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注