使用NLTK sentence_bleu计算中文句子BLEU值返回0的解决办法
解决NLTK sentence_bleu评估中文BLEU分数为0的问题
问题现象
使用NLTK的sentence_bleu()计算中文句子的BLEU分数时,结果始终为0,即使添加平滑方法也无效。但使用SacreBLEU的corpus_score()能得到正常结果(BLEU=4.79)。
错误原因
参数格式不符合NLTK要求
NLTK的sentence_bleu对输入格式有严格要求:references:必须是参考译文的列表,每个参考是分词后的token列表(支持多参考,格式为[[ref1_tokens], [ref2_tokens], ...])hypothesis:必须是单个假设译文的token列表,而非字符串列表
你当前传入的是模型生成后的字符串和字符串列表,完全不符合格式要求。
错误的参考分词方式
你用model.generate()处理参考句子来获取分词结果,这是完全错误的——generate是文本生成接口,不是分词工具,导致参考文本被错误处理(从SacreBLEU输出的ref_len=1可看出,参考被处理成了长度为1的无效token序列)。未正确处理中文分词
中文句子必须先分词为token序列才能计算BLEU,直接使用整句字符串会导致计算逻辑完全错误。
解决方案
修正步骤
- 使用正确的分词工具(模型自带的tokenizer或jieba)对参考和假设句子进行分词,得到token列表。
- 按照NLTK要求的格式传入参数。
- 配合平滑函数解决短句子或低匹配度导致的0分问题。
修正后的完整代码
import nltk from nltk.translate.bleu_score import SmoothingFunction from transformers import BertTokenizer, BartForConditionalGeneration from sacrebleu.metrics import BLEU src = '樓上漏水耍花招不處理可以怎麼做' ref = '上層漏水耍手段不去處理可以怎麼做' checkpoint = 'fnlp/bart-base-chinese' tokenizer = BertTokenizer.from_pretrained(checkpoint) model = BartForConditionalGeneration.from_pretrained(checkpoint) # 生成假设译文 hypothesis_str = "" inputs = tokenizer(src, return_tensors="pt", truncation=True, max_length=100, return_token_type_ids=False) outputs = model.generate(**inputs) hypothesis_str = tokenizer.decode(outputs[0], skip_special_tokens=True) # 正确分词:使用模型tokenizer保证分词一致性 # 参考译文格式:[[ref_tokens]](支持多参考,单参考时外层套列表) ref_tokens = tokenizer.tokenize(ref) references = [ref_tokens] # 假设译文格式:单个token列表 hypothesis_tokens = tokenizer.tokenize(hypothesis_str) # 带平滑计算BLEU smooth_fn = SmoothingFunction() nltk_bleu = nltk.translate.bleu_score.sentence_bleu( references, hypothesis_tokens, smoothing_function=smooth_fn.method3 ) print(f"NLTK BLEU分数: {nltk_bleu * 100:.2f}") # 对比SacreBLEU结果 bleu = BLEU() bleu_score = bleu.corpus_score(references=[[ref]], hypotheses=[hypothesis_str]) print(bleu_score)
代码说明
- 用模型的
tokenizer.tokenize()分词,保证和生成文本的分词逻辑一致;也可以替换为jieba分词,但需注意分词一致性。 - 参考译文传入格式为
[[ref_tokens]],满足NLTK多参考的参数要求。 - 假设译文传入单个token列表,而非字符串列表。
- 使用平滑方法3解决低匹配度场景下的0分问题,避免因某阶n-gram完全不匹配导致整体分数为0。
验证结果
运行修正后的代码,NLTK会输出接近SacreBLEU的分数(两者计算细节略有差异,但不会再出现0分)。
内容的提问来源于stack exchange,提问作者Raptor
相关产品推荐
相关产品推荐

