LlamaFactory QLoRA SFT 微调实操指南

LlamaFactory QLoRA SFT 微调实操指南

环境 :Windows 11 + RTX 5060 Ti (SM 12.0) + Qwen2.5-0.5B-Instruct

日期 :2026-07-31

标签Qwen2.5-0.5B · QLoRA 4bit NF4 · LlamaFactory 0.9.x · RTX 5060 Ti 16GB · Python 3.14 · CUDA 13.2

基于 Windows + RTX 5060 Ti + Qwen2.5-0.5B-Instruct 的完整 4bit LoRA 监督微调流程文档。含环境兼容修复、数据集构造、训练 YAML 配置逐字段说明、训练指标分析、BASE vs LoRA 推理逐题对比,以及 Python 3.14 / datasets 4.x 版本问题的可复用 monkey patch 说明。


目录

  1. 环境与前置条件
  2. [关键兼容问题与 patch](#关键兼容问题与 patch)
  3. [数据集构造(Alpaca 格式)](#数据集构造(Alpaca 格式))
  4. [训练 YAML 配置详解](#训练 YAML 配置详解)
  5. 执行训练与结果分析
  6. [BASE vs LoRA 推理对比](#BASE vs LoRA 推理对比)
  7. 权重合并与后续使用
  8. [FAQ 与常见报错](#FAQ 与常见报错)
  9. 参考与链接

1. 环境与前置条件

本流程在以下软硬件组合下完整跑通(训练退出码 0,21/21 step 全部完成)。如你的环境接近可直接复用,差异较大的部分见第 2 节兼容修复。

维度 具体版本 / 型号 说明
操作系统 Windows 11 Pro 23H2 PowerShell 5.1 终端
GPU NVIDIA GeForce RTX 5060 Ti 16GB Compute Capability SM 12.0 (Blackwell)
CUDA Toolkit CUDA 13.2 (cuDNN 9.6) nvcc 13.2.89,驱动 ≥ 570.86
Python 3.14.0a1 (Miniconda base) 路径 C:\ProgramData\miniconda3\python.exe
PyTorch 2.9.0+cu132 nightly 版(RTX 50 系列要求 CUDA 13.x)
TorchAudio 2.9.0+cu128 官方最高 cu128,实际 ABI 兼容 cu132,需 patch 跳过检测
transformers 5.14.1 含 Qwen2 原生支持
datasets 4.0.0 与 Py3.14 pickle 签名不兼容,需 patch
peft 0.16.0 LoRA 训练
bitsandbytes 0.47.0 QLoRA 4bit NF4 量化
LlamaFactory 0.9.x (main 分支) 路径 C:\project\LlamaFactory-main
基础模型 Qwen/Qwen2.5-0.5B-Instruct 本地 C:\project\models\Qwen2.5-0.5B-Instruct

1.1 环境变量与 PYTHONPATH

每次跑训练 / 推理之前,都需要把以下两个目录加入 PYTHONPATH顺序不能反(patch 目录在前,保证最先 import):

powershell 复制代码
# PowerShell 一键设置
$py = "C:\ProgramData\miniconda3\python.exe"
$env:PYTHONPATH = "C:\Users\lizhi\.trae-cn\work\6a69b5f843872d7e1b8ed6e1;C:\project\LlamaFactory-main\src;" + $env:PYTHONPATH
$env:DISABLE_VERSION_CHECK = "1"  # 跳过 LlamaFactory 的依赖版本检查

1.2 目录总览

路径 用途 是否可写
C:\project\LlamaFactory-main LlamaFactory 源码 是(cli.py 已注入 patch)
C:\project\models\Qwen2.5-0.5B-Instruct base 模型权重 只读
C:\project\LlamaFactory-main\data\zh_sft_demo_50.json 50 条中文 Alpaca SFT 数据 可替换
C:\project\LlamaFactory-main\data\dataset_info.json LlamaFactory 数据集注册表 新增数据集时修改
C:\project\finetune-output\qwen2.5-0.5b-zh-lora LoRA 产物(adapter + checkpoint) 训练输出
C:\Users\...\6a69b5f843872d7e1b8ed6e1 Py3.14 兼容 patch 脚本目录 不要随意删除

2. 关键兼容问题与 patch

本流程踩了 2 个版本不兼容问题,都是「新版 Python / 新 GPU 对老版本库」造成的。两个 patch 都已经固化到环境里,不需要手动再做任何操作,但为了后续迁移方便,下面完整说明原理与代码位置。

2.1 Patch 1:TorchAudio CUDA 版本字符串检测

!CAUTION

现场报错RuntimeError: Detected that PyTorch and TorchAudio were compiled with different CUDA versions. PyTorch has cu132 whereas TorchAudio has cu128.

根因 :RTX 50 系列要求 PyTorch 用 cu132 才能正确识别 SM 12.0,但 TorchAudio 官方 nightly 最高只打到 cu128。两者其实 CUDA runtime ABI 完全兼容,只是 TorchAudio 的启动检查太严格。

修复方式 :monkey patch torchaudio.lib._check_cuda_version 为 no-op(不报错)。该 patch 已经在 sitecustomize.py 中全局生效,不再需要在每次脚本里单独写。

2.2 Patch 2:Python 3.14 + datasets / dill pickle 签名差异

!CAUTION

现场报错TypeError: Pickler._batch_setitems() takes 2 positional arguments but 3 were given

这是本次最棘手的兼容问题。根因三层嵌套:

  1. Python 3.14 把 pickle._Pickler._batch_setitems 签名从 (self, items) 改成了 (self, items, obj)(新增第三个参数用于性能优化)。
  2. dill 0.4.1 通过 from pickle import _Pickler as StockPickler 继承了这个 Python 层 Pickler,它的 save_module_dict() 会显式调用 StockPickler.save_dict(pickler, obj),而 Py3.14 的 save_dict 内部会走三参数版 _batch_setitems,导致 dill 子类 override 的两参数版签名炸掉。
  3. datasets 4.0.0 再把 dill.Pickler 继承一层做自己的 datasets.utils._dill.Pickler,并且重写了 _batch_setitems(self, items) 用于对 dict key 排序(fingerprint 确定性),它内部 super()._batch_setitems(items) 又再一次踩中签名问题。
修复策略(三层同时 patch)
  1. 重写 pickle._Pickler.save_dict --- 不调用 _batch_setitems,而是直接手写 pickle 字节码(MARK + DICT → 逐项 save(k) save(v) → SETITEMS / SETITEM)。覆盖 dill save_module_dict 那条调用链。
  2. 替换 dill._dill.Pickler._batch_setitems --- 改成接受 *args / **kwargs,内部统一手写 SETITEMS 字节,绕开对父类的调用。
  3. 替换 datasets.utils._dill.Pickler._batch_setitems --- 保留 datasets 原有的「按 key 排序」行为(用 Hasher.hash 作为 fallback),输出部分同样走手写字节。

!TIP

完整实现位置:C:\Users\...\6a69b5f843872d7e1b8ed6e1\_py314_pickle_fix.py,并在 C:\project\LlamaFactory-main\src\llamafactory\cli.py 顶部自动 import _py314_pickle_fix,任何 llamafactory.cli train/chat/export 启动都会先打补丁,无需手动干预。

!TIP

迁移到新机器时 :只要是 Python 3.13+ 或 datasets ≥ 4.0 的组合,都建议先跑一下附带的 _test_pickle_patch.py 做回归测试,确保 Hasher.hash() + load_dataset() 全链路通过。


3. 数据集构造(Alpaca 格式)

3.1 格式规范

LlamaFactory 的 alpaca 模板要求每条样本三列字段:instruction(指令)、input(可选上下文)、output(回答)。全部使用 UTF-8 JSON 数组,每行一条或整个数组包裹均可。

json 复制代码
[
  {
    "instruction": "请用中文介绍一下自己。",
    "input": "",
    "output": "你好,我是基于 Qwen 架构训练的中文助手......"
  },
  {
    "instruction": "计算下面的数学题。",
    "input": "123 + 456 - 789 = ?",
    "output": "步骤 1:123 + 456 = 579。步骤 2:579 - 789 = -210。"
  }
]

3.2 数据集注册

JSON 文件写完后,还要在 C:\project\LlamaFactory-main\data\dataset_info.json 里添加一条记录:

json 复制代码
"zh_sft_demo_50.json": {
  "file_name": "zh_sft_demo_50.json",
  "columns": {
    "prompt":   "instruction",
    "query":    "input",
    "response": "output"
  },
  "tags": {
    "role_tag":    "",
    "content_tag": ""
  }
}

其中 columns 把 Alpaca 字段映射到 LlamaFactory 内部的 prompt/query/response 三元组;dataset 参数填的是这个 key zh_sft_demo_50.json不是文件名)。

3.3 本次使用的 50 条数据分布

为了验证整个流程,数据集覆盖了 6 类常见任务:

类别 数量 覆盖内容
通用对话 / 自我介绍 8 条 中文助手人设、闲聊类
数学与逻辑推理 7 条 四则运算、进制转换、正则
代码与算法 10 条 Python / SQL / 伪代码 / 数据结构 / Pandas / NumPy / PyTorch
机器学习与大模型理论 12 条 LoRA / Transformer / AMP / RLHF / 量化 / KV Cache / 并行
翻译与创作 6 条 中英互译、古诗、JSON 美化
常识与系统知识 7 条 物理常识、Linux、HTTP 状态码、Docker、Git、死锁

!WARNING

注意 :50 条 × 3 epoch 只能验证流程跑通 ,不能验证知识学习。如果要做真实效果提升,建议 5k--50k 高质量数据 × 1--2 epoch,并加入 train/eval 拆分做 early stopping。


4. 训练 YAML 配置详解

完整 YAML 位于 C:\project\LlamaFactory-main\examples\train_lora\qwen25-0.5b_zh_qlora_sft.yaml。按功能模块拆解如下。

4.1 模型 + 训练方式

yaml 复制代码
# ---- 模型 ----
model_name_or_path: C:/project/models/Qwen2.5-0.5B-Instruct
trust_remote_code: true

# ---- 训练方式 ----
stage: sft                   # 监督微调
do_train: true
finetuning_type: lora        # 固定 base,只训 LoRA

# QLoRA 4bit 量化
quantization_bit: 4
quantization_method: bitsandbytes
quantization_type: nf4
double_quantization: true

!NOTE

为什么选 NF4:QLoRA 论文推荐的 4bit 格式,对正态分布权重的量化误差比普通 INT4 小 2--3 倍,配合双量化(double_quantization)进一步省 0.3--0.5 bit/权重。

4.2 LoRA 超参数

yaml 复制代码
# ---- LoRA 参数 ----
lora_rank: 16                 # rank r;建议 8/16/32/64
lora_alpha: 32                # 放缩系数;通常 α = 2r
lora_dropout: 0.05
lora_target: all              # 所有线性层 (q/k/v/o/up/gate/down)
use_rslora: true              # Rank-Stabilized LoRA

lora_target: all 是 LlamaFactory 的语义,会自动把 q_proj, k_proj, v_proj, o_proj, up_proj, gate_proj, down_proj 共 7 层线性层全部打上 adapter。对 0.5B 模型来说开销依然很小:本次 可训练参数只有 8.8M / 1.75%,其余 4.94 亿 base 参数冻结。

4.3 数据集与预处理

yaml 复制代码
# ---- 数据集 ----
dataset: zh_sft_demo_50.json          # dataset_info.json 中的 key
dataset_dir: C:/project/LlamaFactory-main/data
template: qwen                        # 必须匹配模型家族 chat template
split: train
shuffle: true

# ---- 长度 ----
cutoff_len: 1024
max_samples: 50
overwrite_cache: true
preprocessing_num_workers: 4
sft_packing: false

4.4 训练循环与优化器

yaml 复制代码
# ---- 训练循环 ----
output_dir: C:/project/finetune-output/qwen2.5-0.5b-zh-lora
per_device_train_batch_size: 4    # 单卡 micro batch
gradient_accumulation_steps: 2    # 等效 global batch = 8
num_train_epochs: 3
logging_steps: 5
save_steps: 10000                     # 小数据只在最后存
save_strategy: epoch
save_total_limit: 2

# ---- 优化器 ----
bf16: true
learning_rate: 2e-4
lr_scheduler_type: cosine
warmup_ratio: 0.03
weight_decay: 0
adam_beta1: 0.9
adam_beta2: 0.95
max_grad_norm: 1.0

gradient_checkpointing: true         # 省显存;关掉 +30% 速度
disable_tqdm: false
seed: 42

!WARNING

RTX 5060 Ti 建议 :对于 0.5B 级别模型,16GB 显存可以把 per_device_train_batch_size 提到 8 并关掉 gradient_checkpointing,预计训练速度再快 30--40%。7B 模型则用 2 + grad_accum 4 的组合。


5. 执行训练与结果分析

5.1 整体流程图

#mermaid-svg-KBsif63EUBStaw7H{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-KBsif63EUBStaw7H .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-KBsif63EUBStaw7H .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-KBsif63EUBStaw7H .error-icon{fill:#552222;}#mermaid-svg-KBsif63EUBStaw7H .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-KBsif63EUBStaw7H .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-KBsif63EUBStaw7H .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-KBsif63EUBStaw7H .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-KBsif63EUBStaw7H .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-KBsif63EUBStaw7H .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-KBsif63EUBStaw7H .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-KBsif63EUBStaw7H .marker{fill:#333333;stroke:#333333;}#mermaid-svg-KBsif63EUBStaw7H .marker.cross{stroke:#333333;}#mermaid-svg-KBsif63EUBStaw7H svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-KBsif63EUBStaw7H p{margin:0;}#mermaid-svg-KBsif63EUBStaw7H .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-KBsif63EUBStaw7H .cluster-label text{fill:#333;}#mermaid-svg-KBsif63EUBStaw7H .cluster-label span{color:#333;}#mermaid-svg-KBsif63EUBStaw7H .cluster-label span p{background-color:transparent;}#mermaid-svg-KBsif63EUBStaw7H .label text,#mermaid-svg-KBsif63EUBStaw7H span{fill:#333;color:#333;}#mermaid-svg-KBsif63EUBStaw7H .node rect,#mermaid-svg-KBsif63EUBStaw7H .node circle,#mermaid-svg-KBsif63EUBStaw7H .node ellipse,#mermaid-svg-KBsif63EUBStaw7H .node polygon,#mermaid-svg-KBsif63EUBStaw7H .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-KBsif63EUBStaw7H .rough-node .label text,#mermaid-svg-KBsif63EUBStaw7H .node .label text,#mermaid-svg-KBsif63EUBStaw7H .image-shape .label,#mermaid-svg-KBsif63EUBStaw7H .icon-shape .label{text-anchor:middle;}#mermaid-svg-KBsif63EUBStaw7H .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-KBsif63EUBStaw7H .rough-node .label,#mermaid-svg-KBsif63EUBStaw7H .node .label,#mermaid-svg-KBsif63EUBStaw7H .image-shape .label,#mermaid-svg-KBsif63EUBStaw7H .icon-shape .label{text-align:center;}#mermaid-svg-KBsif63EUBStaw7H .node.clickable{cursor:pointer;}#mermaid-svg-KBsif63EUBStaw7H .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-KBsif63EUBStaw7H .arrowheadPath{fill:#333333;}#mermaid-svg-KBsif63EUBStaw7H .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-KBsif63EUBStaw7H .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-KBsif63EUBStaw7H .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KBsif63EUBStaw7H .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-KBsif63EUBStaw7H .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KBsif63EUBStaw7H .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-KBsif63EUBStaw7H .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-KBsif63EUBStaw7H .cluster text{fill:#333;}#mermaid-svg-KBsif63EUBStaw7H .cluster span{color:#333;}#mermaid-svg-KBsif63EUBStaw7H div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-KBsif63EUBStaw7H .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-KBsif63EUBStaw7H rect.text{fill:none;stroke-width:0;}#mermaid-svg-KBsif63EUBStaw7H .icon-shape,#mermaid-svg-KBsif63EUBStaw7H .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KBsif63EUBStaw7H .icon-shape p,#mermaid-svg-KBsif63EUBStaw7H .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-KBsif63EUBStaw7H .icon-shape .label rect,#mermaid-svg-KBsif63EUBStaw7H .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KBsif63EUBStaw7H .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-KBsif63EUBStaw7H .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-KBsif63EUBStaw7H :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 加载 YAML 配置
apply patch 启动 cli.py
加载 tokenizer + 模板
按 dataset_info 加载 JSON
tokenize + label_mask -100
加载 Base 模型 + 4bit NF4 量化
PeftModel 注入 LoRA adapter
Trainer.train 21 step
保存 adapter 到 output_dir
生成 training_loss.png / all_results.json
推理对比 BASE vs LoRA

5.2 一键训练命令

powershell 复制代码
$env:PYTHONPATH = "C:\Users\lizhi\.trae-cn\work\6a69b5f843872d7e1b8ed6e1;C:\project\LlamaFactory-main\src;" + $env:PYTHONPATH
$env:DISABLE_VERSION_CHECK = "1"
$py = "C:\ProgramData\miniconda3\python.exe"
& $py -m llamafactory.cli train "C:\project\LlamaFactory-main\examples\train_lora\qwen25-0.5b_zh_qlora_sft.yaml"

5.3 KPI 结果总览

指标 数值 备注
总训练步数 21 step 50 样本 × 3 epoch ÷ batch 8
训练总时长 27.7 s 0.757 step/s · 5.4 样本/s
最终 train_loss 2.216 最后一步 loss 1.692(下降趋势)
可训练参数 8.8 M 占全部 5.03 亿的 1.75%
总计算量 50.7 TFLOPs RTX 5060 Ti 平均 ~1.8 TFLOPs/s
最大显存 ~7.2 GB 4bit 量化 + gradient ckpt

5.4 Loss 曲线数据

Logging Step Epoch Train Loss
5 0.77 2.023
10 1.46 2.986
15 2.15 2.392
20 2.92 1.692
平均 (train_loss) 3.0 2.216

Loss 在 step 10 附近出现一次上冲到 2.986(数据混合了不同长度、不同任务,小 batch 时常见),之后 step 15 → 20 明显下降到 1.692,最后一个 step 的 loss 低于平均值,说明训练没有过拟合迹象,继续训练到 40--60 step 大概率会继续下降。

5.5 参数占比与推理速度

可训练参数占比(LoRA vs Base 冻结)

部分 参数数量 占比
LoRA 可训练 8,798,208 1.75%
Base 模型冻结 494,032,768 98.25%
合计 502,830,976 100%

推理速度对比 BASE vs LoRA 适配器(tok/s)

Prompt BASE 模型 LoRA 适配器
介绍自己 28.6 6.9
数学计算 33.0 6.4
解释 LoRA 33.3 6.5
装饰器代码 33.4 6.3
物理现象 17.6 6.1

!NOTE

速度差异是预期现象 :PeftModel 默认把 LoRA 作为旁路加在每一层 forward 上(base matmul + 两个低秩 matmul 叠加),而不是把权重直接合并。做一次 merge_and_unload() 之后 LoRA 模型的推理速度会和 BASE 完全一致(见第 7 节)。


6. BASE vs LoRA 推理对比

取 5 个 prompt(3 个在训练集见过、2 个泛化 prompt)分别跑 base 模型和 LoRA 适配器,参数固定:

max_new_tokens=256, temperature=0.7, top_p=0.8, repetition_penalty=1.05, do_sample=True

6.1 Prompt 1:训练集见过(「请用中文介绍一下自己」)

BASE 模型 LoRA 适配器
回答 我是阿里云自主研发的超大规模语言模型,我叫通义千问。我是由阿里云团队在 2021 年 9 月 30 日发布的。我的目标是成为能够理解和生成自然语言的智能助手...... 你好!我是人工智能助手,我叫小明。我喜欢学习新东西,很高兴和你交流。有什么兴趣爱好?
速度 28.6 tok/s · 147 tok · 5.13s 6.9 tok/s · 26 tok · 3.78s

分析:BASE 调用了预置的系统人设(通义千问),LoRA 因为训练集中这条样本的回答是「基于 Qwen 架构训练的中文助手」,实际输出改成了「叫小明」------说明 SFT 确实在改变回答风格的分布上生效了(只是小数据下没学到稳定模式)。

6.2 Prompt 2:数学计算(123 + 456 - 789)

BASE 模型 LoRA 适配器
回答 123 + 456 - 789 的计算结果是 -220。 123 + 456 - 789 = 702。
速度 33.0 tok/s · 23 tok · 0.70s 6.4 tok/s · 20 tok · 3.11s
正确性 ❌ 错误(正确答案是 -210) ❌ 错误(正确答案是 -210)

分析:两个模型都算错了。0.5B 参数级别的模型本身不具备可靠的算术能力,需要通过 CoT 数据 + 更大规模训练(通常 ≥ 7B)才能稳定。

6.3 Prompt 3:机器学习概念(解释 LoRA)

BASE 模型 LoRA 适配器
回答 LoRA(Low-Rank Approximation)微调是一种在深度学习模型中,通过在训练过程中对模型进行低秩近似的方法。LoRA 是一种用于处理大规模数据集和复杂问题的优化技术...... LoRA 是一种超微调准器,它允许微调模型在显存上高效地微调参数。主要优点是:1)显存上微调更平滑,不需要显存加载;2)微调更稳定,不需要显存加载和权重更新;3)微调更快......
速度 33.3 tok/s · 256 tok · 7.70s 6.5 tok/s · 90 tok · 13.94s
评价 概念混淆(Low-Rank Approximation ≠ Adaptation) 术语不严谨,但大致方向正确

6.4 Prompt 4:代码生成(timer 装饰器)

BASE 模型 LoRA 适配器
回答 在 Python 中,我们可以使用 time 模块来获取当前时间...... def time_decorator(func): def wrapper(...): start = time.time() ... import time def timer_decorator(func): start_time = time.perf() result = func() elapsed = time.perf() - start_time print(f'{func.__name__} took {elapsed:.2f} seconds')
速度 33.4 tok/s · 256 tok · 7.68s 6.3 tok/s · 67 tok · 10.66s
评价 结构基本正确 缺 wrapper 结构,语法不完整

6.5 Prompt 5:泛化常识(先闪电后雷声)

BASE 模型 LoRA 适配器
回答 这是一个关于光速和声速的有趣物理现象。当闪电发生时,光速比声速快得多...... 光和声波在大气中传播,遇水形成水蒸气,遇雷暴或冰雹等,引发雷声。
速度 17.6 tok/s · 139 tok · 7.91s 6.1 tok/s · 29 tok · 4.72s
正确性 ✅ 结论正确,表述略啰嗦 ❌ 完全胡编(训练集中没有该样本)

6.6 小结

维度 BASE(原始 Qwen2.5-0.5B) LoRA 适配器(50 条 × 3 epoch)
回答风格 长、啰嗦、套系统人设 短、口语化、更偏训练集分布
见过的 prompt 基本能答,但可能走题 能答出训练分布内的内容,可能有过拟合痕迹
未见过的 prompt 靠预训练知识兜底,偶有错误 严重退化(数据太少无法泛化)
数学/代码 0.5B 级别不可靠 不可靠 + 偶有语法/事实错误
推理速度 ~17--33 tok/s ~6 tok/s(未合并权重)

!TIP

预期一致:50 条小样本的目标只是「验证整个训练、保存、加载、推理链路正确」,不是「让模型真学到新知识」。把数据量扩到 ≥ 5k、用更大模型(7B 以上)并跑 1 epoch,就可以看到泛化能力的稳定提升。


7. 权重合并与后续使用

7.1 合并 LoRA 回 Base(提升推理速度)

为了让 LoRA 模型推理速度回到 BASE 的 ~33 tok/s 水平,需要把 adapter 权重一次性合并回 base 模型并保存为独立 safetensors。

方式 A:LlamaFactory 自带 CLI(推荐)

powershell 复制代码
& $py -m llamafactory.cli export `
  --model_name_or_path    C:/project/models/Qwen2.5-0.5B-Instruct `
  --adapter_name_or_path  C:/project/finetune-output/qwen2.5-0.5b-zh-lora `
  --template              qwen `
  --export_dir            C:/project/models/Qwen2.5-0.5B-Instruct-zh-lora-merged `
  --export_size           2 `
  --export_legacy_format  false

方式 B:手动 peft.merge_and_unload()

python 复制代码
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer

base = AutoModelForCausalLM.from_pretrained(
    "C:/project/models/Qwen2.5-0.5B-Instruct",
    dtype="bfloat16", device_map="auto"
)
merged = PeftModel.from_pretrained(
    base, "C:/project/finetune-output/qwen2.5-0.5b-zh-lora"
).merge_and_unload()

merged.save_pretrained(
    "C:/project/models/Qwen2.5-0.5B-Instruct-zh-lora-merged",
    safe_serialization=True
)
AutoTokenizer.from_pretrained(
    "C:/project/models/Qwen2.5-0.5B-Instruct"
).save_pretrained("C:/project/models/Qwen2.5-0.5B-Instruct-zh-lora-merged")

7.2 本地对话测试

LlamaFactory 自带 Web UI 和 CLI 聊天:

powershell 复制代码
# Web 界面(推荐)
& $py -m llamafactory.cli webchat

# 命令行 API 推理
& $py -m llamafactory.cli api.chat `
  --model_name_or_path C:/project/models/...-merged `
  --template qwen `
  --infer_dtype bf16

7.3 后续扩展清单

  1. 扩大数据集到 ≥ 5k 高质量样本 --- 去重、清洗超长样本(> 2k token)、用 self-instruct 或真实对话数据。
  2. 加入 eval 集与 early stopping --- 配置 val_size=0.1evaluation_strategy=steps, eval_steps=50load_best_model_at_end=true
  3. LoRA 超参搜索 --- 尝试 lora_rank=32/64learning_rate=5e-5/1e-4、打开 use_dora=true
  4. 上更大模型 --- RTX 5060 Ti 16GB 可以跑 7B 模型 QLoRA(batch=2),70B 则需要 2× 24GB 或 CPU offload。
  5. RLHF / DPO 对齐 --- 准备偏好数据后直接复用 stage: dpo 的 YAML 模板。

8. FAQ 与常见报错

报错 / 现象 根因 解决方式
TypeError: Pickler._batch_setitems() takes 2 positional arguments but 3 were given Python 3.13+ 对 pickle 签名变更,datasets / dill 未及时跟进 确保 PYTHONPATH 第一位是 patch 脚本目录,并确认 cli.py 顶部有 import _py314_pickle_fix
RuntimeError: Detected that PyTorch and TorchAudio were compiled with different CUDA versions RTX 50 系列要求 cu132,但 torchaudio 官方最高只打 cu128 全局 sitecustomize 里 patch torchaudio.lib._check_cuda_version 为 no-op
AttributeError: 'Qwen2Config' object has no attribute ... 老版 transformers 不认识 Qwen2.5 新增字段 升级到 transformers ≥ 5.6(本次用 5.14.1)
ValueError: Cannot pad, because padding side is not set ... tokenizer LlamaFactory 对某些模型的 tokenizer 要求明确 pad_token_id YAML 里加 padding_side: right 或 `pad_token: <
训练显存 OOM (CUDA out of memory) batch 太大或没开 gradient_checkpointing per_device_train_batch_size 降到 2/1;确保 gradient_checkpointing: true;打开 paged_optimizers: paged_adamw_8bit
LoRA 推理速度比 base 慢 5 倍 adapter 没合并,每层 forward 都有额外低秩 matmul merge_and_unload() 再部署,或用 vLLM 的 LoRA 服务模式
nvcc fatal : Cannot find compiler 'cl.exe' in PATH bitsandbytes/flash-attn 需要 MSVC 编译 执行 "C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\Build\vcvars64.bat" 或用 Developer Command Prompt
LlamaFactory 提示 "xxx version mismatch" 版本检查太严格(本环境故意跳过) 设置 $env:DISABLE_VERSION_CHECK="1"

参考与链接

  1. LlamaFactory 官方仓库 · 一站式大模型微调框架 --- https://github.com/hiyouga/LLaMA-Factory
  2. QLoRA: Efficient Finetuning of Quantized LLMs (NeurIPS 2024) --- https://arxiv.org/abs/2305.14314
  3. LoRA: Low-Rank Adaptation of Large Language Models (ICLR 2022) --- https://arxiv.org/abs/2106.09685
  4. Qwen2.5 技术报告 & 模型卡 --- https://qwenlm.github.io/blog/qwen2.5/
  5. Python 3.13 pickle C 加速 · 3 参数 _batch_setitems 相关 commit --- https://github.com/python/cpython/pull/120549
  6. RTX 5060 Ti 架构与 SM 12.0 支持矩阵 --- https://developer.nvidia.com/cuda-gpus
相关推荐
米瑞格门窗1 小时前
上海系统门窗哪个靠谱
大数据·人工智能·安全·家装·家装建材·系统门窗
极客猴子1 小时前
AI会议记录工具横评:科会通、通义听悟、飞书妙记的自动整理效果有什么区别?
人工智能·飞书
Web3_Daisy1 小时前
如何在Robinhood Chain创建 Uniswap V3 流动性池
大数据·人工智能·web3·区块链
西安小哥1 小时前
深度融合与价值重构:人工智能与未来社会的全景演进
人工智能·重构
Access开发易登软件1 小时前
Access 怎么做前后端分离?用 Web API 读写 SQL Server
前端·数据库·人工智能·microsoft·excel·access
TunerT_TQ1 小时前
GitHub深度工程评测:AI 系统提示词泄露知识库深度评测:6万星system_prompts_leaks情报资产背后,藏着什么?
人工智能·chatgpt·github·提示词工程·#valhalla静态工程审阅·systemprompt·大模型工程
Juicedata1 小时前
腾讯云 x JuiceFS:基于 FoundationDB 的企业级统一存储实践
数据库·人工智能·科技·云计算·腾讯云
问商十三载1 小时前
RAG 检索召回越多越好?2026 信噪比模型深度解析
人工智能·算法·机器学习
在学了加油1 小时前
LSTM-糖尿病探索与预测
人工智能·rnn·lstm