小白必看!用Qwen2.5-0.5B实现中文命名实体识别全流程

小白必看!用Qwen2.5-0.5B实现中文命名实体识别全流程

1. 引言:为什么选择Qwen2.5-0.5B做NER任务?

在自然语言处理(NLP)领域,命名实体识别(Named Entity Recognition, NER)是一项基础而关键的任务,广泛应用于信息抽取、知识图谱构建、智能客服等场景。传统方法依赖于标注数据训练BiLSTM-CRF或BERT类模型,但随着大语言模型(LLM)的发展,我们可以通过指令微调(Instruction Tuning)的方式,让通用大模型学会结构化输出能力,从而高效完成NER任务。

本文面向初学者,手把手带你使用阿里开源的轻量级大模型Qwen2.5-0.5B-Instruct,基于中文NER数据集 CLUENER2020 实现从环境准备、数据预处理、全参数微调到模型测试的完整流程。该方案具备以下优势:

  • ✅ 模型体积小(仅0.5B),适合单卡甚至消费级显卡训练
  • ✅ 支持多语言和结构化输出(JSON格式),天然适配NER任务
  • ✅ 提供网页推理接口,部署便捷
  • ✅ 全程代码可复现,附带详细解析

通过本教程,你将掌握如何将一个通用大模型“教会”执行专业NLP任务的核心思路与工程实践。


2. 技术背景与数据准备

2.1 Qwen2.5-0.5B模型特性解析

Qwen2.5-0.5B-Instruct是通义千问系列中最小的指令调优版本,专为轻量化部署和快速迭代设计。其核心能力包括:

  • 支持最长128K上下文输入,适用于长文本理解
  • 生成长度可达8K tokens,满足复杂结构化输出需求
  • 内置对JSON等结构化格式的强解析能力
  • 支持超过29种语言,其中中文表现尤为出色
  • 经过高质量指令微调,能准确理解系统提示(system prompt)

这些特性使其非常适合用于需要精确提取并格式化输出实体信息的NER任务。

📌 官方ModelScope地址:https://modelscope.cn/models/Qwen/Qwen2.5-0.5B-Instruct

2.2 数据集介绍:CLUENER2020 中文命名实体识别基准

我们采用业界广泛使用的CLUENER2020数据集进行实验,包含10类中文实体标签:

标签类别示例
address北京、上海
book《三体》
company阿里巴巴
game英雄联盟
government教育部
movie流浪地球
name张三
organization联合国儿童基金会
position总经理
scene故宫博物院

原始数据格式如下:

{ "text": "浙商银行企业信贷部叶老桂博士则从另一个角度对五道门槛进行了解读。", "label": { "name": {"叶老桂": [[9, 11]]}, "company": {"浙商银行": [[0, 3]]} } }

由于我们更关注实体内容而非位置索引,因此对数据进行了简化转换,仅保留实体名称列表。

2.3 数据预处理:统一为结构化JSON输出格式

为了适配大模型的生成式NER任务,我们将原始数据转换为如下格式:

{ "text": "彭小军认为,国内银行现在走的是台湾的发卡模式", "label": { "address": ["台湾"], "name": ["彭小军"] } }

对应的Python转换脚本如下:

import json def trans(file_path, save_path): with open(save_path, "a", encoding="utf-8") as w: with open(file_path, "r", encoding="utf-8") as r: for line in r: line = json.loads(line) text = line['text'] label = line['label'] trans_label = {} for key, items in label.items(): items = list(items.keys()) # 只保留实体名 trans_label[key] = items trans = { "text": text, "label": trans_label } line = json.dumps(trans, ensure_ascii=False) w.write(line + "\n") w.flush() if __name__ == '__main__': trans("ner_data_origin/train.json", "ner_data/train.json") trans("ner_data_origin/dev.json", "ner_data/val.json")

2.4 Token分布分析:确定最大序列长度

为合理设置输入输出长度,我们统计了训练集的Token分布情况:

from transformers import AutoTokenizer import json import numpy as np def get_token_distribution(file_path, tokenizer): input_tokens, output_tokens = [], [] with open(file_path, "r", encoding="utf-8") as f: for line in f: data = json.loads(line) text = data["text"] label = json.dumps(data["label"], ensure_ascii=False) input_tokens.append(len(tokenizer(text).input_ids)) output_tokens.append(len(tokenizer(label).input_ids)) return np.mean(input_tokens), np.max(input_tokens), np.mean(output_tokens), np.max(output_tokens) # 加载 tokenizer tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-0.5B-Instruct", trust_remote_code=True) i_avg, i_max, o_avg, o_max = get_token_distribution("ner_data/train.json", tokenizer) print(f"Input - Avg: {i_avg:.1f}, Max: {i_max}") print(f"Output - Avg: {o_avg:.1f}, Max: {o_max}")

结果表明: - 输入最大约50个Token - 输出最大约70个Token

据此设定:

max_source_length = 50 # 输入文本最大长度 max_target_length = 140 # 输出标签最大长度(预留冗余)

3. 模型微调:从零构建NER数据集与训练流程

3.1 自定义Dataset类:构造对话式训练样本

我们利用Qwen的apply_chat_template方法,将NER任务构造成“系统指令+用户提问”的对话形式,激发其结构化输出能力。

# ner_dataset.py from torch.utils.data import Dataset import torch import json import numpy as np class NerDataset(Dataset): def __init__(self, data_path, tokenizer, max_source_length, max_target_length): super().__init__() self.tokenizer = tokenizer self.max_source_length = max_source_length self.max_target_length = max_target_length self.max_seq_length = max_source_length + max_target_length self.data = [] if data_path: with open(data_path, "r", encoding='utf-8') as f: for line in f: if not line.strip(): continue item = json.loads(line) self.data.append({ "text": item["text"], "label": json.dumps(item["label"], ensure_ascii=False) }) print(f"Loaded {len(self.data)} samples.") def preprocess(self, text, label): messages = [ {"role": "system", "content": "你的任务是做NER任务提取,根据用户输入提取出完整的实体信息,并以JSON格式输出。"}, {"role": "user", "content": text}, {"role": "assistant", "content": label} ] # 构造prompt prompt = self.tokenizer.apply_chat_template( messages[:-1], tokenize=False, add_generation_prompt=True ) response = label # 编码输入 input_enc = self.tokenizer( prompt, truncation=True, max_length=self.max_source_length, padding="max_length", return_tensors="pt", add_special_tokens=False ) # 编码输出 output_enc = self.tokenizer( response, truncation=True, max_length=self.max_target_length, padding="max_length", return_tensors="pt", add_special_tokens=False ) input_ids = input_enc["input_ids"][0].tolist() attention_mask = input_enc["attention_mask"][0].tolist() labels = [-100] * len(input_ids) + output_enc["input_ids"][0].tolist() return { "input_ids": torch.LongTensor(input_ids), "attention_mask": torch.LongTensor(attention_mask), "labels": torch.LongTensor(labels) } def __getitem__(self, index): return self.preprocess(**self.data[index]) def __len__(self): return len(self.data)

🔍 关键点说明: - 使用-100填充非输出部分的labels,确保损失函数只计算Assistant回复部分 -add_generation_prompt=True自动添加<|im_start|>assistant\n触发生成

3.2 训练脚本详解:全参数微调策略

# train.py import torch from torch.utils.data import DataLoader from torch.utils.tensorboard import SummaryWriter from transformers import AutoModelForCausalLM, AutoTokenizer from ner_dataset import NerDataset from tqdm import tqdm import time, sys def train_model(model, train_loader, val_loader, optimizer, device, num_epochs, model_output_dir, writer): batch_step = 0 for epoch in range(num_epochs): model.train() start_time = time.time() for idx, batch in enumerate(tqdm(train_loader, desc=f"Train Epoch [{epoch+1}/{num_epochs}]")): input_ids = batch['input_ids'].to(device) attention_mask = batch['attention_mask'].to(device) labels = batch['labels'].to(device) optimizer.zero_grad() outputs = model( input_ids=input_ids, attention_mask=attention_mask, labels=labels ) loss = outputs.loss loss.backward() optimizer.step() writer.add_scalar('Loss/Train', loss.item(), batch_step) batch_step += 1 if idx % 100 == 0: avg_time = (time.time() - start_time) / (idx + 1) print(f"Step {idx}, Loss: {loss:.4f}, Time per step: {avg_time:.2f}s") # Validation model.eval() val_loss = 0.0 with torch.no_grad(): for batch in tqdm(val_loader, desc="Validation"): input_ids = batch['input_ids'].to(device) attention_mask = batch['attention_mask'].to(device) labels = batch['labels'].to(device) outputs = model(input_ids=input_ids, attention_mask=attention_mask, labels=labels) val_loss += outputs.loss.item() val_loss /= len(val_loader) writer.add_scalar('Loss/Val', val_loss, epoch) print(f"Epoch {epoch+1} | Val Loss: {val_loss:.4f}") # Save checkpoint model.save_pretrained(model_output_dir) print(f"Model saved to {model_output_dir}") def main(): model_name = "Qwen/Qwen2.5-0.5B-Instruct" train_path = "ner_data/train.json" val_path = "ner_data/val.json" output_dir = "output_ner" log_dir = "logs" device = torch.device("cuda" if torch.cuda.is_available() else "cpu") tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True) model = AutoModelForCausalLM.from_pretrained(model_name, trust_remote_code=True) # Dataset train_set = NerDataset(train_path, tokenizer, max_source_length=50, max_target_length=140) val_set = NerDataset(val_path, tokenizer, max_source_length=50, max_target_length=140) train_loader = DataLoader(train_set, batch_size=16, shuffle=True, num_workers=4) val_loader = DataLoader(val_set, batch_size=16, shuffle=False) # Optimizer & Writer optimizer = torch.optim.AdamW(model.parameters(), lr=1e-4) writer = SummaryWriter(log_dir) model.to(device) train_model( model=model, train_loader=train_loader, val_loader=val_loader, optimizer=optimizer, device=device, num_epochs=30, model_output_dir=output_dir, writer=writer ) writer.close() if __name__ == '__main__': main()

⚙️ 训练建议: - 显存不足时可降低batch_size至8或4 - 可加入学习率调度器(如CosineAnnealingLR) - 监控TensorBoard曲线防止过拟合


4. 模型测试与效果验证

4.1 推理脚本编写

# test.py from transformers import AutoModelForCausalLM, AutoTokenizer import torch def predict(text, model, tokenizer, device): messages = [ {"role": "system", "content": "你的任务是做NER任务提取,根据用户输入提取出完整的实体信息,并以JSON格式输出。"}, {"role": "user", "content": text} ] prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) inputs = tokenizer(prompt, return_tensors="pt").to(device) with torch.no_grad(): outputs = model.generate( **inputs, max_new_tokens=140, do_sample=False, # 贪心解码保证稳定性 top_k=1 ) # 截取新生成的部分 new_tokens = outputs[0][inputs['input_ids'].shape[-1]:] response = tokenizer.decode(new_tokens, skip_special_tokens=True) return response # 加载模型 device = torch.device("cuda" if torch.cuda.is_available() else "cpu") model = AutoModelForCausalLM.from_pretrained("output_ner", trust_remote_code=True).to(device) tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-0.5B-Instruct", trust_remote_code=True) # 测试案例 test_cases = [ "三星WCG2011北京赛区魔兽争霸3最终名次", "新华网孟买3月10日电(记者聂云)印度国防部10日说,印度政府当天批准", "证券时报记者肖渔" ] for case in test_cases: result = predict(case, model, tokenizer, device) print(f"输入: {case}") print(f"输出: {result}\n")

4.2 实际输出示例

输入: 新华网孟买3月10日电(记者聂云)印度国防部10日说,印度政府当天批准 输出: {"organization": ["新华网"], "address": ["孟买"], "position": ["记者"], "name": ["聂云"], "government": ["印度国防部", "印度政府"]}

✅ 模型成功识别出媒体、地点、职位、人名和政府机构等多种实体,且输出为标准JSON格式,便于后续系统集成。


5. 总结

本文完整展示了如何使用Qwen2.5-0.5B-Instruct实现中文命名实体识别任务的端到端流程:

  1. 数据准备:选用CLUENER2020数据集并转换为结构化输出格式;
  2. 模型适配:通过对话模板引导模型理解NER任务意图;
  3. 训练实现:基于PyTorch和HuggingFace Transformers完成全参数微调;
  4. 推理验证:模型能够稳定输出JSON格式的实体识别结果。

💡核心价值总结: - 利用大模型强大的泛化能力和结构化输出能力,简化传统NER流水线 - 0.5B小模型即可胜任专业NLP任务,适合资源受限场景 - 指令微调范式易于迁移到其他信息抽取任务(如关系抽取、事件识别)

未来可进一步探索: - 结合LoRA进行高效微调,节省显存 - 引入Few-shot Prompt提升少样本性能 - 部署为API服务或Web应用


💡获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1154566.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一文说清LCD与MCU间8080时序接口的设计要点

LCD与MCU的8080并行接口&#xff1a;从原理到实战的深度解析在嵌入式开发中&#xff0c;一块能稳定显示、快速刷新的屏幕&#xff0c;往往是产品成败的关键。而当你选择使用TFT-LCD模块时&#xff0c;大概率会遇到这样一个名字——8080时序接口。它不像SPI那样“温柔”&#xf…

AI人脸隐私卫士本地处理优势:完全数据自主权部署方案

AI人脸隐私卫士本地处理优势&#xff1a;完全数据自主权部署方案 1. 引言&#xff1a;为何需要本地化的人脸隐私保护&#xff1f; 随着社交媒体和数字影像的普及&#xff0c;个人照片中的人脸信息暴露风险日益加剧。无论是家庭合照、会议记录还是公共监控截图&#xff0c;一旦…

Java Web 网站系统源码-SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0【含文档】

摘要 随着互联网技术的快速发展&#xff0c;Web应用系统在企业信息化建设和个人生活中扮演着越来越重要的角色。传统单体架构的Web系统在可维护性、扩展性和开发效率方面存在诸多不足&#xff0c;而基于前后端分离的现代化架构逐渐成为主流趋势。SpringBoot作为轻量级的Java开发…

HunyuanVideo-Foley无障碍设计:为视障人士生成描述性音效

HunyuanVideo-Foley无障碍设计&#xff1a;为视障人士生成描述性音效 1. 技术背景与社会价值 随着人工智能技术的不断演进&#xff0c;多媒体内容的智能化生成能力正在深刻改变数字世界的交互方式。2025年8月28日&#xff0c;腾讯混元正式开源了HunyuanVideo-Foley——一款端…

HunyuanVideo-Foley未来展望:下一代音效生成模型演进方向

HunyuanVideo-Foley未来展望&#xff1a;下一代音效生成模型演进方向 随着AI生成技术在音视频领域的深度融合&#xff0c;腾讯混元于2025年8月28日宣布开源其端到端视频音效生成模型——HunyuanVideo-Foley。该模型实现了从“无声画面”到“声画同步”的跨越式突破&#xff0c…

Keil5在工控开发中的安装与基础设置操作指南

Keil5工控开发环境搭建全攻略&#xff1a;从安装到实战配置 在工业自动化现场&#xff0c;你是否曾因开发工具卡顿、烧录失败或调试无响应而耽误项目进度&#xff1f;一个稳定可靠的嵌入式开发环境&#xff0c;往往是决定工控固件能否按时交付的关键。尤其当你面对的是PLC主控…

深度学习毕设选题推荐:基于python-CNN卷积神经网络深度学习训练识别马路是否有坑洼

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

隐私保护合规难题破解:AI人脸卫士企业级部署实战案例

隐私保护合规难题破解&#xff1a;AI人脸卫士企业级部署实战案例 1. 引言&#xff1a;企业数据合规中的隐私脱敏挑战 随着《个人信息保护法》&#xff08;PIPL&#xff09;和《数据安全法》的全面实施&#xff0c;企业在处理图像、视频等多媒体数据时面临前所未有的合规压力。…

【收藏+转发】AI大模型架构师职业完全指南:知识背景、任职要求与高薪前景

AI大模型架构师是融合软件架构、机器学习和系统设计的高级技术角色&#xff0c;负责设计、实现和优化大规模AI模型系统。需掌握深度学习、分布式系统、高性能计算等多领域知识&#xff0c;计算机、人工智能、数学等专业是理想背景。工作内容包括设计AI架构、优化算法性能、跟踪…

GLM-4.6V-Flash-WEB企业落地:金融票据识别实战

GLM-4.6V-Flash-WEB企业落地&#xff1a;金融票据识别实战 &#x1f4a1; 获取更多AI镜像 想探索更多AI镜像和应用场景&#xff1f;访问 CSDN星图镜像广场&#xff0c;提供丰富的预置镜像&#xff0c;覆盖大模型推理、图像生成、视频生成、模型微调等多个领域&#xff0c;支持一…

Java SpringBoot+Vue3+MyBatis 人事系统系统源码|前后端分离+MySQL数据库

摘要 随着信息技术的快速发展&#xff0c;企业人事管理系统的数字化转型成为提升管理效率的关键。传统人事管理依赖手工操作和纸质文档&#xff0c;存在效率低、数据易丢失、查询困难等问题。现代企业亟需一套高效、稳定且易于维护的人事管理系统&#xff0c;以实现员工信息管…

测试可访问性地图服务:构建数字出行的无障碍通道

一、可访问性测试的技术价值重构 在Web内容无障碍指南(WCAG) 2.1 AA级标准全球普及的背景下&#xff0c;地图服务的无障碍缺陷将直接导致&#xff1a; 1.2亿全球视障用户无法获取导航服务 老年用户群体操作流失率提升300% 企业面临GDPR合规风险&#xff08;欧盟罚款可达年营…

GLM-4.6V-Flash-WEB实战案例:医疗影像辅助诊断部署

GLM-4.6V-Flash-WEB实战案例&#xff1a;医疗影像辅助诊断部署 智谱最新开源&#xff0c;视觉大模型。 1. 引言&#xff1a;为何选择GLM-4.6V-Flash-WEB用于医疗影像诊断&#xff1f; 随着人工智能在医疗领域的深入应用&#xff0c;视觉大模型&#xff08;Vision-Language Mod…

计算机深度学习毕设实战-基于python-CNN卷积神经网络训练识别马路是否有坑洼

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

4.42 RAG系统调参指南:从向量维度到检索数量,参数调优完整攻略

4.42 RAG系统调参指南:从向量维度到检索数量,参数调优完整攻略 引言 本文提供RAG系统调参指南,从向量维度到检索数量的完整参数调优攻略。 一、调参参数 1.1 关键参数 # RAG调参 def rag_hyperparameters():"""RAG系统参数"""print(&quo…

MediaPipe Pose部署实测:低配笔记本也能流畅运行?

MediaPipe Pose部署实测&#xff1a;低配笔记本也能流畅运行&#xff1f; 1. 引言&#xff1a;AI人体骨骼关键点检测的轻量化突破 在计算机视觉领域&#xff0c;人体姿态估计&#xff08;Human Pose Estimation&#xff09;是一项基础且关键的技术&#xff0c;广泛应用于动作…

HunyuanVideo-Foley benchmark:建立音效生成领域的标准评测集

HunyuanVideo-Foley benchmark&#xff1a;建立音效生成领域的标准评测集 1. 引言&#xff1a;音效生成的挑战与 HunyuanVideo-Foley 的突破 1.1 视频音效生成的技术瓶颈 在影视、短视频和游戏内容创作中&#xff0c;高质量的音效是提升沉浸感的关键。传统音效制作依赖人工配…

HunyuanVideo-Foley直播辅助:预生成应急音效包应对突发情况

HunyuanVideo-Foley直播辅助&#xff1a;预生成应急音效包应对突发情况 1. 背景与挑战&#xff1a;直播中的声音盲区 在实时直播场景中&#xff0c;画面内容瞬息万变&#xff0c;而音频的缺失或不匹配往往成为影响观众体验的关键短板。传统做法依赖人工音效师现场操作&#x…

计算机深度学习毕设实战-基于python-CNN卷积神经网络识别昆虫基于机器学习python-CNN卷积神经网络识别昆虫

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

MediaPipe Hands实战指南:21个

MediaPipe Hands实战指南&#xff1a;21个关键点实现高精度手势识别与彩虹骨骼可视化 1. 引言&#xff1a;AI 手势识别与追踪的现实价值 随着人机交互技术的不断演进&#xff0c;手势识别正逐步成为智能设备、虚拟现实&#xff08;VR&#xff09;、增强现实&#xff08;AR&am…