PaddleNLP 拼写纠错评估指标详解:DetectionF1 与 CorrectionF1(SIGHAN 评测体系)
2026/9/24 4:40:10 网站建设 项目流程
  • 人工智能
  • 大模型
  • 预训练
  • 微调
  • LoRA
  • RLHF
  • 强化学习
  • 分布式训练

【免费下载链接】PaddleNLP

Easy-to-use and powerful LLM and SLM library with awesome model zoo.

项目地址:https://gitcode.com/gh_mirrors/pa/PaddleNLP
点击查看免费下载

导读

本文聚焦 PaddleNLP 中面向中文拼写纠错(Chinese Spelling Correction, CSC)任务的专用评估模块 paddlenlp.metrics.sighan。该模块基于 SIGHAN 系列评测(如 SIGHAN 2015 中文拼写纠错任务)的评测口径,提供了错误检测纠错结果两套 F1 指标实现。读完本文,你将掌握DetectionF1CorrectionF1的统计逻辑、与 Paddle 训练框架的接入方式,以及它们与paddle.metric.Metric基类之间的关系。

一、模块定位:SIGHAN 评测任务与指标语义

paddlenlp.metrics.sighan对应 PaddleNLP 文档中sighan这个 API 页面(见 paddlenlp.metrics.sighan.rst),是paddlenlp.metrics指标族中面向中文拼写纠错场景的一员。

  • SIGHAN 是什么:SIGHAN(Special Interest Group on Chinese Language Processing)是 NLP 领域的评测组织,其举办的拼写纠错评测任务(如 SIGHAN 2013/2014/2015 Bake-off)为中文拼写纠错提供了标准数据集与评估口径。PaddleNLP 的该模块即按照“一句文本中是否存在错误、错误位置/纠错结果是否正确”的逐句(sequence-level)方式统计。
  • 与其它指标的区别paddlenlp.metrics下既有 BLEU、Rouge、Perplexity 等生成式指标,也有 ChunkEvaluator、SpanEvaluator 等结构化预测指标;而sighan模块专门服务于“检测 + 纠正”两阶段输出的拼写纠错模型。
  • 导出方式:模块通过__all__ = ["DetectionF1", "CorrectionF1"]对外暴露两个类,并在 paddlenlp/metrics/init.py 中随包整体导出(from .sighan import CorrectionF1, DetectionF1),因此用户可以直接from paddlenlp.metrics import DetectionF1, CorrectionF1

两个指标均继承自paddle.metric.Metric(sighan.py),天然支持update / reset / accumulate / name的标准生命周期,可无缝接入 PaddleNLP Trainer 的评估回调。

二、DetectionF1:错误检测阶段的句子级 F1

DetectionF1用于评估模型是否把一句话识别为包含拼写错误,即“检测任务”(Detection)。其核心思想是逐句(以 batch 中每条样本为单位)判定一次“检出/漏检/误检”,再汇总为精确率、召回率与 F1。

2.1 初始化

class DetectionF1(Metric): def __init__(self, pos_label=1, name="DetectionF1", *args, **kwargs): super(DetectionF1, self).__init__(*args, **kwargs) self.pos_label = pos_label self._name = name self.reset()
  • pos_label:表示“该位置存在错误”的标签值,默认1,对应检测头二分类中的正类(正确字符通常为0)。
  • name:指标实例名称,默认"DetectionF1",可在日志与回调中区分不同指标。
  • 构造末尾调用reset()清零内部统计量。

2.2 update:逐句累计 TP / FP / FN

def update(self, preds, labels, length, *args): # [B, T, 2] pred_labels = preds.argmax(axis=-1) for i, label_length in enumerate(length): pred_label = pred_labels[i][1 : 1 + label_length] label = labels[i][1 : 1 + label_length] # the sequence has errors if (label == self.pos_label).any(): if (pred_label == label).all(): self.tp += 1 else: self.fn += 1 else: if (label != pred_label).any(): self.fp += 1

输入语义(对应 Paddle Metric 协议中的update(output, label, ...)):

  • preds:形状为[B, T, 2]的检测头 logits/概率分布,argmax(axis=-1)后得到[B, T]的预测标签;
  • labels:形状为[B, T]的检测标签(0/1),1 表示该 token 位置为错误;
  • length:每条样本的真实序列长度(不含 padding),用于对齐。

逐句统计规则(关键实现细节):

  1. 忽略[CLS]与 padding:切片从位置1开始(1 : 1 + label_length),即跳过[CLS]标记,只统计真实 token 区间,[SEP]/padding 不参与统计;
  2. 真实含错(label 中存在 1):若预测标签与真实标签完全一致(pred_label == label).all()),记为 TP;否则记为 FN(整句漏检或检错位置不匹配都算漏检);
  3. 真实无错(label 全为 0):只要预测中出现任意一个 1((label != pred_label).any()),就记为 FP(误报)。

注意:这里采用**句子级(sequence-level)**判定,即“这一句有没有被正确检测”,而不是按 token 粒度统计,这与 SIGHAN 评测中以句子为单位的报告口径一致。

2.3 accumulate:汇总精确率、召回率与 F1

def accumulate(self): precision = np.nan if self.tp + self.fp > 0: precision = self.tp / (self.tp + self.fp) recall = np.nan if self.tp + self.fn > 0: recall = self.tp / (self.tp + self.fn) if self.tp == 0: f1 = 0.0 else: f1 = 2 * precision * recall / (precision + recall) return f1, precision, recall
  • Precision=TP / (TP + FP):检出的句子中真实含错的比例;
  • Recall=TP / (TP + FN):真实含错句子中被正确检出的比例;
  • F1=2 * P * R / (P + R);当TP == 0时 F1 直接取0.0(避免除零),当分母为 0 时 P/R 返回np.nan

返回值顺序为(f1, precision, recall),在 Trainer 中通常取f1作为监控指标。

2.4 reset 与 name

  • reset()tp / fp / fn全部归零,供新一轮 epoch 评估复用;
  • name()返回构造时传入的name(默认"DetectionF1"),用于日志展示。

三、CorrectionF1:纠错阶段的联合 F1

CorrectionF1继承自DetectionF1(sighan.py),用于评估纠错模型给出的最终纠错结果是否正确——即不仅要求“检测出错误”,还要求“改对了”。它同时消费检测头与纠错头的输出。

3.1 初始化

class CorrectionF1(DetectionF1): def __init__(self, pos_label=1, name="CorrectionF1", *args, **kwargs): super(CorrectionF1, self).__init__(pos_label, name, *args, **kwargs)

复用父类的pos_label(默认1)与reset/accumulate/name逻辑,只重写update,默认指标名"CorrectionF1"

3.2 update:检测 × 纠错的联合判定

def update(self, det_preds, det_labels, corr_preds, corr_labels, length, *args): # [B, T, 2] det_preds_labels = det_preds.argmax(axis=-1) corr_preds_labels = corr_preds.argmax(axis=-1) for i, label_length in enumerate(length): # Ignore [CLS] token, so calculate from position 1. det_preds_label = det_preds_labels[i][1 : 1 + label_length] det_label = det_labels[i][1 : 1 + label_length] corr_preds_label = corr_preds_labels[i][1 : 1 + label_length] corr_label = corr_labels[i][1 : 1 + label_length] # The sequence has any errors. if (det_label == self.pos_label).any(): corr_pred_label = corr_preds_label * det_preds_label corr_label = det_label * corr_label if (corr_pred_label == corr_label).all(): self.tp += 1 else: self.fn += 1 else: if (det_label != det_preds_label).any(): self.fp += 1

输入包含四路张量(均为[B, T, 2]的 logits/概率分布):

  • det_preds/det_labels:检测头预测与真实标签;
  • corr_preds/corr_labels:纠错头预测与真实纠错标签;
  • length:每条样本真实长度。

判定逻辑(逐句):

  1. 统一忽略[CLS],从位置1切片到1 + label_length
  2. 真实含错(det_label 中存在 1):通过逐元素乘法corr_pred_label = corr_preds_label * det_preds_labelcorr_label = det_label * corr_label实现“掩码”——只在检测为错误的位置上比较纠错结果(预测与标签都在错误位置置 1 的位置才保留数值)。若掩码后的预测与标签完全一致,记 TP,否则记 FN。这一设计的含义是:只有“错误位置找对且该位置改对”才算整句纠错成功
  3. 真实无错:与DetectionF1一致,预测中若出现任何错误位置则记 FP。

从源码结构看,corr_preds_label * det_preds_label这种乘法掩码保证:模型在非错误位置即使输出了纠错标签也不参与比较,只有检测为错的位置上的纠错结果才被计入,实现了“检测 + 纠正”两阶段联合打分。

3.3 指标输出

由于accumulate()reset()name()均继承自父类,CorrectionF1同样返回(f1, precision, recall),且f1TP == 0时为0.0

四、在训练与评估中如何接入

4.1 使用 PaddleNLP Metric 标准协议

两个类都遵循paddle.metric.Metric的接口约定(update / reset / accumulate / name)。在 PaddleNLP Trainer 中,将指标实例传入compute_metrics回调即可:

from paddlenlp.metrics import DetectionF1, CorrectionF1 det_metric = DetectionF1(pos_label=1, name="DetectionF1") corr_metric = CorrectionF1(pos_label=1, name="CorrectionF1") def compute_metrics(eval_preds): # eval_preds 包含模型输出与标签,按 update 的形参顺序组织: # DetectionF1: (preds, labels, length) # CorrectionF1: (det_preds, det_labels, corr_preds, corr_labels, length) det_metric.update(preds, det_labels, length) corr_metric.update(det_preds, det_labels, corr_preds, corr_labels, length) det_f1, det_p, det_r = det_metric.accumulate() corr_f1, corr_p, corr_r = corr_metric.accumulate() det_metric.reset() corr_metric.reset() return { "DetectionF1": det_f1, "DetectionPrecision": det_p, "DetectionRecall": det_r, "CorrectionF1": corr_f1, "CorrectionPrecision": corr_p, "CorrectionRecall": corr_r, }

4.2 输入张量的形状要求

参数形状含义
preds/det_preds/corr_preds[B, T, 2]对应头的 logits 或概率,最后一维做argmax得到标签
labels/det_labels/corr_labels[B, T]真实标签(0/1),1表示错误(pos_label
length[B]或 list每条样本真实长度,用于剔除[CLS]与 padding

注意update的形参顺序即调用顺序:DetectionF1.update(preds, labels, length)CorrectionF1.update(det_preds, det_labels, corr_preds, corr_labels, length);Batch 内各样本需按length对齐,超出1 + label_length的位置不参与统计。

五、实现要点与边界情况总结

  1. 句子级统计而非 token 级DetectionF1的 TP/FN/FP 均以整句为单位累计,与 SIGHAN 评测的句级口径一致;逐 token 的准确率不在此模块覆盖范围内。
  2. 首位置约定:切片从1开始,假定序列首位是[CLS]且不参与评测;如果模型输入首位不是[CLS],需要自行对齐该约定。
  3. 除零保护accumulate()对分母为零的情况分别处理——无 TP 时 F1 为0.0,P/R 分母为零时返回np.nan,不会抛异常。
  4. 联合掩码设计CorrectionF1用乘法掩码把检测结果与纠错结果绑定,天然惩罚“检错位置错”的样本,是检测与纠正联合评测的简洁实现。
  5. 继承与复用CorrectionF1只重写update,其余生命周期方法继承自DetectionF1,代码结构清晰,便于维护与扩展。

六、相关资源

  • 指标实现源码:paddlenlp/metrics/sighan.py
  • 指标统一导出:paddlenlp/metrics/init.py
  • 文档索引页:docs/zh/source/paddlenlp.metrics.sighan.rst
  • 同目录下其它可复用指标:paddlenlp/metrics/(含 bleu.py、rouge.py、chunk.py、span.py 等)

在实现中文拼写纠错模型时,将DetectionF1CorrectionF1同时接入评估流程,即可分别报告“检测能力”与“最终纠错能力”两套指标,完整对齐 SIGHAN 评测任务的核心评测维度。

  • 人工智能
  • 大模型
  • 预训练
  • 微调
  • LoRA
  • RLHF
  • 强化学习
  • 分布式训练

【免费下载链接】PaddleNLP

Easy-to-use and powerful LLM and SLM library with awesome model zoo.

项目地址:https://gitcode.com/gh_mirrors/pa/PaddleNLP
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询