第七周做序列标注(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,571 | 48.7% | 2.36 字 |
| ORG 机构名 | 9,277 | 27.3% | 5.06 字 |
| PER 人名 | 8,144 | 24.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 赢了,但赢得很微妙
| 类型 | Linear | CRF | 差值 |
|---|---|---|---|
| 整体 | —— | —— | +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 里召回和精排两阶段的理论基础。