Metric扩展开发:集成BERTScore与CHRF++
在大模型时代,我们越来越难用“这个句子有没有出错”来评判一个生成结果的好坏。比如,当模型回答“中国的首都是北京”,而标准答案是“北京是中国的首都”时,人类一眼就能看出语义一致,但传统BLEU指标可能因词序不同给出近乎零分。这种“明明说对了却不得分”的尴尬,暴露了基于n-gram匹配的评估体系的根本局限。
正是在这种背景下,像BERTScore和CHRF++这样的新一代自动评测指标应运而生。它们不再拘泥于字面匹配,而是尝试从语义相似性和结构保真度两个维度,更贴近人类判断地量化生成质量。魔搭社区的ms-swift框架作为支持600+纯文本与300+多模态大模型的一站式开发平台,其评测模块 EvalScope 提供了强大的插件化机制,使得集成这些先进 metric 成为可能——不仅可行,而且高效。
BERTScore:让评估“理解”语义
如果把传统指标比作只会查重的阅卷机,那 BERTScore 更像是一个懂得上下文含义的助教。它的核心思想很直观:即使词汇不完全重合,只要语义接近,在预训练语言模型的向量空间里就应该靠得近。
具体来说,BERTScore 利用 BERT、RoBERTa 等模型提取候选句和参考句中每个词的上下文嵌入(contextual embeddings),然后计算词与词之间的余弦相似度。对于候选句中的每一个词,它都会在参考句中寻找最相似的那个词作为匹配对象,取最大值构成 Precision;反过来也计算 Recall。最终通过 F1 分数综合两者,并引入 IDF 权重降低高频虚词(如“的”、“是”)的影响。
这一机制带来了几个关键优势:
- 它能识别同义替换:“强大” vs “厉害”、“首都” vs “政治中心”;
- 它容忍句式变换:“A 是 B” 与 “B 属于 A” 在语义上等价;
- 它依赖的是上下文化表示,避免了 Word2Vec 静态词向量“一词多义”带来的歧义问题。
更重要的是,多项研究证实,BERTScore 与人工评分的相关性显著高于 BLEU 或 ROUGE,尤其在摘要生成和对话系统任务中表现突出。以中文为例,使用bert-base-chinese模型即可实现高质量的语义对齐。
下面是一个轻量封装示例,可直接用于ms-swift的自定义 metric 注册:
from bert_score import score def compute_bertscore(candidates, references): """ 计算 BERTScore Args: candidates: List[str], 生成文本列表 references: List[str], 参考文本列表 Returns: precision, recall, f1: Tensor, 平均得分 """ P, R, F1 = score( cands=candidates, refs=references, lang='zh', model_type='bert-base-chinese', verbose=False ) return P.mean().item(), R.mean().item(), F1.mean().item() # 示例调用 candidates = ["这是一个生成的句子。"] references = ["这是一个人工撰写的参考句。"] p, r, f = compute_bertscore(candidates, references) print(f"BERTScore - P: {p:.4f}, R: {r:.4f}, F: {f:.4f}")需要注意的是,BERTScore 的计算开销相对较大,因为它本质上是在做一次完整的 BERT 推理。因此在实际工程部署中建议采用以下优化策略:
- 启用批量处理(batching)并优先使用 GPU 加速;
- 对固定参考集的 embeddings 进行缓存,避免重复编码;
- 在大规模评测时可考虑采样部分样本进行趋势监控,而非全量计算。
此外,选择合适的底层模型也至关重要。例如在专业领域任务中,使用领域微调过的 BERT 模型(如医学、法律)往往比通用模型更能反映语义一致性。
CHRF++:字符级精细结构捕捉
如果说 BERTScore 解决的是“说什么”的问题,那么 CHRF++ 更关注的是“怎么说”——即生成文本在拼写、形态和局部结构上的准确性。这对于中文这类无空格分隔的语言尤为关键。
CHRF++ 是原始 CHRF 指标的增强版,其全称是Character n-gram F-score ++。它最大的特点是:无需分词,直接在字符序列上操作。这意味着它完全规避了中文分词工具带来的误差传播问题。同时,它还引入了词边界建模(word boundary indicators)和词序敏感性(word order sensitivity),使其不仅能捕捉字符匹配程度,还能感知词语组合的合理性。
其工作流程如下:
- 将候选句和参考句拆分为字符流;
- 提取长度从 1 到 N 的连续字符 n-gram(通常 N=6);
- 统计匹配的 n-gram 数量,计算 Precision 和 Recall;
- 使用 F-score 融合二者,并通过参数 β 控制对召回率的偏好;
- 引入词边界信息作为修正项,提升对词汇结构的敏感性。
公式简化表达为:
$$
\text{CHRF}^{++} = \max(F_\text{char}, w \cdot F_\text{word})
$$
其中 $F_\text{word}$ 是融合了词边界的加权项。
这使得 CHRF++ 在多种场景下表现出更强的鲁棒性。例如面对错别字或打字错误:
- 生成句:这个馍型很强打
- 参考句:这个模型很强大
尽管有两个错字,“馍”代替“模”,“打”代替“大”,但由于其余字符高度匹配,CHRF++ 仍能获得一个合理的分数,体现出一定的容错能力。相比之下,BLEU 会因为“词”不匹配而几乎不得分。
再比如在少数民族语言或低资源语言(如藏语、维吾尔语)中,缺乏成熟分词工具的情况下,CHRF++ 几乎是唯一可行的自动化评估方案之一。
其实现可通过sacrebleu库简洁完成:
from sacrebleu import sentence_chrf def compute_chrfpp(candidates, references): """ 计算 CHRF++ 得分 Args: candidates: str or List[str], 生成文本 references: str or List[List[str]], 参考文本(可多个) Returns: chrf_score: float, CHRF++ 分数 """ scores = [] for cand, refs in zip(candidates, references): if isinstance(refs, str): refs = [refs] score = sentence_chrf(hypothesis=cand, references=refs, word_order=2, beta=2) scores.append(score.score) return sum(scores) / len(scores) # 示例调用 candidate = "这个模型很强大" reference = "这个模型非常强大" chrfpp = compute_chrfpp([candidate], [[reference]]) print(f"CHRF++ Score: {chrfpp:.4f}")这里的关键参数word_order=2表示启用两阶词序建模,是 CHRF++ 区别于基础 CHRF 的核心所在。beta=2则增强了对召回率的重视,适合强调内容完整性的任务。
实战集成:在ms-swift中构建统一评测体系
在ms-swift框架中,metric 扩展并非孤立功能,而是深度融入整个评测流水线的一部分。其架构设计充分体现了模块化与可插拔的思想:
[用户输入] ↓ [评测任务配置] → [数据加载器] → [模型推理模块] ↓ [生成文本] ———→ [参考文本] ↓ [Metric Registry] ← 注册自定义 metric ↙ ↘ BERTScore Plugin CHRF++ Plugin ↘ ↙ → [汇总报告生成] ↓ [可视化输出]开发者只需继承BaseMetric类,实现compute()方法,即可将上述指标注册为独立组件。框架会在运行时自动调度,并与其他 metric(如 BLEU、ROUGE)并行计算,最终输出统一格式的评测报告。
典型接入方式如下:
from swift.eval import Evaluator, BERTScoreMetric, ChrFPlusPlusMetric evaluator = Evaluator( model='qwen', dataset='cmrc2018', metrics=[ BERTScoreMetric(lang='zh', model_type='bert-base-chinese'), ChrFPlusPlusMetric(n_char_order=6, n_word_order=2) ] ) results = evaluator.run() print(results)这样的设计带来了极大的灵活性。你可以根据不同任务动态组合指标:
- 在机器翻译任务中,同时启用 BERTScore(语义) + CHRF++(结构) + BLEU(通用基准);
- 在对话系统中,侧重 BERTScore 和语义多样性指标;
- 在代码生成中,则可以结合语法正确性检查与字符级精确匹配。
当然,在实际应用中也需要一些经验性的权衡:
- 性能与精度平衡:BERTScore 虽准但慢,是否开启需根据评测规模决定。对于每日迭代的训练任务,可仅在验证集上定期跑一次完整评估;
- 多指标融合策略:不要单一依赖某一项得分。建议建立加权评分体系,例如
(0.4 × BERT-F1) + (0.3 × CHRF++) + (0.3 × BLEU),形成综合排名依据; - 版本一致性保障:确保 tokenizer、embedding 模型与训练阶段一致,防止因前后端差异导致评估偏差;
- 缓存与复用机制:对参考文本的 embeddings 或 n-gram 特征进行缓存,大幅减少重复计算开销。
更进一步:为什么我们需要多样化的评估视角?
一个值得深思的问题是:有没有一种“万能”的自动评估指标?
答案恐怕是否定的。每种 metric 都有其擅长的“战场”。BLEU 擅长检测词汇覆盖,CHRF++ 敏感于局部结构变形,BERTScore 把握整体语义连贯性。就像医生不会只看体温判断病情,我们也必须从多个维度审视模型输出。
举个例子,在摘要任务中:
- 模型生成:“科学家发现新药可有效抑制肿瘤生长。”
- 参考文本:“研究人员研发出一种新型药物,能够显著减缓癌症发展。”
BLEU 可能因关键词不完全重叠而扣分;
CHRF++ 因“抑/制/肿/瘤”与“减/缓/癌/症”部分字符匹配仍能得分;
BERTScore 则能识别“科学家≈研究人员”、“新药≈新型药物”、“肿瘤生长≈癌症发展”的语义对应关系,给出高分。
三者结合,才能还原一个完整的评估图景。
这也正是ms-swift构建插件化评测体系的深层价值:它不追求“唯一真理”,而是提供一套灵活工具链,让开发者可以根据任务特性自由搭配“评估滤镜”。
结语
将 BERTScore 与 CHRF++ 集成进ms-swift,不只是增加了两个数字输出那么简单。它代表着模型评估正从“表面匹配”走向“深层理解”的范式转变。
BERTScore 让我们第一次真正意义上用向量空间去度量“意思是不是一样”;CHRF++ 则在不分词的前提下实现了对中文等语言的精细化结构评估。两者互补,构成了当前中文生成任务中最实用的一组自动评测组合。
未来,随着 MoverScore、Prism、UniEval 等更复杂的语义评估方法不断涌现,这套插件化架构将持续释放潜力。我们可以预见,一个更加智能、多层次、贴近人类感知的自动评测体系正在成型——而这,正是推动大模型从“能说”走向“说得好”的关键一步。