人工智能之语言领域
第七章 命名实体识别
文章目录
- 人工智能之语言领域
- [前言 命名实体识别(NER)](#前言 命名实体识别(NER))
- [7.1 NER任务概述](#7.1 NER任务概述)
- [7.1.1 实体类型](#7.1.1 实体类型)
- [7.1.2 NER的评价指标](#7.1.2 NER的评价指标)
- [7.2 传统NER方法](#7.2 传统NER方法)
- [7.2.1 基于规则与词典的方法](#7.2.1 基于规则与词典的方法)
- [7.2.2 基于统计学习的方法:HMM、CRF](#7.2.2 基于统计学习的方法:HMM、CRF)
- [7.3 深度学习NER方法](#7.3 深度学习NER方法)
- [7.3.1 RNN+CRF模型:序列标注经典架构](#7.3.1 RNN+CRF模型:序列标注经典架构)
- [7.3.2 BERT+CRF模型:上下文感知的实体识别](#7.3.2 BERT+CRF模型:上下文感知的实体识别)
- [7.4 低资源与跨领域NER](#7.4 低资源与跨领域NER)
- [7.4.1 迁移学习在NER中的应用](#7.4.1 迁移学习在NER中的应用)
- [7.4.2 少样本NER方法](#7.4.2 少样本NER方法)
- [7.5 实战案例:医疗领域实体(疾病、药物)识别](#7.5 实战案例:医疗领域实体(疾病、药物)识别)
- [补充:NER 系统架构对比](#补充:NER 系统架构对比)
- 小结
- 资料关注
前言 命名实体识别(NER)
命名实体识别(Named Entity Recognition, NER)是自然语言处理(NLP)中一项基础而关键的信息抽取任务,其目标是从非结构化文本中自动识别并分类预定义类型的实体,如人名、地名、组织机构等。NER 是构建知识图谱、智能问答、信息检索等系统的基石。本章将系统介绍 NER 的任务定义、传统与深度学习方法、低资源场景策略,并通过医疗领域实体识别实战案例完整演示端到端流程。
7.1 NER任务概述
7.1.1 实体类型
NER 通常识别以下标准实体类型(以 CoNLL-2003 和 中文 MSRA 数据集为例):
| 类型 | 英文缩写 | 示例 |
|---|---|---|
| 人名 | PER | 马云、爱因斯坦 |
| 地名 | LOC | 北京、太平洋 |
| 机构名 | ORG | 阿里巴巴、联合国 |
| 时间 | TIME | 2025年3月、昨天 |
| 数字/货币/百分比 | NUM/MONEY/PCT | 100元、50% |
📌 中文特殊性:
- 无空格分隔,需先分词或字符级标注
- 实体边界模糊(如"北京大学" vs "北京 大学")
- 领域实体丰富(如医疗:"阿莫西林"、"高血压")
标注格式(BIO 标注):
B-:实体开始(Begin)I-:实体内部(Inside)O:非实体(Outside)
🌰 示例:
文本:
马云 创立了 阿里巴巴
标注:B-PER O B-ORG
原始文本
分词/字符切分
BIO 标注序列
B-PER, O, B-ORG
7.1.2 NER的评价指标
NER 是序列标注任务 ,评估需考虑实体边界和类型是否完全匹配。
- 精确率(Precision) = 正确预测的实体数 / 所有预测的实体数
- 召回率(Recall) = 正确预测的实体数 / 所有真实实体数
- F1值 = 2 × (Prec × Rec) / (Prec + Rec)
⚠️ 注意:
- "马云" 被标为 "B-PER I-PER" → 正确
- "马云" 被标为 "B-PER B-PER" → 错误(边界错)
- "马云" 被标为 "B-ORG" → 错误(类型错)
常用工具:seqeval(专为序列标注设计)
python
from seqeval.metrics import classification_report
y_true = [['B-PER', 'I-PER', 'O', 'B-ORG']]
y_pred = [['B-PER', 'I-PER', 'O', 'B-ORG']]
print(classification_report(y_true, y_pred))
# 输出按实体类型统计的 Precision/Recall/F1
7.2 传统NER方法
7.2.1 基于规则与词典的方法
原理:利用人工编写的规则或外部词典匹配实体。
- 规则:正则表达式匹配日期、电话、邮箱
- 词典:加载人名库(如公安部姓氏库)、地名库(GeoNames)
python
import re
# 规则示例:匹配日期
text = "会议定于2025年3月10日举行"
date_pattern = r'\d{4}年\d{1,2}月\d{1,2}日'
matches = re.findall(date_pattern, text)
print("识别到日期:", matches) # ['2025年3月10日']
✅ 优点:准确率高(对规则覆盖部分)
❌ 缺点:泛化能力差,维护成本高,无法处理未登录词
7.2.2 基于统计学习的方法:HMM、CRF
隐马尔可夫模型(HMM)
- 将 NER 视为序列标注问题
- 假设当前标签只依赖前一标签(马尔可夫性)
- 使用维特比算法解码最可能标签序列
条件随机场(CRF)
- 全局归一化,避免标签偏置问题
- 可加入丰富特征(词形、前后缀、词性等)
- 曾是 NER 的 SOTA 方法(2010s)
python
# 使用 sklearn-crfsuite 实现 CRF(需先提取特征)
import sklearn_crfsuite
from sklearn_crfsuite import scorers, metrics
def word2features(sent, i):
word = sent[i][0]
features = {
'word': word,
'word.lower()': word.lower(),
'word[-3:]': word[-3:],
'word[-2:]': word[-2:],
'word.isupper()': word.isupper(),
'word.isdigit()': word.isdigit(),
}
if i > 0:
features['prev_word'] = sent[i-1][0]
else:
features['BOS'] = True
if i < len(sent)-1:
features['next_word'] = sent[i+1][0]
else:
features['EOS'] = True
return features
def sent2features(sent):
return [word2features(sent, i) for i in range(len(sent))]
# 假设 train_sents 是 [(word, tag), ...] 的列表
X_train = [sent2features(s) for s in train_sents]
y_train = [sent2labels(s) for s in train_sents]
crf = sklearn_crfsuite.CRF(
algorithm='lbfgs',
c1=0.1,
c2=0.1,
max_iterations=100,
all_possible_transitions=True
)
crf.fit(X_train, y_train)
💡 中文实践:需先分词,并将每个词作为单元输入。
7.3 深度学习NER方法
7.3.1 RNN+CRF模型:序列标注经典架构
架构流程:
- 词嵌入(Word Embedding)
- 双向 LSTM 编码上下文
- CRF 解码器保证标签合法性(如 I-PER 不能跟在 O 后)
词序列
Embedding Layer
BiLSTM Encoder
CRF Decoder
BIO 标签序列
python
import torch
import torch.nn as nn
from torchcrf import CRF
class BiLSTM_CRF(nn.Module):
def __init__(self, vocab_size, tag_to_ix, embedding_dim=128, hidden_dim=256):
super().__init__()
self.embedding_dim = embedding_dim
self.hidden_dim = hidden_dim
self.vocab_size = vocab_size
self.tag_to_ix = tag_to_ix
self.tagset_size = len(tag_to_ix)
self.word_embeds = nn.Embedding(vocab_size, embedding_dim)
self.lstm = nn.LSTM(embedding_dim, hidden_dim // 2,
num_layers=1, bidirectional=True)
self.hidden2tag = nn.Linear(hidden_dim, self.tagset_size)
self.crf = CRF(self.tagset_size, batch_first=True)
def forward(self, x, tags=None):
# x: [batch, seq_len]
embeds = self.word_embeds(x) # [B, L, D]
lstm_out, _ = self.lstm(embeds) # [B, L, H]
emissions = self.hidden2tag(lstm_out) # [B, L, num_tags]
if tags is not None:
# 训练:返回 loss
loss = -self.crf(emissions, tags, reduction='mean')
return loss
else:
# 推理:返回预测标签
return self.crf.decode(emissions)
✅ 优势:端到端训练,自动学习特征
❌ 劣势:依赖分词质量,长距离依赖有限
7.3.2 BERT+CRF模型:上下文感知的实体识别
核心思想 :用 BERT 替代 BiLSTM 作为编码器,提供上下文相关词表示。
- 输入:字符序列(中文无需分词)
- 输出:每个 token 的向量 → 线性层 → CRF
python
from transformers import BertModel, BertPreTrainedModel
from torchcrf import CRF
class BertCRF(BertPreTrainedModel):
def __init__(self, config, num_labels):
super().__init__(config)
self.bert = BertModel(config)
self.dropout = nn.Dropout(config.hidden_dropout_prob)
self.classifier = nn.Linear(config.hidden_size, num_labels)
self.crf = CRF(num_labels, batch_first=True)
def forward(self, input_ids, attention_mask=None, labels=None):
outputs = self.bert(input_ids=input_ids, attention_mask=attention_mask)
sequence_output = outputs[0] # [B, L, 768]
sequence_output = self.dropout(sequence_output)
logits = self.classifier(sequence_output) # [B, L, num_labels]
if labels is not None:
loss = -self.crf(logits, labels, mask=attention_mask.bool(), reduction='mean')
return loss
else:
decoded = self.crf.decode(logits, mask=attention_mask.bool())
return decoded
🌐 中文推荐模型:
bert-base-chinese、hfl/chinese-bert-wwm-ext
7.4 低资源与跨领域NER
7.4.1 迁移学习在NER中的应用
场景:目标领域(如医疗)标注数据少,但有大量通用领域数据(如新闻)。
策略:
- 在通用 NER 数据集(如 MSRA)上预训练模型
- 在医疗 NER 数据上微调
python
# Step 1: 加载在 MSRA 上训练好的中文 BERT-NER 模型
# model = BertCRF.from_pretrained("your-msra-ner-model")
# Step 2: 在医疗数据上继续微调
# trainer.train()
✅ 效果:通常比从头训练提升 5--15% F1
7.4.2 少样本NER方法
当每类实体只有几个标注样本时:
| 方法 | 原理 |
|---|---|
| Prompt-based NER | 将 NER 转为填空任务(如"马云是 [MASK]" → "人名") |
| 原型网络(Prototypical Networks) | 计算 token 向量到各类原型的距离 |
| 远程监督(Distant Supervision) | 用知识库(如 UMLS)自动标注 |
🔮 前沿方向:结合大语言模型(LLM)进行零样本/少样本 NER。
7.5 实战案例:医疗领域实体(疾病、药物)识别
任务描述
- 输入 :电子病历或医学文献片段 "患者诊断为2型糖尿病,处方二甲双胍500mg每日两次。"
- 输出 :
- 疾病:
B-DIS I-DIS I-DIS(2型糖尿病) - 药物:
B-DRUG I-DRUG(二甲双胍)
- 疾病:
数据集
使用公开中文医疗 NER 数据集 CMeEE(Chinese Medical Entity Extraction)。
完整代码实现(基于 Transformers + CRF)
python
# Step 1: 安装依赖
# pip install transformers datasets torch seqeval torchcrf
# Step 2: 加载 CMeEE 数据(简化版)
from datasets import load_dataset
dataset = load_dataset("liushiqi/CMeEE") # 或自行下载
# Step 3: 定义标签
label_list = ["O", "B-dis", "I-dis", "B-sym", "I-sym", "B-dru", "I-dru", ...]
label_to_id = {l: i for i, l in enumerate(label_list)}
# Step 4: Tokenize(字符级)
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("hfl/chinese-bert-wwm-ext")
def tokenize_and_align_labels(examples):
tokenized_inputs = tokenizer(
examples["text"],
truncation=True,
padding=True,
max_length=128,
is_split_into_words=False # 输入为字符串
)
labels = []
for i, label in enumerate(examples["labels"]):
word_ids = tokenized_inputs.word_ids(batch_index=i)
previous_word_idx = None
label_ids = []
for word_idx in word_ids:
if word_idx is None:
label_ids.append(-100) # 忽略 special tokens
elif word_idx != previous_word_idx:
label_ids.append(label_to_id[label[word_idx]])
else:
label_ids.append(-100) # 子词标签忽略
previous_word_idx = word_idx
labels.append(label_ids)
tokenized_inputs["labels"] = labels
return tokenized_inputs
tokenized_datasets = dataset.map(tokenize_and_align_labels, batched=True)
# Step 5: 加载模型(BERT+CRF)
model = BertCRF.from_pretrained("hfl/chinese-bert-wwm-ext", num_labels=len(label_list))
# Step 6: 训练(使用 Trainer)
from transformers import TrainingArguments, Trainer
training_args = TrainingArguments(
output_dir="./medical-ner",
evaluation_strategy="epoch",
learning_rate=2e-5,
per_device_train_batch_size=16,
num_train_epochs=5,
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized_datasets["train"],
eval_dataset=tokenized_datasets["validation"],
tokenizer=tokenizer,
)
trainer.train()
# Step 7: 预测与评估
from seqeval.metrics import classification_report
predictions = trainer.predict(tokenized_datasets["test"])
y_pred = [[label_list[p] for p in pred if p != -100] for pred in predictions.predictions]
y_true = [[label_list[l] for l in label if l != -100] for label in predictions.label_ids]
print(classification_report(y_true, y_pred))
预期结果
- 疾病识别 F1:>85%
- 药物识别 F1:>80%
💡 若无标注数据,可先用 LTP 或 HanLP 的通用 NER 模型抽取,再人工校验。
补充:NER 系统架构对比
规则/词典
中小数据
大数据
追求SOTA
输入文本
方法选择
正则+词典匹配
CRF + 手工特征
BiLSTM-CRF
BERT-CRF
输出实体
小结
命名实体识别从早期的规则系统发展到今天的预训练语言模型,已成为 NLP 中成熟而活跃的研究方向。BERT+CRF 架构目前是工业界主流方案,尤其适合中文等复杂语言。在医疗、金融、法律等专业领域,领域自适应 和少样本学习 是突破数据瓶颈的关键。未来,NER 将与大语言模型 、知识图谱 、多模态理解深度融合,迈向更精准、更智能的信息抽取。
资料关注
咚咚王
《Python 编程:从入门到实践》
《利用 Python 进行数据分析》
《算法导论中文第三版》
《概率论与数理统计(第四版) (盛骤) 》
《程序员的数学》
《线性代数应该这样学第 3 版》
《微积分和数学分析引论》
《(西瓜书)周志华-机器学习》
《TensorFlow 机器学习实战指南》
《Sklearn 与 TensorFlow 机器学习实用指南》
《模式识别(第四版)》
《深度学习 deep learning》伊恩·古德费洛著 花书
《Python 深度学习第二版(中文版)【纯文本】 (登封大数据 (Francois Choliet)) (Z-Library)》
《深入浅出神经网络与深度学习 +(迈克尔·尼尔森(Michael+Nielsen)》
《自然语言处理综论 第 2 版》
《Natural-Language-Processing-with-PyTorch》
《计算机视觉-算法与应用(中文版)》
《Learning OpenCV 4》
《AIGC:智能创作时代》杜雨 +&+ 张孜铭
《AIGC 原理与实践:零基础学大语言模型、扩散模型和多模态模型》
《从零构建大语言模型(中文版)》
《实战 AI 大模型》
《AI 3.0》