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

轻量化微调 Qwen2.5 LoRA 训练全流程详解

视频链接:https://www.bilibili.com/video/BV1FGKz6FEqk/?vd_source=5ba34935b7845cd15c65ef62c64ba82f

代码仓库:https://github.com/LitchiCheng/LLM-learning

分享下使用LoRA进行微调LLM的学习,选择Qwen2.5-0.5B-INstruct,参数量很小,应该随便一台机器都可以训练,这里HF可能下载比较慢,训练的模型

https://www.modelscope.cn/models/Qwen/Qwen2.5-0.5B-Instruct

从魔搭下载

参考例子

https://huggingface.co/docs/peft/index

tokenizer

from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True) tokenizer.pad_token = tokenizer.eos_token

加载对应的分词器,每个汉字/英文单词都会被拆成若干 token ID,在模型眼中就是数字

训练时不同样本长度不同,需要把短序列补到统一长度,eos就是end of sequence,用这个填充,并且告知模型这句话到这儿结束了

.cache/modelscope/models/qwen--Qwen2.5-0.5B-Instruct/snapshots/master/tokenizer.json 中可以看到 ID

模型加载

from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained( model_path, torch_dtype=torch.float16, device_map="auto", trust_remote_code=True )

把模型加载到内存中,dtype决定加载到显存中的权重的类型,可以修改,比如qwen2.5下载下来是fp16,可以改成float32,但显存就会多占一倍

print(f" Params: {sum(p.numel() for p in model.parameters()):,}")

每个张量加起来的总和,共0.49B的参数量

LoRA原理

原始模型的一层线性变换:y = Wx + b,W 是一个大矩阵(比如 4096×4096)。不直接改 W,而是在旁边挂两个小矩阵 A 和 B:y = (W + B·A) · x + b

W: 原始权重(冻结不动) 4096 × 4096

A: 随机初始化的小矩阵 4096 × r

B: 随机初始化的小矩阵 r × 4096

r: 秩(rank),控制小矩阵的大小

因为 B·A 的乘积秩最多是 r,所以只训练 A 和 B ,用最精华的特征来调整,就能近似地"修补"W。

from peft import LoraConfig, get_peft_model, TaskType print("\nConfiguring LoRA...") lora = LoraConfig( r=16, lora_alpha=32, target_modules=[ "q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj" ], lora_dropout=0.05, bias="none", task_type=TaskType.CAUSAL_LM ) model = get_peft_model(model, lora) trainable = sum(p.numel() for p in model.parameters() if p.requires_grad) total = sum(p.numel() for p in model.parameters()) print(f" OK: Trainable {trainable:,} / {total:,} ({100*trainable/total:.2f}%)")

参数

含义

r=16

LoRA 的秩(rank)。A 是in_dim × 16,B 是16 × out_dim

r 越大,可训练参数量越多,微调能力越强,但显存/时间也越多

常用 8、16、64

lora_alpha=32

LoRA 的缩放系数。实际效果是(alpha / r) × B·A = (32/16) × B·A = 2 × B·A

一般设为 r 的 2 倍

target_modules

只在这几层加 LoRA,其他层的权重冻结。选了注意力机制(q/k/v/o)和前馈网络(gate/up/down),覆盖了 Transformer 的主要计算路径

lora_dropout=0.05

LoRA 层的 dropout,防止过拟合

bias="none"

不在 bias 上施加 LoRA(bias 本身参数少,加了收益不大)

task_type=TaskType.CAUSAL_LM

告诉 PEFT 这是因果语言模型任务

ChatML

https://huggingface.co/docs/transformers/chat_templating

samples = [ {"messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "你是谁?"}, {"role": "assistant", "content": "你是LitchiCheng微调的Qwen2.5模型"}]}, {"messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "你是谁微调的?"}, {"role": "assistant", "content": "LitchiCheng"}]}, {"messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "你是不是标准的Qwen2.5模型?"}, {"role": "assistant", "content": "不是,我是LitchiCheng微调的模型"}]}, ] def format_sample(s): return {"text": tokenizer.apply_chat_template(s["messages"], tokenize=False, add_generation_prompt=False)} dataset = Dataset.from_list([format_sample(s) for s in samples]) print(f" OK: {len(dataset)} samples")

按照OpenAI的ChatML格式,system 告知角色,User 作为输入,assistant 作为输出

微调训练

args = TrainingArguments( output_dir=output_dir, per_device_train_batch_size=1, gradient_accumulation_steps=4, learning_rate=2e-4, max_steps=100, logging_steps=1, save_steps=10, fp16=True, report_to="none", ) trainer = SFTTrainer(model=model, train_dataset=dataset, args=args) start = time.time() result = trainer.train() elapsed = time.time() - start print(f"\n OK: Done in {elapsed:.1f}s") print(f" Loss: {result.training_loss:.4f}") print(f" Speed: {result.global_step/elapsed:.2f} steps/sec") # 保存 model.save_pretrained(f'{output_dir}/lora') tokenizer.save_pretrained(f'{output_dir}/lora')

微调测试

如下为完整代码,测试提问是什么模型,看它怎么回答?

#!/usr/bin/env python3 """Qwen2.5 微调推理脚本 - 加载 LoRA 权重进行推理""" import os, sys, time import torch CACHE_DIR = os.path.join(os.path.dirname(__file__), ".cache", "modelscope", "models", "qwen--Qwen2.5-0.5B-Instruct", "snapshots", "master") BASE_MODEL = CACHE_DIR LORA_DIR = "fine_tune_output/20260718_212052/lora" print("Loading tokenizer...") from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained(LORA_DIR, trust_remote_code=True) tokenizer.pad_token = tokenizer.eos_token print(f" OK: Vocabulary size {len(tokenizer)}") # 加载基座模型 + LoRA 权重 print("\nLoading base model...") from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained( BASE_MODEL, torch_dtype=torch.float16, device_map="auto", trust_remote_code=True ) # 用 PEFT 加载 LoRA adapter 并合并到基座模型 print("Loading LoRA weights...") from peft import PeftModel model = PeftModel.from_pretrained(model, LORA_DIR) model = model.merge_and_unload() # 将 LoRA 权重合并进基座,释放 LoRA 内存 print(f" OK: Model loaded, params: {sum(p.numel() for p in model.parameters()):,}") # 用 chat template 做正式对话测试 print("\nChat test:") messages = [ {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "你是什么模型"}, ] prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) inputs = tokenizer(prompt, return_tensors="pt").to(model.device) with torch.no_grad(): out = model.generate(**inputs, max_new_tokens=100) resp = tokenizer.decode(out[0], skip_special_tokens=True)[len(tokenizer.eos_token):].strip() print(f" {resp}") print("\n" + "="*60) print("Fine-tuning inference test passed!") print("="*60)

http://www.jsqmd.com/news/1229439/

相关文章:

  • 2026丹东数码家电回收排名 TOP5 回收办公电脑显示器,废旧空调冰柜洗衣机高价回收 手机回收无套路 联系方式推荐 - 诚金汇钻回收公司
  • 3步重塑3D创作:Hunyuan3D-2如何革新AI驱动的高分辨率资产生成
  • 2026保山奢侈品回收排名 TOP5 国家资质 名表 + 名包 + 钻石回收、劳力士 + LV + 香奈儿回收 无套路 联系方式推荐 - 中业金奢再生回收中心
  • Linux平台总线驱动开发详解与实战
  • 签约桌上的隐形防线:二级商户审视一级直付通的法务底线
  • Typstyle 未来路线图:即将推出的令人兴奋的新功能
  • 生产管理优化:打破信息壁垒,实现数据闭环
  • Objective-C开发者必看:iOS-Tech-Weekly中的经典技术与现代实践
  • CSV.swift核心功能详解:从字符串到文件的全方位读写技巧
  • 武汉宝玑官方直营售后维修网点|官网备案正规维保渠道完整名录(2026 年 7 月最新) - 宝玑官方售后服务中心
  • Django ORM 深度优化指南:从 N+1 到企业级性能调优
  • 小说推文怎么自动分角色配音?5款小说配音实测横评
  • GPU显存健康检测:5分钟掌握memtest_vulkan精准诊断显卡故障
  • C++负数求余问题解析:从原理到实战修正方案
  • 非技术人转行,最稳的方式不是学代码,而是找准岗位入口
  • 从理论到实践:如何将美妙而空荡的技术概念转化为生产级解决方案
  • 搞懂张量(Tensor)—— 从矩阵到高阶抽象
  • AM263P FSI通信与SDFM配置实战:从寄存器到电机控制应用
  • MissingDrawer性能优化:如何避免内存泄漏和资源浪费
  • 揭秘RPCS3:如何在PC上完美重温PS3经典游戏的终极指南
  • CSV.swift高级用法:自定义编码解码策略与错误处理最佳实践
  • 基于RIPv2的全网互通及路由优化实验
  • OData.NET:终极指南 - 掌握微软开源OData协议.NET库
  • MES 制造执行:工单、报工、质检、追溯,制造业数字化的轻量起步
  • 2026泸州江阳区黄金回收避坑指南|三大三十年口碑品牌实测,全境免费上门阳光交易 - 得天独厚
  • 南京AI搜索排名优化公司推荐,三大头部机构实力对比 - 品牌评测官
  • 电源管理芯片(PMIC)技术解析与选型指南
  • Roo Code深度解析:如何将整个AI开发团队装进你的代码编辑器?
  • explicit-architecture-php部署指南:Docker环境下的Symfony架构应用最佳配置
  • 2026 杭州钻石回收红榜|奢二网门店测评,钻戒裸钻行情梳理对比 - 每日生活报