My Blog
Agent 学习

Agent 学习第 7 周:序列标注,CRF 到底带来了什么

用 BERT + CRF 做中文 NER:为什么必须用实体级 F1,以及 CRF 的 +0.58pp 到底算不算赢。

发布于 2026/9/11更新于 2026/9/11阅读约 12 分钟
只问这篇文章 →

第七周做序列标注(NER)。和上周的文本分类比,这周有个本质区别:

文本分类:一条样本 → 一个标签
序列标注:一条样本 → 一串标签,每个字都要预测,而且标签之间有强依赖

作业是在 peoples_daily 中文语料上训 NER,跑了三条路线:BERT + Linear、BERT + CRF、以及 LLM 路线。


一、标签之间的依赖是这周所有设计的出发点

先看一条样本:

原文    海 钓 比 赛 地 点 在 厦 门 与 金 门 之 间 的 海 域 。
标签    O  O  O  O  O  O  O  B-LOC I-LOC O B-LOC I-LOC O O O O O O
                              └─厦门─┘   └─金门─┘

关键在于:I-LOC 只能跟在 B-LOC 或 I-LOC 后面,不能凭空出现。

这个约束是本周所有内容的出发点——因为如果每个位置独立预测,模型完全可能输出 O I-LOC O 这种非法序列。


二、NER 的本质被我误解了

这周最大的认知更新来自课上的一句话:

NER 的本质是一个通用 span 分类器,与具体实体类型无关。

我原来的理解:NER 就是识别人名、地名、机构名,类型是固定的三四种。

课上纠正:

常见误解正确理解
只能识别人名地名机构名实体 = 任意业务关心的文本 span
实体类型是固定的类型由业务需求自由定义
只有专有名词才算实体可以是术语、属性、数值、事件
不同业务要用不同方法思路永远是「定义 → 标注 → 训练」

模型学到的是「给定上下文,判断一段连续 token 是否属于目标类别」,这个能力与类别叫什么名字无关。同一套 BERT + CRF 框架,换标注数据就能迁移到医疗、金融、法律任何领域。

这个视角一下子把 NER 的适用范围扩大了很多——它其实是个通用信息抽取框架。


三、标注体系的选择

体系优点缺点
BIO简洁、标签少单字实体与多字实体的 I 容易混
BIOES边界明确、单字有 S标签数翻倍,标注更复杂
IO最简单只有 2 类无法区分相邻的同类实体

设计原则:类别数不宜过多(>20 类会显著增加难度)。

我用的是 BIO,3 类实体(LOC/ORG/PER)共 7 个标签(O + 3×2)。


四、数据先看一遍

              训练集    验证集
句数          20,864    2,318
含实体的句子   60.9%     60.4%
实体总数      33,992     3,819

实体分布:

类型数量占比平均长度
LOC 地名16,57148.7%2.36 字
ORG 机构名9,27727.3%5.06 字
PER 人名8,14424.0%2.95 字

ORG 平均 5.06 字,是 LOC 的两倍多。 记住这个数——后面三个模型在 ORG 上全都表现最差,根源就在这里:实体越长,边界越难判准,而实体级评估要求边界完全正确。

训练集和验证集的分布高度一致(48.7/27.3/24.0 vs 51.1/25.8/23.1),说明划分是可靠的。


五、为什么不能用准确率

这是这周方法论上最重要的一点。

序列标注的 token 里 90% 以上都是 O。一个「全部预测 O」的模型 token 准确率就有 0.9,但一个实体都没找到。

所以必须用实体级 F1:

一个实体的边界和类型都完全正确才算命中。预测出「厦门市」而答案是「厦门」算全错——既是一个假阳性又是一个假阴性,不给部分分。

这个评估口径比模型本身更值得记。指标选错了,再好的模型也看不出好坏。


六、CRF 到底带来了什么

结构

BERT → Dropout → Linear(768, 7) → CRF

线性层的输出不再直接 argmax,而是当作发射分数,CRF 在其上叠加一个 7×7 的转移矩阵(含起始/结束共 63 个参数),用 Viterbi 算法找全局最优路径。

直觉上:Linear 是「每个位置各自猜」,CRF 是「考虑标签之间的转移概率,找一整条最合理的路径」。

一个容易踩的坑

CRF 的 loss 和线性头不在一个尺度上,不能直接比大小。

线性头是逐 token 交叉熵的平均值,CRF 是整条序列的负对数似然(一条 128 长的序列累加出来的数)。看 CRF 训得好不好只能看 F1 和它自己的趋势。

我一开始看到 CRF 的 loss 是个大得多的数字,还以为训崩了。

结果:CRF 赢了,但赢得很微妙

类型LinearCRF差值
整体————+0.58pp

3,657 个实体的标准误约 sqrt(0.95×0.05/3657) ≈ 0.36%,+0.58pp 约 1.6 个标准误——单看这一个数不算显著。

但三类实体的方向全部一致(CRF 在 LOC/ORG/PER 上都略优),所以可以认为 CRF 确实略好。

一个关于样本量的教训

我还在 300 条的子集上跑过一次,CRF 只赢 0.11pp,而且 ORG 反而更差。

小样本上的差异不可信,必须看全量。

这条经验后来在别的实验里救过我好几次——看到一个「有趣的差异」,先问样本量够不够。


这周的收获

1. 指标决定你能看见什么。

token 准确率会让「全预测 O」的废物模型看起来有 0.9 分。换成实体级 F1,废物模型立刻现原形。 选对指标比选对模型更靠前。

2. 数据分布能预测模型的弱点。

ORG 平均 5.06 字(其他两类 2~3 字)→ 三个模型在 ORG 上全都最差。看完数据统计,我在跑模型之前就知道哪一类会拉胯。

3. 效果差异要放在统计误差里看。

+0.58pp 到底算不算赢?要看标准误、要看方向是否一致、要看样本量够不够。不做这个判断,就会把噪声当成结论。

下周是文本匹配——双塔 vs 交互式,这是 RAG 里召回和精排两阶段的理论基础。

相关文章