[机器翻译]—BLEU值的计算

前言

最近还卡在复现工作的结果这一环节上。具体来说,我使用那篇工作提供的脚本,使用的是fairseq-generate来完成的结果的评估。然后我发现我得到的结果和论文中的结果完全不一致。
首先,在预处理阶段,如记一次多语言机器翻译模型的训练所示,我是用moses的tokenizer完成的tokenize,然后又使用moses的lowercase完成的小写化,最后用subword-nmt bpelearn和apply的子词。当然,一方面,小写化不利于模型性能的比较(来自师兄);另一方面,可以使用sentencepiece这一工具来直接学bpe,而不需要做额外的tokenize,但本文暂不考虑。

别人是怎么做的?

这部分内容主要参考:Computing and reporting BLEU scores

考虑以下情况:机器翻译的训练和测试数据,都经过tokenize和truecased的预处理,以及bpe的分词。而在后处理阶段,在保证正确答案(ref)和模型输出(hyp)经过相同的后处理操作的情况下,不同的操作带来的BLEU值是很不同的。如下图所示:
在这里插入图片描述
主要有以下发现:

  1. 【行1vs行2】在bpe级别计算的BLEU值偏高。解释:行1没有采取任何后处理,也就是说,hyp和ref都是tokenized、truecased的bpe子词。此时,由于粒度更细,原本word级别是错误的输出,分成更细粒度的子词,可能就产生“正确”的结果了。
  2. 【行3vs行4】如果不使用sacreBLEU提供的standard tokenization,结果BLEU值偏高。解释:行3没有做detokenize,同时,把sacreBLEU中的standard tokenization也ban掉了;而行4先做了detokenize(行4中的tokenization要理解为detokenize),然后使用了sacreBLEU中的standard tokenization(默认应该是13a tokenizier)。一般来说,行3被称为tokenized BLEU(wrong),行4被称为detokenized BLEU(right)。但是我不知道这两个为什么差别这么大。
  3. 【行5】如果不考虑大小写,也就是完全小写,BLEU值偏高。
  4. 【行6】这一类应该也算是tokenized BLEU,也就是说,它先做了detokenize,只不过在计算BLEU时,又要进行tokenize的时候,使用的是其它第三方的tokenizer而不是sacreBLEU中的tokenizer,这种做法对最终的结果也有影响。

总结:

  • 用SacreBLEU!
  • 在计算BLEU之前,要做好完全的post-preprocess(undo BPE\truecase\detokenize等等)!

我的错误

经过上一部分,可以看到,我的预处理步骤的问题并不大(虽然小写会导致结果偏高),我的问题主要出在,在运行fairseq-generate时,我没有提供bpe\bpe-codes\tokenizer\scoring\post-process参数,也就是说,我没有做任何的post-process。其中,各参数的功能如下:

  • bpe:通过bpe.decode(x)语句来做undo bpe。以bpe=subword_nmt为例,做的就是:(x + " ").replace(self.bpe_symbol, "").rstrip(),其中self.bpe_symbol=@@
  • tokenizer:通过tokenizer.decode(x)语句来做detokenize。以tokenzier=moses为例,做的就是:MosesDetokenizer.detokenize(inp.split())
  • scoring:通过scorer = scoring.build_scorer(cfg.scoring, tgt_dict)语句来建立计算BLEU的对象。如果scoring=‘bleu’(默认),则具体计算的语句为scorer.add(target_tokens, hypo_tokens),其中,target\hypo_tokens是经过一些预处理(可能经过了undo bpe和detokenize,也有可能什么也没做:只是用" "这个分隔符把sentence中所有的tokenized bpe子词连成了一串字符串),得到target\hypo_str之后,再做fairseq提供的简单的tokenize(fairseq/fairseq/tokenizer.py),然后计算BLEU值。而如果scoring=‘sacrebleu’,则具体计算的语句为scorer.add_string(target_str, detok_hypo_str),在这种情况下,如果我们做好了应该做的post-process,target_str就是纯纯的原文本,detok_hypo_str也如此。而在计算BLEU值时,我们又是用的sacrebleu的standard tokenization,可比性会高很多。
  • post-process:这个参数和bpe参数重复

(可能)正确做法

做法一:直接用fairseq-generate计算BLEU值

CUDA_VISIBLE_DEVICES=5 fairseq-generate ../../data/iwslt14/data-bin   --path checkpoints/iwslt14/baseline/evaluate_bleu/checkpoint_best.pt   --task translation_multi_simple_epoch   --source-lang ar   --target-lang en   --encoder-langtok "src"   --decoder-langtok   --bpe subword_nmt   --tokenizer moses   --scoring sacrebleu   --bpe-codes /home/syxu/data/iwslt14/code   --lang-pairs "ar-en,de-en,en-ar,en-de,en-es,en-fa,en-he,en-it,en-nl,en-pl,es-en,fa-en,he-en,it-en,nl-en,pl-en" --quiet

主要就是提供了bpe\bpe-codes\tokenizer\scoring,这四个参数。

做法二:先用fairseq-generate生成,再用sacrebleu评估

另外,也可以不看fairseq-generate提供的BLEU结果,而是利用它生成的hyp.txt和ref.txt文件,然后用sacrebleu工具来计算分数。

用fairseq-generate生成
cat ${genpath} | grep -P "^T" | cut -f 2- > ${refpath}
cat ${genpath} | grep -P "^D" | cut -f 3- > ${hyppath}
sacrebleu ${refpath} -i ${hyppath} -w 2 -b

注意:这里的ref.txt是fairseq-generate生成文件中的T开头的文本,而hyp.txt是fairseq-generate生成文件中的D开头的文本,如下图所示。
在这里插入图片描述

也碰到fairseq提供的一些examples中,它们的hyp.txt用的是生成文件中的H开头的文本,个人觉得不太对,因为H开头的文本只是经过了remove bpe,还没有完成detokenize。(如果它一开始就用sentencepiece来训练bpe的话,这里的H开头的文本应该就是纯文本?—>待确认)

尚存疑问

  • 为什么tokenized\detokenized BLEU差别那么大?----> 师兄说,可能有一些语种,如拉丁字母构成的,这种情况下,tokenized BLEU意味着,使用拉丁字母特有的分词器来进行分词,可能会把文本全部分成字符。
  • fairseq-generate的–sacrebleu有什么用?---->好像没屌用。

参考资料

https://bricksdont.github.io/posts/2020/12/computing-and-reporting-bleu-scores/

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值