惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Y
Y Combinator Blog
腾讯CDC
Recent Announcements
Recent Announcements
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Hugging Face - Blog
Hugging Face - Blog
H
Help Net Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Last Week in AI
Last Week in AI
博客园_首页
D
DataBreaches.Net
P
Proofpoint News Feed
云风的 BLOG
云风的 BLOG
V
Visual Studio Blog
月光博客
月光博客
Jina AI
Jina AI
Stack Overflow Blog
Stack Overflow Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 【当耐特】
Vercel News
Vercel News
WordPress大学
WordPress大学
J
Java Code Geeks
博客园 - 聂微东
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
U
Unit 42

博客园 - VipSoft

FastAPI 全局 HTTP 异常处理器 + 统一响应封装 SpringBoot 心跳日志不记录 access.log Qdrant Linux 安装(非Docker) LangChain — RAG 知识库(实操) LangChain — RAG 构建知识库(理论) LangChain — RAG 构建知识库(实操) Python PyCharm 运行,取不到 .env 文件中的值 Qdrant 安装(Windows) LangChain — RAG 构建知识库 Python 项目简单部署(Linux) MinerU - 将非结构化文档(PDF、图片、Office 文件等)转换为机器可读的 Markdown 和 JSON LangChain 入门 服务端部署-FastAPI LangChain 入门 LangSmith LangChain 入门 实战 - 食谱推荐 LangChain 入门 Memory 会话记忆 LangChain 入门 Tools 工具 LangChain 入门 Tools 工具 LangChain 入门 Prompts 提示词 LangChain 入门 Message 消息 LangChain 入门 Model 的初始化和调用 LangChain 入门 Agent 的基本运行机制 AI 0基础学习,名词解析 LangChain 和 LangGraph AI大模型知识体系 Dify — Workflow - 数据可视化 Dify — 连接MySQL配置 Dify — Chatflow - 数据库智能查询 Dify — Chatflow - 文档知识库 Dify — Agent 智能体 高安全券码、注册码生成
跟着AI学AI - 诊断结论信息抽取 - 模型训练
VipSoft · 2026-05-11 · via 博客园 - VipSoft

数据增强和自动标注只是准备数据的手段,最终目的是用这些数据训练出好用的模型。

seqeval 是一个专门用于评估序列标注任务(如命名实体识别 NER)的 Python 库。它支持多种标签格式(如 BIO、IOBES 等),并提供了计算准确率(Accuracy)、查准率(Precision)、召回率(Recall)和 F1 分数等指标的便捷方法。seqeval 适用于命名实体识别、词性标注和语义角色标注等任务。

# 设置镜像源的环境变量
(vippython) PS D:\OpenSource\Python\VipPython> $env:HF_ENDPOINT = "https://hf-mirror.com"
# 安装依赖
(vippython) PS D:\OpenSource\Python\VipPython> uv pip install seqeval
(vippython) PS D:\OpenSource\Python\VipPython> uv pip install accelerate>=0.26.0
# 切换下目录,否则会报文件不存在
(vippython) PS D:\OpenSource\Python\VipPython> cd D:\OpenSource\Python\VipPython\information_extraction
(vippython) PS D:\OpenSource\Python\VipPython\information_extraction> uv run .\information_extraction\train_ner_model.py

train_ner_model.py

# train_ner_model.py
import json
import torch
from transformers import (
    AutoTokenizer,
    AutoModelForTokenClassification,
    TrainingArguments,
    Trainer,
    DataCollatorForTokenClassification
)
from torch.utils.data import Dataset
import numpy as np
from sklearn.metrics import classification_report, confusion_matrix
import os


class NERDataset(Dataset):
    def __init__(self, data, label2id):
        self.data = data
        self.label2id = label2id

    def __len__(self):
        return len(self.data)

    def __getitem__(self, idx):
        item = self.data[idx]
        return {
            'input_ids': torch.tensor(item['input_ids']),
            'attention_mask': torch.tensor(item['attention_mask']),
            'labels': torch.tensor(item['labels'])
        }


def compute_metrics(pred):
    """计算评估指标"""
    predictions, labels = pred
    predictions = np.argmax(predictions, axis=2)

    # 移除忽略的索引
    true_predictions = [
        [p for (p, l) in zip(pred_row, label_row) if l != -100]
        for pred_row, label_row in zip(predictions, labels)
    ]
    true_labels = [
        [l for l in label_row if l != -100]
        for label_row in labels
    ]

    # 计算指标
    from seqeval.metrics import classification_report as seq_report
    from seqeval.metrics import accuracy_score, f1_score, precision_score, recall_score

    # 将ID转换为标签名
    id2label = {v: k for k, v in label2id.items()}

    predictions_labels = [[id2label[p] for p in pred] for pred in true_predictions]
    references_labels = [[id2label[l] for l in ref] for ref in true_labels]

    return {
        'f1': f1_score(references_labels, predictions_labels),
        'precision': precision_score(references_labels, predictions_labels),
        'recall': recall_score(references_labels, predictions_labels),
        'accuracy': accuracy_score(references_labels, predictions_labels)
    }


def train_model(train_file, valid_file, label2id, output_dir='./ner_model'):
    """训练NER模型"""
    print("=" * 60)
    print("开始训练NER模型")
    print("=" * 60)

    # 1. 加载数据
    print("加载训练数据...")
    with open(train_file, 'r', encoding='utf-8') as f:
        train_data = json.load(f)

    with open(valid_file, 'r', encoding='utf-8') as f:
        valid_data = json.load(f)

    print(f"训练集: {len(train_data)} 条")
    print(f"验证集: {len(valid_data)} 条")

    # 2. 创建数据集
    train_dataset = NERDataset(train_data, label2id)
    valid_dataset = NERDataset(valid_data, label2id)

    # 3. 加载模型
    tokenizer = AutoTokenizer.from_pretrained("bert-base-chinese")
    model = AutoModelForTokenClassification.from_pretrained(
        "bert-base-chinese",
        num_labels=len(label2id),
        id2label={str(k): v for k, v in id2label.items()},
        label2id=label2id
    )

    # 4. 训练参数
    training_args = TrainingArguments(
        output_dir=output_dir,
        num_train_epochs=10,  # 训练轮数
        per_device_train_batch_size=16,  # 批次大小
        per_device_eval_batch_size=16,
        learning_rate=2e-5,  # 学习率
        weight_decay=0.01,  # 权重衰减
        warmup_ratio=0.1,  # 预热比例
        logging_dir='./logs',
        logging_steps=50,
        eval_strategy="epoch",  # 每个epoch评估一次
        save_strategy="epoch",  # 每个epoch保存一次
        load_best_model_at_end=True,  # 结束时加载最佳模型
        metric_for_best_model="f1",
        greater_is_better=True,
        save_total_limit=3,  # 只保留最后3个模型
        fp16=False,  # 没有GPU设为False
        report_to="none",  # 不报告到wandb等
    )

    # 5. 数据整理器
    data_collator = DataCollatorForTokenClassification(tokenizer)

    # 6. 创建训练器
    trainer = Trainer(
        model=model,
        args=training_args,
        train_dataset=train_dataset,
        eval_dataset=valid_dataset,
        tokenizer=tokenizer,
        data_collator=data_collator,
        compute_metrics=compute_metrics
    )

    # 7. 开始训练
    print("\n开始训练...")
    trainer.train()

    # 8. 保存模型
    print(f"\n保存模型到: {output_dir}")
    trainer.save_model()
    tokenizer.save_pretrained(output_dir)

    # 9. 保存标签映射
    with open(os.path.join(output_dir, 'label2id.json'), 'w', encoding='utf-8') as f:
        json.dump(label2id, f, indent=2, ensure_ascii=False)

    with open(os.path.join(output_dir, 'id2label.json'), 'w', encoding='utf-8') as f:
        json.dump(id2label, f, indent=2, ensure_ascii=False)

    print("训练完成!")
    return trainer


if __name__ == "__main__":
    # 加载标签映射
    with open('data/out/labels_info.json', 'r', encoding='utf-8') as f:
        labels_info = json.load(f)
    label2id = labels_info['label2id']
    id2label = {int(k): v for k, v in labels_info['id2label'].items()}

    # 训练模型
    train_model(
        train_file='data/out/bert_training_data_ecg_augmented.json',  # 增强后的数据
        valid_file='data/out/bert_training_data.json',  # 原始数据作为验证集
        label2id=label2id,
        output_dir='./ecg_ner_model'
    )

image