当前位置: 首页 > article >正文

【NLP】使用 SpaCy 通过 LLM 合成数据微调 NER 模型

在我们之前的文章“使用 SpaCy、ollama 创建用于命名实体识别的合成数据集”中,我们探讨了如何使用 Qwen 生成合成数据,以自动化命名实体识别 (NER) 的注释过程。通过利用合成数据,我们能够高效地准备来自 SmoothNLP金融新闻数据集  的高质量数据集。现在,在这篇文章中,我们将更进一步,使用 SpaCy 训练各种 NER 模型,比较它们的性能,并检查它们在我们合成生成的数据集中识别实体的能力。

步骤 1:加载模型并准备管道

import spacy
nlp = spacy.load('zh_core_web_sm')
from spacy.training import Example
from spacy.util import minibatch
from tqdm import tqdm
import random
from spacy.tokens import DocBin

# Get the Named Entity Recognizer (NER) component or add it if not present
if "ner" not in nlp.pipe_names:
    ner = nlp.add_pipe("ner")
else:
    ner = nlp.get_pipe("ner")

在这里,我们加载了 SpaCy 的预训练中文模型,zh_core_web_sm其中包括大型词向量以提高准确性。我们检查ner管道中是否存在命名实体识别器 ( ) 组件。这对于识别文本中的名称、位置和组织等实体至关重要。

步骤 2:加载训练数据

# 加载训练数据(它是 .spacy 格式)
train_doc_bin = DocBin().from_disk(r"train.spacy")

# 将文档箱转换为文档对象
docs = list(train_doc_bin.get_docs(nlp.vocab))

# 将数据分成训练和验证集(例如,80% 训练,20% 验证)
train_ratio = 0.8
split_idx = int(len(docs) * train_ratio)
train_docs = docs[:split_idx]
valid_docs = docs[split_idx:]

我们使用 SpaCy 的类加载以 .spacy格式存储的训练数据(DocBin),这对于大型数据集非常有效。该get_docs()方法将二进制文件转换为 SpaCy的Doc对象。然后,我们将数据分成训练集 (80%) 和验证集 (20%),使我们能够在训练期间评估模型性能。

步骤 3:准备训练示例

train_examples = [Example.from_dict(doc, {"entities": [(ent.start_char, ent.end_char, ent.label_) for ent in doc.ents]}) for doc in train_docs]

在这里,我们通过创建对象来准备训练示例Example。每个示例将原始文本(doc)与其实体注释(起始和终止字符索引以及实体标签)配对。这些Example对象对于训练 SpaCy 模型至关重要,因为它们封装了输入(原始文本)和预期输出(实体)。

步骤 4:初始化优化器并设置训练参数

# 初始化优化器以进行微调
optimizer = nlp.resume_training() 

# 设置训练参数
n_iter = 20   # 训练周期次数
patient = 4   # 提前停止耐心
batch_size = 8   # 训练批次大小
best_f1 = 0   # 跟踪最佳 F1 分数
no_improvement = 0   # 用于提前停止

我们使用 SpaCy 的内置resume_training()方法恢复训练,该方法初始化优化器。然后我们定义训练参数:

  • n_iter:训练周期数(模型查看整个训练数据的次数)。
  • patience:在触发早期停止之前,等待未出现改进的时期数。
  • batch_size:每次训练的示例数。
  • best_f1:在验证期间跟踪最佳 F1 分数。
  • no_improvement:计算 F1 分数没有提高的时期数,用于早期停止。

步骤 5:训练循环

# 使用早期停止和验证的训练循环
for epoch in tqdm(range(n_iter)):
    print(f"Epoch {epoch + 1}/{n_iter}")

    # 打乱训练数据
    random.shuffle(train_examples)

    # 创建训练数据批次
    batches = minibatch(train_examples, size=batch_size)

    # 在每个批次上进行训练
    for batch in tqdm(batches, leave=False):
        nlp.update(batch, sgd=optimizer)

    # 在每个 epoch 之后对验证集进行评估
    print("Evaluating on validation set...")

    valid_examples = []
    for doc in valid_docs:
        # 创建一个包含原始文本(无注释)的新 Doc 对象用于预测
        pred_doc = nlp.make_doc(doc.text)  
        
        # 创建一个将预测与原始带注释文档配对的 Example 对象
        example = Example(pred_doc, doc)
        valid_examples.append(example)

    # 将 nlp.evaluate() 与新创建的 Example 对象一起使用
    results = nlp.evaluate(valid_examples)

    # 提取 F1 分数、精度和召回率
    precision = results["ents_p"]
    recall = results["ents_r"]
    f1 = results["ents_f"]

    print(f"Validation Precision: {precision:.4f}, Recall: {recall:.4f}, F1 Score: {f1:.4f}")

    # 根据验证 F1 分数的早期停止逻辑
    if f1 > best_f1:
        best_f1 = f1
        no_improvement = 0
        # Save the best model
        nlp.to_disk("best_model")
    else:
        no_improvement += 1
        print(f"No improvement for {no_improvement} epochs.")

    if no_improvement >= patience:
        print("Early stopping triggered. Stopping training.")
        break

 

这是主要的训练循环。对于每个周期:

  • 我们对训练示例进行打乱,以避免过度拟合。
  • 我们用来minibatch创建小批量数据进行梯度更新。
  • nlp.update()对每一批训练示例执行单步优化,调整模型的权重以最小化损失。
  • 在每个时期之后,我们都会在验证集上评估模型。对于每个验证示例,我们使用生成预测nlp.make_doc()并将它们与原始注释进行比较。我们使用nlp.evaluate()来计算评估指标,例如精确度召回率F1 分数。这些指标可帮助我们评估模型在未见过的数据上的表现。如果 F1 分数在一个时期后有所提高,我们会重置计数器no_improvement并保存模型。如果模型在一定数量的时期内没有显示出任何改进(patience),我们会停止训练以避免过度拟合。表现最佳的模型将保存到磁盘。

步骤 6:评估最终模型

为了使用手动注释的测试集有效地评估最终模型,我们可以按如下方式进行设置:

# 从磁盘加载表现最佳的模型
nlp = spacy.load("best_model")

# 测试数据
test_doc_bin = DocBin().from_disk(r"test.spacy")
test_docs = list(test_doc_bin.get_docs(nlp.vocab))

# 将测试文档转换为示例以供评估
test_examples = [Example.from_dict(doc, {"entities": [(ent.start_char, ent.end_char, ent.label_) for ent in doc.ents]}) for doc in test_docs]

# 在测试示例上评估最终模型
test_results = nlp.evaluate(test_examples)
test_precision = test_results["ents_p"]
test_recall = test_results["ents_r"]
test_f1 = test_results["ents_f"]

print(f"Test Precision: {test_precision:.4f}, Recall: {test_recall:.4f}, F1 Score: {test_f1:.4f}")

步骤 7:使用我们微调的模型进行预测

为了使用我们微调的 NER 模型进行预测,我们可以加载保存的模型并使用它来识别新文本数据中的实体:

# 加载微调后的模型
nlp = spacy.load("best_model")

# 定义要分析的文本
text = "贵州:扫黑风暴使在逃多年涉案人员自首\n新华社贵阳2月15日电(记者 汪军)记者从贵州省公安厅了解到,在扫黑除恶专项斗争高压态势下,在逃8年多的涉嫌组织、领导、参加黑社会性质组织的胡某河近日主动到贵州省铜仁市公安机关投案自首。\n2009年8月,贵州省公安厅统一指挥,成功打掉了铜仁市思南县一涉嫌组织、领导、参加黑社会性质的犯罪团伙,当地群众拍手称快,但该案主要犯罪嫌疑人胡某河在逃。\n今年1月,全国扫黑除恶专项斗争开展以来,贵州省市县三级公安机关协调联动,通过媒体发布相关通告,宣讲有关政策,广泛发动群众检举揭发,深入宣传党和政府扫黑除恶的决心,敦促涉黑涉恶人员主动投案自首、争取宽大处理,积极营造全社会参与支持扫黑除恶的氛围。\n近日在公安机关强大宣传攻势下,在逃8年多的涉嫌组织、领导、参加黑社会性质组织的胡某河迫于压力,主动到公安机关投案自首。目前,该案相关工作正在进一步进行中。"

# 使用模型处理文本
doc = nlp(text)

# 打印识别出的带有标签的实体
for ent in doc.ents:
    print(f"Entity: {ent.text}, Label: {ent.label_}")

结论

本文详细介绍了如何使用SpaCy库训练和优化中文命名实体识别(NER)模型。首先,我们加载了SpaCy的预训练中文模型,并确保了NER组件的存在。接着,我们从.spacy格式的文件中加载训练数据,并将其分为训练集和验证集。然后,我们准备了训练示例,初始化了优化器,并设置了训练参数。在训练循环中,我们对训练数据进行打乱和分批处理,同时在每个周期后评估模型在验证集上的性能,并根据F1分数进行早期停止判断。最终,我们保存了表现最佳的模型,并在手动注释的测试集上进行了评估。文章最后展示了如何使用微调后的模型对新文本进行实体识别预测,从而验证了模型的实用性和准确性。 


http://www.kler.cn/a/385683.html

相关文章:

  • TVM计算图分割--分割方式
  • 如何使用IDEA创建Maven/SSM工程?
  • Linux学习笔记之组管理和权限管理
  • Android CarrierConfig 参数项和正则匹配逻辑
  • TensorFlow|猫狗识别
  • 新的服务器Centos7.6 安卓基础的环境配置(新服务器可直接粘贴使用配置)
  • 大数据新视界 -- 大数据大厂之 Impala 性能优化:融合机器学习的未来之路(上 (2-2))(11/30)
  • 《应用力学学报》
  • PyTorch nn.Embedding() 嵌入层详解和要点提醒
  • CSS3中的3D变换(3D空间与景深、透视点的位置、3D位移、3D旋转、3D缩放、3D多重交换、背部可见性)
  • 移动取证和 Android 安全
  • TCP(传输控制协议)和UDP(用户数据报协议)
  • uniapp 小程序 周选择器
  • 【机器学习】平均绝对误差(MAE:Mean Absolute Error)
  • stm32cubeide 1.16.1 在ubuntu 24.04上的安装
  • Intern大模型训练营(五):书生大模型全链路开源体系笔记
  • Python代码主要实现了一个基于Transformer和LSTM的混合模型,用于对给定数据集进行二分类任务
  • 用 Python 从零开始创建神经网络(一)
  • MeterSphere接口自动化-ForEach循环
  • 五分钟使用 CocosCreator 快速部署 TON 游戏:开发基于 ZKP 的游戏
  • 【dvwa靶场:XSS系列】XSS (Stored)低-中-高级别,通关啦
  • 华为大咖说 | 浅谈智能运维技术
  • 【1】 Kafka快速入门-从原理到实践
  • 一七七、window.performance API使用介绍
  • SQL pta习题
  • 我谈正态分布——正态偏态