轻量化微调 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)
相关推荐
Cosolar19 小时前
深入理解 AI Agent:设计原理与工程实践
人工智能·面试·github
糖果店的幽灵20 小时前
【langgraph 从入门到精通graphApi 篇】Memory 与长期记忆
运维·服务器·人工智能·langgraph
火山引擎开发者社区20 小时前
一句话上线 AI Agent 应用:火山 Supabase + IGA Pages 全栈部署实践
人工智能
火山引擎开发者社区20 小时前
AI Agent 真正进入工作流:AgentKit CLI 打造云端沙箱开发环境
人工智能
蓝速科技20 小时前
蓝速 AI 双屏翻译机:实体商铺跨境沟通落地指南
人工智能
phltxy1 天前
LangChain从模型输出到RAG数据管道实战
服务器·人工智能·深度学习·语言模型·langchain
10x101 天前
企业 AI 真正的分水岭:不是人人都在用,而是工作方式被重新设计
人工智能
收放扳机1 天前
PCB产线的“柔性”是怎么实现的——从自动化上下料设备兼容性看产线弹性
人工智能·科技·自动化·制造·pcb工艺
一个天蝎座 白勺 程序猿1 天前
从电网改造踩坑说起:深度拆解时序大模型TimechoAI的自主可控与安全合规底气
大数据·运维·服务器·大模型·timechoai