1. BLEU计算
评价机器翻译结果通常使⽤BLEU来评价,对于模型预测序列中任意的⼦序列,BLEU考察这个⼦序列是否出现在标签序列中。
具体来说,设词数为
n的⼦序列的精度为
pn,他是预测序列_与_标签序列_匹配词数为
n的子序列的数量_与_预测序列中词数为
n 的_子序列的数量之比。
举个例子,假设标签序列为A, B, C, D, E, F,预测序列为A, B, B, C, D,那么
p1=4/5,
p2=3/4,
p3=1/3,p4=0。 另
lenlabel和
lenpred分别为标签序列和预测序列的词数,那么BLEU的定义为:
BLEU=exp(min(0,1−lenpred lenlabel ))n=1∏kpn1/2n
其中
k是我们希望匹配的子序列的最大词数(或者说是n-gram中的n),可以发现当预测序列和标签序列完全一致时BLEU值为1。
因为匹配较⻓⼦序列⽐匹配较短⼦序列更难,BLEU对匹配较⻓⼦序列的精度赋予了更⼤权重。例如,当
pn固定为0.5时, 随着n增大,
0.51/2≈0.7,0.51/4≈0.84,0.51/8≈0.92,0.51/16≈0.96 。
另外,模型预测较短序列往往会得到较⾼
pn值。因此,上式中连乘项前⾯的系数是为了惩罚较短的输出⽽设置的。例如,当
k=2时,假设标签序列为A, B, C, D, E, F,而预测序列为A, B。虽然
p1=p2=1,但是惩罚系数
exp(1−6/2)≈0.14, 因此BLEU结果接近0.14
2. 注意
BLEU计算公式很多地方会给出如下形式:
BLEU=BPexp(n=1∑Nwnlogpn)其中
BP={1e(1−r/c)if c>rif c≤r
c是预测序列的长度,
r是标签序列的长度
该公式和上面的公式其实是一样的,此处的
BP就相当于上面的
exp(min(0,1−lenpredlenlabel )),剩下部分推导如下:
exp(n=1∑Nwnlnpn)=n=1∏Nexp(ωnlnpn)=n=1∏Nexp(lnpnwn)=n=1∏Npnwn其中
ωn=2n1
BLEU的取值范围是[0,1],0最差,1最好;在第1节公式中
k一般取4左右,一般不大于4
3.BLEU编程实现
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
if __name__ == '__main__':
import math
import collections
score = bleu(['The', 'cat', 'sat', 'on', 'the', 'mat'], ['The', 'cat', 'is', 'on', 'the', 'mat'], 3)
print(score)
输出:
0.6756000774035172
[Finished in 0.1s]
注意k值不能取太大