机器翻译与自动文摘评价指标 BLEU 和 ROUGE

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了机器翻译与自动文摘评价指标 BLEU 和 ROUGE相关的知识,希望对你有一定的参考价值。

参考技术A

在机器翻译任务中,BLEU 和 ROUGE 是两个常用的评价指标, BLEU 根据精确率(Precision) 衡量翻译的质量,而 ROUGE 根据召回率(Recall) 衡量翻译的质量。

使用机器学习的方法生成文本的翻译之后,需要评价模型翻译的性能,这就要用到一些机器翻译评价指标,其中比较常见的评价指标有 BLEU 和 ROUGE。这两个指标具有比较旧的历史, BLEU 是 2002 年提出的,而 ROUGE 是 2003 年提出的 。这两种指标虽然存在着一些问题,但是仍然是比较主流的机器翻译评价指标。

一般用 表示机器翻译的译文,另外还需要提供m个参考的翻译 。评价指标就可以衡量机器翻译的 和参考翻译 的匹配程度。

BLEU 的全称是 Bilingual evaluation understudy(双语互译质量评估辅助工具),BLEU 的分数取值范围是 0~1,分数越接近1,说明翻译的质量越高。BLEU 主要是基于精确率(Precision)的。

其实最原始的BLEU算法很简单,我们每个人都有意无意做过这种事:两个句子,S1和S2,S1里头的词出现在S2里头越多,就说明这两个句子越一致。就像这样子:similarity(‘i like apple’, ‘i like english’)=2/3。

分子是 一个候选翻译的单词有多少出现在参考翻译中 (出现过就记一次,不管是不是在同一句参考翻译里头), 分母是这个候选翻译的词汇数

请看下面这个错误案例:

计算过程:

很明显,这样算是错的,需要改进一下。

专业一点,上面出现的错误可以理解为 常用词干扰 (over-generate “reasonable”words),比如the, on这样的词,所以极易造成翻译结果低劣评分结果却贼高的情况。

另外,上面我们一个词一个词的去做统计,以一个单词为单位的集合,我们统称uni-grams(一元组集)。如果是这样“the cat”, “cat is”, “is on”, “on the”, “the mat”,类似"the cat"两个相邻词一组就叫做bi-gram(二元组),以此类推:三元组、四元组、…、多元组(n-gram),集合变复数:n-grams。

OK,上述算法问题其实处在分子的计算上,我们换成这个:

名词解释:对于一跳候选翻译——

举例:

其实 改进的n-gram精度得分可以用了衡量翻译评估的充分性和流畅性两个指标:一元组属于字符级别,关注的是翻译的充分性,就是衡量你的逐字逐字翻译能力; 多元组上升到了词汇级别的,关注点是翻译的流畅性,词组准了,说话自然相对流畅了。所以我们可以用多组多元精度得分来衡量翻译结果的。

BLEU的处理办法其实还是一样,把多个句子当成一个句子罢了:

不要被这里的连加公式给欺骗了,它将候选段落的所有n-gram进行了截断统计作为分子,分母是候选段落的n-gram的个数。

在3.2提到,uni-gram下的指标可以衡量翻译的充分性,n-gram下的可以衡量翻译的流畅性,建议将它们组合使用。那么,应该如何正确的组合它们呢?

没疑问,加总求和取平均。专业点的做法要根据所处的境况选择加权平均,甚至是对原式做一些变形。

首先请看一下不同n-gram下的对某次翻译结果的精度计算:

事实是这样,随着n-gram的增大,精度得分总体上成指数下降的,而且可以粗略的看成随着n而 指数级的下降 。我们这里采取 几何加权平均 ,并且将各n-gram的作用视为等重要的,即取权重服从均匀分布。

对应到上图,公式简单表示为:

再仔细看改进n-gram精度测量,当译句比参考翻译都要长时,分母增大了,这就相对惩罚了译句较长的情况。译句较短就更严重了!比如说下面这样:

显然,这时候选翻译的精度得分又是 。短译句就是这样,很容易得高分…所以必须要设计一个有效的惩罚措施去控制。

首先,定一个名词叫“最佳匹配长度”(best match length),就是,如果译句长度和任意一个参考翻译的长度相同,就认为它满足最佳匹配长度。这种情况下,就不要惩罚了,惩罚因子要设为1。

见上式, 是一个参考翻译的词数, 是一个候选翻译的词数,BP代表译句较短惩罚值。由此,最终 值得计算公式为:

通过一次次的改进、纠正,这样的 BLEU算法已经基本可以快捷地给出相对有参考价值的评估分数了。做不到也不需要很精确,它只是给出了一个评判的参考线而已。

ROUGE指标的全称是(Recall-Oriented Understudy for Gisting Evaluation),主要是基于召回率(recall)的。ROUGE是一种常用的机器翻译和文章摘要评价指标,由Chin-Yew Lin提出,其在论文中提出了4种ROUGE方法:

ROUGE-N 主要统计 N-gram 上的召回率,对于 N-gram,可以计算得到 ROUGE-N 分数,计算公式如下:

公式的分母是统计在参考译文中 N-gram 的个数,而分子是统计参考译文与机器译文共有的 N-gram 个数。

上面例子的ROUGE-1和ROUGE-2分数如下

如果给定多个参考译文 ,Chin-Yew Lin 也给出了一种计算方法,假设有 M 个译文 S1, ..., SM。ROUGE-N 会 分别计算机器译文和这些参考译文的 ROUGE-N 分数 ,并取其最大值,公式如下。这个方法也可以用于 ROUGE-L,ROUGE-W 和 ROUGE-S。

ROUGE-L 中的 L 指最长公共子序列 (longest common subsequence, LCS),ROUGE-L 计算的时候使用了机器译文 C 和参考译文 S 的最长公共子序列,计算公式如下:

ROUGE-W 是 ROUGE-L 的改进版,考虑下面的例子,X 表示参考译文,而 Y1,Y2 表示两种机器译文。

在这个例子中,明显 Y1 的翻译质量更高,因为 Y1 有更多连续匹配的翻译。但是采用 ROUGE-L 计算得到的分数确实一样的,即 ROUGE-L(X, Y1)=ROUGE-L(X, Y2)。

因此作者提出了一种加权最长公共子序列方法 (WLCS),给连续翻译正确的更高的分数,具体做法可以阅读原论文《ROUGE: A Package for Automatic Evaluation of Summaries》。

ROUGE-S 也是对 N-gram 进行统计,但是其采用的 N-gram 允许"跳词 (Skip)",即单词不需要连续出现。例如句子 "I have a cat" 的 Skip 2-gram 包括 (I, have),(I, a),(I, cat),(have, a),(have, cat),(a, cat)。

机器翻译评测--BLEU与Perplexity详解

前言

  近年来,在自然语言研究领域中,评测问题越来越受到广泛的重视,可以说,评测是整个自然语言领域最核心和关键的部分。而机器翻译评价对于机器翻译的研究和发展具有重要意义:机器翻译系统的开发者可以通过评测得知系统存在的问题而不断改进,用户也可以根据评测报告选择满足自己需求的产品,而对于机器翻译的研究人员来说,评测能够给他们的技术发展方向提供最可靠的依据。

——摘自北京邮电大学信息工程系张剑博士在微软亚洲研究院访问期间完成的一篇论文中的一段话。  

  早在90年代初,美国国家自然基金委员会和欧盟就资助的国际语言工程标准(ISLE)计划就专门设立了EWG(Evaluation Working Group)机器翻译评测工作组。1992年至1994年之间,美国国防部高级研究计划署(DARPA)专门组织一批专家从翻译译文的忠实度、流利度和信息量三个角度对当时的法英、日英、西英的机器翻译系统进行了大规模的评测。目前比较流行的自动评测方法是是IBM提出的BLEU算法,BLEU(bilingual evaluation understudy),简单来说,BLEU算法的思想就是机器翻译的译文越接近人工翻译的结果,它的翻译质量就越高。所以评测算法就是如何定义机器翻译译文与参考译文之间的相似度。

  我们看下BLEU算法具体的细节吧:

 

N-gram

  BLEU 采用一种N-gram的匹配规则,原理比较简单,就是比较译文和参考译文之间n组词的相似的一个占比。

  例如:

    原文:今天天气不错

    机器译文:It is a nice day today

    人工译文:Today ia nice day

  如果用1-gram匹配的话:

    技术分享

  可以看到机器译文一共6个词,有5个词语都命中的了参考译文,那么它1-gram的匹配度为 5/6 

  我们再以3-gram举例:

    技术分享

  可以看到机器译文一共可以分为四个3-gram的词组,其中有两个可以命中参考译文,那么它3-gram的匹配度为 2/4  

  依次类推,我们可以很容易实现一个程序来遍历计算N-gram的一个匹配度。一般来说1-gram的结果代表了文中有多少个词被单独翻译出来了,因此它反映的是这篇译文的忠实度;而当我们计算2-gram以上时,更多时候结果反映的是译文的流畅度,值越高文章的可读性就越好。

 

召回率

  上面所说的方法比较好理解,也比较好实现,但是没有考虑到召回率,举一个非常简单的例子说明:

  原文:猫站在地上

  机器译文:the the the the 

  人工译文:The cat is standing on the ground

  在计算1-gram的时候,the 都出现在译文中,因此匹配度为4/4 ,但是很明显 the 在人工译文中最多出现的次数只有2次,因此BLEU算法修正了这个值的算法,首先会计算该n-gram在译文中可能出现的最大次数:

  技术分享

  Count是N-gram在机器翻译译文中的出现次数,Max_Ref_Count是该N-gram在一个参考译文中最大的出现次数,最终统计结果取两者中的较小值。然后在把这个匹配结果除以机器翻译译文的N-gram个数。因此对于上面的例子来说,修正后的1-gram的统计结果就是2/4。

  我们将整个要处理的将机器翻译的句子表示为Ci,标准答案表示为 Si=si1,...sim(m表示有m个参考答案)  

  n-grams表示n个单词长度的词组集合,令Wk第k个n-gram

  比如这样的一句话,”I come from china”,第1个2-gram为:I come; 第2个2-gram为:come from; 第3个2-gram为:from china;

  Hk(Ci) 表示Wk翻译选译文Ci中出现的次数

  Hk(Sij) 表示Wk在标准答案Sij中出现的次数

 

  综上所述各阶N-gram的精度都可以按照下面这个公式计算:

  技术分享

  

  maxi∈mhk(sij)表示某n-gram在多条标准答案中出现最多的次数

  ∑i∑kmin(hk(ci),maxj∈mhk(sij))表示取n-gram在翻译译文和标准答案中出现的最小次数

 

惩罚因子

  上面的算法已经足够可以有效的翻译评估了,然而N-gram的匹配度可能会随着句子长度的变短而变好,因此会存在这样一个问题:一个翻译引擎只翻译出了句子中部分句子且翻译的比较准确,那么它的匹配度依然会很高。为了避免这种评分的偏向性,BLEU在最后的评分结果中引入了长度惩罚因子(Brevity Penalty)。

  技术分享

  BP的计算公式如上。lc代表表示机器翻译译文的长度,ls表示参考答案的有效长度,当存在多个参考译文时,选取和翻译译文最接近的长度。当翻译译文长度大于参考译文的长度时,惩罚系数为1,意味着不惩罚,只有机器翻译译文长度小于参考答案才会计算惩罚因子。

 

BLEU 

  由于各N-gram统计量的精度随着阶数的升高而呈指数形式递减,所以为了平衡各阶统计量的作用,对其采用几何平均形式求平均值然后加权,再乘以长度惩罚因子,得到最后的评价公式:

  技术分享

  BLEU的原型系统采用的是均匀加权,即Wn=1/N 。N的上限取值为4,即最多只统计4-gram的精度。

 

实例

  译文(Candidate)

Going to play basketball this afternoon ?

  参考答案(Reference)

Going to play basketball in the afternoon ?

  译文gram长度:7  参考答案gram长度:8

  先看1-gram,除了this这个单词没有命中,其他都命中了,因此:

    P1 = 6/7 = 0.85714...

  其他gram以此类推:

    P2 = 4/6 = 0.6666..

    P3 = 2/5 = 0.4

    P4 = 1/4 = 0.25

  再计算logPn,这里用python自带的:

  技术分享

  ∑logPn和为-2.8622 ;再乘以Wn,也就是除以4为 0.7156

  BP = e^(1-8/7)  约等于 0.867 

  BLEU = 0.867 * e^((P1 + P2 + P3 + P4)/4) = 0.867*0.4889 = 0.4238

  本来打算自己实现一个python的代码,结果发现已经有国外小哥做了,拿下来稍微修改了点内容,这里供大家参考

技术分享
#-*- coding:utf-8 -*-
import sys
import codecs
import os
import math
import operator
import json


# 如果是一份答案的话,务必在答案的后面加上.txt   python Bleu.py Candidate ref.txt 
# 如果是多份答案的话,把多份答案放到一个文件夹中  python Bleu.py Candidate 文件夹

def fetch_data(cand, ref):
    """ Store each reference and candidate sentences as a list """
    references = []
    if ‘.txt‘ in ref:
        reference_file = codecs.open(ref, ‘r‘, ‘utf-8‘)
        references.append(reference_file.readlines())
    else:
        for root, dirs, files in os.walk(ref):
            for f in files:
                reference_file = codecs.open(os.path.join(root, f), ‘r‘, ‘utf-8‘)
                references.append(reference_file.readlines())
    candidate_file = codecs.open(cand, ‘r‘, ‘utf-8‘)
    candidate = candidate_file.readlines()
    return candidate, references


def count_ngram(candidate, references, n):
    clipped_count = 0
    count = 0
    r = 0
    c = 0
    for si in range(len(candidate)):
        # Calculate precision for each sentence
        #print si
        ref_counts = []
        ref_lengths = []
        #print references
        # Build dictionary of ngram counts
        for reference in references:
            #print ‘reference‘ + reference
            ref_sentence = reference[si]
            ngram_d = {}
            words = ref_sentence.strip().split()
            ref_lengths.append(len(words))
            limits = len(words) - n + 1
            # loop through the sentance consider the ngram length
            for i in range(limits):
                ngram = ‘ ‘.join(words[i:i+n]).lower()
                if ngram in ngram_d.keys():
                    ngram_d[ngram] += 1
                else:
                    ngram_d[ngram] = 1
            ref_counts.append(ngram_d)
        # candidate
        cand_sentence = candidate[si]
        cand_dict = {}
        words = cand_sentence.strip().split()
        limits = len(words) - n + 1
        for i in range(0, limits):
            ngram = ‘ ‘.join(words[i:i + n]).lower()
            if ngram in cand_dict:
                cand_dict[ngram] += 1
            else:
                cand_dict[ngram] = 1
        clipped_count += clip_count(cand_dict, ref_counts)
        count += limits
        r += best_length_match(ref_lengths, len(words))
        c += len(words)
    if clipped_count == 0:
        pr = 0
    else:
        pr = float(clipped_count) / count
    bp = brevity_penalty(c, r)
    return pr, bp


def clip_count(cand_d, ref_ds):
    """Count the clip count for each ngram considering all references"""
    count = 0
    for m in cand_d.keys():
        m_w = cand_d[m]
        m_max = 0
        for ref in ref_ds:
            if m in ref:
                m_max = max(m_max, ref[m])
        m_w = min(m_w, m_max)
        count += m_w
    return count


def best_length_match(ref_l, cand_l):
    """Find the closest length of reference to that of candidate"""
    least_diff = abs(cand_l-ref_l[0])
    best = ref_l[0]
    for ref in ref_l:
        if abs(cand_l-ref) < least_diff:
            least_diff = abs(cand_l-ref)
            best = ref
    return best


def brevity_penalty(c, r):
    if c > r:
        bp = 1
    else:
        bp = math.exp(1-(float(r)/c))
    
    return bp


def geometric_mean(precisions):
    return (reduce(operator.mul, precisions)) ** (1.0 / len(precisions))


def BLEU(candidate, references):
    precisions = []
    for i in range(4):
        pr, bp = count_ngram(candidate, references, i+1)
        precisions.append(pr)
        print ‘P‘+str(i), ‘ = ‘,round(pr, 2)
    print ‘BP = ‘,round(bp, 2) 
    bleu = geometric_mean(precisions) * bp
    return bleu

if __name__ == "__main__":
    candidate, references = fetch_data(sys.argv[1], sys.argv[2])
    bleu = BLEU(candidate, references)
    print ‘BLEU = ‘,round(bleu, 4)
    out = open(‘bleu_out.txt‘, ‘w‘)
    out.write(str(bleu))
    out.close()
技术分享

 

Perplexity详解:http://blog.csdn.net/luo123n/article/details/48902815


以上是关于机器翻译与自动文摘评价指标 BLEU 和 ROUGE的主要内容,如果未能解决你的问题,请参考以下文章

Metric评价指标-机器翻译指标之BLEU(转载)

机器翻译评价指标之BLEU详细计算过程

机器翻译自动评价之BLEU详解-BLEU: a Method for Automatic Evaluation of Machine Translation

机器翻译自动评价之BLEU详解-BLEU: a Method for Automatic Evaluation of Machine Translation

BLEU评估指标

BLEU评估指标