1.4 序列标注
NER、POS tagging、Chunking;BIO / BIOES 标注方案;HMM / CRF 与神经网络的结合;LLM 时代零样本 NER 的局限
从"整句分类"到"逐字打标签"
上一节讲的文本分类是把整段文本映射到一个标签。本节讲序列标注(Sequence Labeling)——给句子里的每一个 token 都分配一个标签。
这类任务在工业界极其重要但在大模型热潮下有些被遗忘:
- 命名实体识别(NER, Named Entity Recognition):从一段文本中抽出"人名 / 地名 / 机构 / 时间 / 金额"等
- 词性标注(POS Tagging, Part-of-Speech):为每个词打上"名词 / 动词 / 形容词"等
- 组块分析(Chunking):把连续的词切成短语(名词短语、动词短语)
- 事件抽取 / 关系抽取:NER 的延伸——不只是实体,还要抽取实体间的关系
信息抽取(IE)、知识图谱构建、医疗电子病历结构化、法律合同审查、RAG 系统的元数据提取——每一个落地场景背后都有 NER 在支撑。
核心问题:如何把"序列"变成"标签序列"?
给定句子:
北京 大学 位于 海淀区 中关村NER 任务希望输出:
北京大学 → ORG
海淀区 → LOC
中关村 → LOC模型需要同时解决两个子问题:
- 边界识别:"北京" 和 "大学" 应该合并为一个机构名,而不是两个独立的地名
- 类型分类:识别出的片段属于哪一类实体
这里的难点:模型是逐 token 做预测的,如何让它输出"跨越多个 token 的实体"?这就是 BIO 标注方案要解决的事。
BIO 与 BIOES 标注
BIO 方案(最常用)
- B-X:实体 X 的开始(Begin)
- I-X:实体 X 的中间或末尾(Inside)
- O:不属于任何实体(Outside)
上面例子在 BIO 下变成:
| token | 北京 | 大学 | 位于 | 海淀区 | 中关村 |
|---|---|---|---|---|---|
| BIO 标签 | B-ORG | I-ORG | O | B-LOC | B-LOC |
这样,NER 就被转化为标准的 token 级分类问题——每个 token 在 类标签(2N+1 类,N 为实体类型数)中选一个。
BIOES 方案(更精细)
BIOES 在 BIO 基础上加两个标签:
- E-X:实体 X 的结束(End)
- S-X:单 token 实体(Single)
好处:明确区分"实体末尾"与"实体中间",让模型的边界学习信号更强。代价:标签数翻倍,小数据集上反而容易过拟合。
BIO vs BIOES 的选择:学术 benchmark 上 BIOES 常略优,但差距通常 < 1%。工业界大多数用 BIO,简单且便于调试。关键是训练与评估使用的方案必须一致——混用会导致灾难。
建模演化:从 HMM 到 BERT + CRF
HMM 与 CRF 时代(2000-2015)
序列标注的核心特点:相邻标签之间有强约束。B-PER 后面不可能直接跟 I-LOC,独立逐 token 预测会产生大量非法组合。
这就是条件随机场(CRF, Conditional Random Field)要解决的事。CRF 的决策目标不是独立最大化每个 token 的概率,而是最大化整条标签序列的联合概率:
其中 是特征函数, 是学习到的权重。CRF 通过 Viterbi 算法在所有可能标签序列中找最优,天然排除非法的 BIO 跳转。
神经网络 + CRF 时代(2015-2018)
经典架构:BiLSTM + CRF。BiLSTM 学习每个 token 的上下文表示,CRF 层建模标签间的转移约束。在当时是 NER 的 SOTA。
BERT 时代(2018-)
BERT 级别的预训练表示已经极强,很多任务上 BERT + 线性头 就能达到 BERT + CRF 的水平,因为 BERT 的上下文信息足以让模型"自学"到标签约束。但在低资源、标注稀少的场景下,CRF 层提供的结构先验仍能带来 0.5-2 个点的提升。
评估:Entity-level F1
序列标注的评估不是 token 级的。考虑:
真实标签: [B-ORG, I-ORG, I-ORG] → 一个 3-token 的机构
模型预测: [B-ORG, I-ORG, O] → 只识别出 2 个 tokenToken 级 F1 会说"你做对了 2/3",但业务上这个实体完全错了——边界错误导致下游不可用。
Entity-level F1 的定义:
- TP:预测的实体与真实实体边界完全一致 且 类型一致
- FP:预测出了一个实体,但边界或类型不对
- FN:真实实体没有被预测到
然后按分类任务的 Precision / Recall / F1 公式聚合。这是 CoNLL、OntoNotes 等经典 NER benchmark 的标准评估方式,也是 seqeval 库的默认行为。
from seqeval.metrics import classification_report
y_true = [["B-ORG", "I-ORG", "O", "B-LOC"]]
y_pred = [["B-ORG", "I-ORG", "O", "B-LOC"]]
print(classification_report(y_true, y_pred, digits=4))LLM 时代:零样本 NER 能取代标注吗?
一个现代研究生常问的问题:既然 GPT-4 / Claude 一句 prompt 就能做 NER,还需要标注数据微调吗?
现实比宣传复杂得多。
零样本 NER 能做什么
prompt = """
从下面文本中抽取所有"机构名"和"地名",以 JSON 返回:
"北京大学位于海淀区中关村"
"""
# GPT-4 大概率返回:
# {"机构名": ["北京大学"], "地名": ["海淀区", "中关村"]}对通用领域、实体类型明确的任务,LLM zero-shot NER 表现相当不错——可能达到 70-85 F1。
零样本 NER 做不好的事
零样本 NER 的五个致命弱点:
- 专业领域:医学、法律、金融的实体边界和类型定义非常细(如 ICD-10 疾病代码)。通用 LLM 不懂你的体系,零样本得分可能跌到 40-60 F1。
- 边界一致性:同一个实体 "Dr. 张三" 可能有时包含职称、有时不包含,LLM 输出无法保持内部一致。
- 嵌套实体:真实数据中实体常嵌套("北京大学软件与微电子学院" 同时是 ORG 和包含地名"北京")。Prompt 很难明确指定嵌套规则。
- 规模化成本:处理 100 万篇文档,LLM API 调用成本比部署一个 BERT-NER 模型贵几个数量级,推理延迟也慢百倍。
- 可控性:业务要求"必须返回 JSON 格式",LLM 偶尔会飘出非法输出,下游系统崩溃。
现代工业实践
真实的 NER 系统往往采用分层架构:
- 基座:BERT-NER 或 LLM 蒸馏出的小模型,覆盖 95% 常见实体
- LLM 补充:冷启动、新增实体类型、罕见实体用 LLM 兜底
- 主动学习闭环:LLM 输出供人工审核 → 进入训练集 → 下一版 BERT-NER
序列标注这条线没有被大模型取代,而是被融合进了更复杂的数据飞轮。
本节小结
| 概念 | 要点 |
|---|---|
| 序列标注 | 为每个 token 分配标签;NER / POS / Chunking 的共同形式 |
| BIO 方案 | B-X 开始、I-X 内部、O 非实体;NER 的标准编码 |
| BIOES 方案 | 增加 E-X(结束)和 S-X(单 token);边界信号更强 |
| CRF | 建模标签间转移约束,排除非法 BIO 跳转 |
| BERT + 线性头 | 大多数场景足够;低资源时加 CRF |
| Entity-level F1 | 评估必须到实体级,不能只看 token 级 |
| LLM 零样本 NER | 通用场景可用,专业领域、规模化、可控性上仍需传统 NER |