基于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库中的相关包:

  1. 分词器:AutoTokenizer
  2. 模型加载器:AutoModelForTokenClassification(因为NER任务本质是Token分类任务,所以用这个模型加载器)
  3. 模型训练框架:TrainingArguments、Trainer、DataCollatorForTokenClassification
  4. 数据集加载器: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()

在这里插入图片描述

开始训练 = 完结撒花


总结

总结一下吧,其实模型的训练无论是什么任务大致都是这几个步骤。我感觉只要把这几个步骤搞清楚吃透了,以后无论是什么任务大家应该都能信手拈来。
本系列持续更新!希望我的分享能帮到大家,谢谢!

参考

  1. 【手把手带你实战HuggingFace Transformers-实战篇】实战演练之命名实体识别 https://www.bilibili.com/video/BV1gW4y197CT/?spm_id_from=333.1007.top_right_bar_window_history.content.click
Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐