基于Transformer的NLP下游任务实战之命名实体识别(纯小白)
现在大语言模型横行,其实命名实体识别任务完全可以通过大模型来做,无非就是猛猛的堆模型参数。但是作为NLP的一个基础任务,我认为多少还是需要掌握滴。博主本人也是小白,跟着B站上的大佬来学习,这里主要分享一下自学心得。希望可以帮到大家。总结一下吧,其实模型的训练无论是什么任务大致都是这几个步骤。我感觉只要把这几个步骤搞清楚吃透了,以后无论是什么任务大家应该都能信手拈来。本系列持续更新!
基于Transformer的NLP下游任务实战之命名实体识别(纯小白)
文章目录
- 基于Transformer的NLP下游任务实战之命名实体识别(纯小白)
- 前言
- 一、命名实体识别(NER)是什么?
- 二、要想训练一个NER模型应该怎么做?
-
- Step1 导入包
- Step2 加载数据集
- Step3 下载模型
- Step4 数据预处理 (比较难)
-
- 示例说明
- Step5 加载模型
- Step6 创建评估函数(难)
- Step7 配置训练参数
- Step8 创建训练器
- Step9 模型训练
- 总结
- 参考
前言
现在大语言模型横行,其实命名实体识别任务完全可以通过大模型来做,无非就是猛猛的堆模型参数。但是作为NLP的一个基础任务,我认为多少还是需要掌握滴。博主本人也是小白,跟着B站上的大佬来学习,这里主要分享一下自学心得。希望可以帮到大家。
一、命名实体识别(NER)是什么?
命名实体识别(NER)是自然语言处理(NLP)中的一项关键技术,用于从非结构化文本中自动识别并分类特定类别的实体,例如人名、地点、组织机构、时间、日期、货币等。简单来说,它就像文本的“信息提取器”,能够快速定位和标注文本中的关键元素,从而为搜索引擎、知识图谱、智能问答等应用提供结构化数据支持。例如,在句子“苹果公司于2023年在加州发布了新款iPhone”中,NER会识别出“苹果公司”(组织)、“2023年”(时间)、“加州”(地点)和“iPhone”(产品)。
二、要想训练一个NER模型应该怎么做?
Step1 导入包
from transformers import AutoTokenizer, AutoModelForTokenClassification, TrainingArguments, Trainer, DataCollatorForTokenClassification
from datasets import load_dataset
import evaluate
我们使用的模型是基于transformer框架的模型,所以我们需要导入transformers库中的相关包:
- 分词器:AutoTokenizer
- 模型加载器:AutoModelForTokenClassification(因为NER任务本质是Token分类任务,所以用这个模型加载器)
- 模型训练框架:TrainingArguments、Trainer、DataCollatorForTokenClassification
- 数据集加载器:load_dataset
Step2 加载数据集
"""(需要科学上网)"""
ner_datasets = load_dataset("peoples_daily_ner", cache_dir="./data")
ner_datasets
这里使用load_dataset从Huggingface上拉取数据集,这里使用的是Huggingface上人民日报的一个中文NER数据集。
数据集格式如下:
DatasetDict({
train: Dataset({
features: ['id', 'tokens', 'ner_tags'],
num_rows: 20865
})
validation: Dataset({
features: ['id', 'tokens', 'ner_tags'],
num_rows: 2319
})
test: Dataset({
features: ['id', 'tokens', 'ner_tags'],
num_rows: 4637
})
})
Step3 下载模型
from transformers import pipeline
"""(需要科学上网)"""
pipe = pipeline("fill-mask", model="hfl/chinese-macbert-base", model_kwargs={"cache_dir": "../model"} )
从Huggingface上拉取模型到本地目录。这里使用的是chinese-macbert-base模型。
Step4 数据预处理 (比较难)
#定义数据处理函数
def process_function(examples):
# is_split_into_words=True:表示输入已预先分词(无需再切分单词)。
# max_length=128:截断过长的文本。
# 输出 tokenizer_examples 包含 input_ids、attention_mask 等字段。
tokenizer_examples = tokenizer(examples["tokens"], max_length=128, truncation=True, is_split_into_words=True)
labels = []
for i , label in enumerate(examples["ner_tags"]):
word_ids = tokenizer_examples.word_ids(batch_index = i)
label_ids = []
for word_id in word_ids:
if word_id is None:
label_ids.append(-100) # 特殊 token(如 [CLS]、[SEP])的标签设为 -100(被交叉熵损失函数忽略,不计算loss。)
else:
label_ids.append(label[word_id])
labels.append(label_ids)
tokenizer_examples["labels"] = labels
return tokenizer_examples
# 获得darasets,其中包括处理好的训练集、测试集和验证集
tokenized_datasets = ner_datasets.map(process_function, batched=True)
该部分主要是处理数据,做数据标签对齐。分词器可能将单词拆分为子词(如 “北京” → [“北”, “京”]),但原始标签 B-LOC 只对应整个单词。通过 word_ids() 获取每个 token 对应的原始单词索引。对子词(如 “北”、“京”)复用原始单词的标签(均赋 B-LOC)。特殊 token(如 [CLS])的标签设为 -100,训练时会被忽略。
示例说明
假设原始数据如下:
examples = {
"tokens": [["北京", "是", "中国", "首都"]],
"ner_tags": [[1, 0, 2, 0]] # 假设 1=B-LOC, 0=O, 2=B-COUNTRY
}
处理后:
- input_ids: [ [CLS], “北”, “京”, “是”, “中”, “国”, “首”, “都”, [SEP] ]
- labels: [ -100, 1, 1, 0, 2, 2, 0, 0, -100 ] (“北”、“京” 共享标签 1,“中”、“国” 共享标签 2)
Step5 加载模型
# 加载模型到本地,这里路径对应上面下载模型的路径
model = AutoModelForTokenClassification.from_pretrained("hfl/chinese-macbert-base", cache_dir="../model",num_labels=len(label_list))
将模型加载到本地。
Step6 创建评估函数(难)
import numpy as np
# 下载评估器
seqeval = evaluate.load("seqeval")
#定义评估计算函数
def eval_metric(pred):
# 从pred中取出预测结果和标签
# predictions:模型的原始输出(未归一化的 logits,形状为 [batch_size, seq_length, num_labels])。
# labels:真实的标签(形状为 [batch_size, seq_length]),其中 -100 表示需要忽略的 token(如 [CLS]、[SEP])
predictions, labels = pred
# 对每个 token 的 logits 取 argmax,得到预测的标签 ID(形状变为 [batch_size, seq_length])。
predictions = np.argmax(predictions, axis=-1)
# true_predictions:将预测的标签 ID 转换为实际标签名称(如 B-PER),并过滤掉 -100 对应的 token。
true_predictions = [
[label_list[p] for p, l in zip(prediction, label) if l != -100]
for prediction, label in zip(predictions, labels)
]
# true_labels:对真实标签做相同处理。
true_labels = [
[label_list[l] for p, l in zip(prediction, label) if l != -100]
for prediction, label in zip(predictions, labels)
]
"""示例:
原始 predictions: [3, 1, 0, -100](假设 3=B-LOC, 1=O)
原始 labels: [3, 1, 2, -100]
过滤后:
true_predictions: ["B-LOC", "O"]
true_labels: ["B-LOC", "O"]
"""
# 计算评估指标
# mode="strict":要求实体边界和类型完全匹配才视为正确。
# scheme="IOB2":指定标签格式为 IOB2(B- 表示实体开头,I- 表示实体内部)。
result = seqeval.compute(predictions=true_predictions, references=true_labels, mode="strict", scheme="IOB2")
return {
"f1":result["overall_f1"]
}
该部分内容个人认为比较难,希望大家结合代码注释多看几遍。
Step7 配置训练参数
args = TrainingArguments(
output_dir = "model_for_ner", # 指定训练好模型输出位置
per_device_train_batch_size = 64, # 模型训练batch size
per_device_eval_batch_size = 128, # 模型验证batch size
eval_strategy = "epoch", # 每一epoch验证一次
save_strategy = "epoch", # 每一epoch保存一次
metric_for_best_model = "f1", # 模型选择的标准是基于验证集上的 F1 分数
load_best_model_at_end = True, # 训练结束时自动加载验证集上性能最佳的模型
logging_steps=50 # 每50布打印一次训练信息
)
Step8 创建训练器
trainer = Trainer(
model=model, # 指定上面加载的模型
args=args, # 指定上面训练配置
train_dataset=tokenized_datasets["train"], # 指定训练数据集
eval_dataset=tokenized_datasets["validation"], # 指定验证数据集
compute_metrics=eval_metric, # 指定评估函数
data_collator=DataCollatorForTokenClassification(tokenizer=tokenizer) # 指定数据构造器,因为训练时一批次一批次,所以涉及到数据拼接、填充等操作。使用数据构造器就是干这个的。
)
Step9 模型训练
trainer.train()

开始训练 = 完结撒花
总结
总结一下吧,其实模型的训练无论是什么任务大致都是这几个步骤。我感觉只要把这几个步骤搞清楚吃透了,以后无论是什么任务大家应该都能信手拈来。
本系列持续更新!希望我的分享能帮到大家,谢谢!
参考
- 【手把手带你实战HuggingFace Transformers-实战篇】实战演练之命名实体识别 https://www.bilibili.com/video/BV1gW4y197CT/?spm_id_from=333.1007.top_right_bar_window_history.content.click
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐

所有评论(0)