【LoRA】一篇文章带你入门QLoRA微调

  • 时间:2025-11-07 13:55 作者: 来源: 阅读:0
  • 扫一扫,手机访问
摘要:整理不易,请不要吝啬你的赞和收藏。 1. 前言 这篇文章将通过一次微调内部代码数据集,带你了解 QLoRA 微调的整个流程,包括如何选择模型,下载模型,如何搭建微调环境,训练时该注意哪些参数,要如何配置能达到较好的效果等等。 接下来,我们先了解目前大模型微调(Fine-tuning)有哪些主流方案,根据训练目标、硬件条件、模型规模和任务类型不同,通常可以分为三大类:全参数微调、参数高效微调(

整理不易,请不要吝啬你的赞和收藏。

1. 前言

这篇文章将通过一次微调内部代码数据集,带你了解 QLoRA 微调的整个流程,包括如何选择模型,下载模型,如何搭建微调环境,训练时该注意哪些参数,要如何配置能达到较好的效果等等。

接下来,我们先了解目前大模型微调(Fine-tuning)有哪些主流方案,根据训练目标、硬件条件、模型规模和任务类型不同,通常可以分为三大类:全参数微调、参数高效微调(PEFT)、指令/对齐微调

1.1 主流微调方案介绍

1.1.1 全参数微调 (Full Fine-Tuning):

原理

对预训练模型中的所有参数(如Transformer的所有层、注意力权重、词嵌入等)进行梯度更新,而不仅仅是新增或部分参数。 也就是说,在训练过程中,会对整个模型(数十亿甚至上千亿参数)都进行反向传播和梯度优化。

优点

精度最高,可以完全拟合新任务可适用于领域迁移(如法律、医疗、工业等特定语料)没有额外推理时开销(不依赖 adapter 层或 LoRA 权重)

缺点

显存占用极高训练耗时长容易遗忘预训练知识保存下来的模型文件体积巨大

适用场景

模型完全重构特定领域(例如“医疗问诊模型”、“法律咨询模型”)。

1.1.2 参数高效微调(PEFT)

原理

PEFT 是一类只微调模型中极少部分参数的方法,它在保持原始模型绝大多数参数冻结(不更新)的同时,通过增加或调整少量参数,让模型适应新的任务或领域。

其核心思想是:冻结模型大部分参数,只训练一小部分“可插拔层 。对比全参数微调,其效果接近甚至相同,但显存开销大幅减少。是目前的主流方案。、

优点

显存占用低(通常节省 90%)训练速度快(10x+)可并行训练多个任务(多适配器)方便部署(按需加载)

缺点

模型性能上限略低于全参数微调容易在极端领域"欠拟合"需要开发者具备一定的调优能力推理阶段开销略增,PEFT 不是纯粹修改原模型权重,而是额外添加模块 。在推理时, 需要在模型中加载 LoRA 的 delta 权重(A、B矩阵),并进行矩阵加法运算。

常见微调方法

方法核心思想显存需求适用场景
LoRA在每个线性层添加低秩矩阵极低(<20%)各类任务通用
QLoRA在量化模型基础上应用 LoRA极低(适合单卡)消耗更少显存
Prefix Tuning在输入前添加可学习的前缀向量生成类任务
Adapter Tuning在 Transformer 层间插入可训练小模块分类任务
BitFit只训练 bias 参数很低小范围微调
IA³训练少量缩放参数很低通用、快速适配

1.1.3 指令/对齐微调

指令微调(Instruction Fine-tuning)对齐微调(Alignment Fine-tuning) 是目前使大模型变得「听话」「有用」「符合人类价值观」的关键技术环节。

定义

指令微调的目的是让模型学会理解指令、生成符合意图的回答 ,模型对齐第一阶段。

对齐微调的目的是 让模型学会符合人类偏好、安全、礼貌 ,模型对齐第二阶段。

为什么需要指令/对齐微调?

预训练语言模型(Pre-trained LM)虽然掌握了大量知识,但它只是**“补全下一个词”**的机器,它不知道“用户的问题”是什么意思,也不知道该“有条理地回答”。

例如:


用户:请帮我写一封道歉信  
原始LM:道歉信是一种书信体...

它会解释“什么是道歉信”,而不是直接写信。这说明它没学过“指令 → 输出”这种模式。所以我们要通过指令微调教它:“当我说‘帮我写一封道歉信’,不是让你定义,而是让你生成。”。

优点

让模型理解人类意图、遵循指令显著提升可用性和人机交互体验

缺点

需要高质量指令数据(构造成本高)容易学习数据偏见或错误模式

1.2 LoRA介绍

上面大致介绍了目前主流的微调方案,下面我们进入本篇文章的主题。

1.2.1 什么是 LoRA?

LoRA,全称 Low-Rank Adaptation of Large Language Models,即大语言模型的低秩适应,是一种用于微调大型语言模型的技术。论文:《LoRA: Low-Rank Adaptation of Large Language Models》

核心思想

LoRA的核心思想是通过低秩分解来建模模型参数的更新。它在微调时冻结预训练模型的权重,仅在指定层(如 Transformer 的 attention 投影层)中注入两个可训练的低秩矩阵,从而大幅减少可训练参数量。

工作原理


原理:

1.2.2 什么是QLoRA?

QLoRA(Quantized Low-Rank Adapter)全称是量化低秩适配器微调,其结合了量化和低秩适配(LoRA)技术,以在低资源环境下实现模型的高效微调,同时保持性能。 论文: 《QLoRA: Efficient Finetuning of Quantized LLMs》 。

下图是不同的微调方法和它们的内存需求。QLoRA 通过将 transformer 模型量化为 4 位精度,并使用分页优化器来处理内存峰值,从而改进了 LoRA。

2. 模型下载

HuggingFace 和 ModelScope(魔塔社区) 是目前主流的机器学习开发和共享平台,我们可以在上面进行模型下载。基于网络问题,我这里使用 ModelScope 下载模型。

(PS:我的电脑信息,win11 系统,英伟达 5070Ti 移动端显卡,显存 12GB)

2.1 配置环境变量

首先我们先配置环境变量 MODELSCOPE_CACHEHF_HOME。配置后模型会默认下载到该路径下,便于管理。


# 值为自己的目录,我这里全部配置成一个路径,方便管理模型
MODELSCOPE_CACHE = D:workspacepackagesmodelscope_cache
HF_HOME = D:workspacepackagesmodelscope_cache

2.2 如何选择模型

2.2.1 选择多大参数的模型

以下为不同微调方式、精度、模型参数所需的显存大小预估,信息摘自 LLaMA-Factory 。

你可以根据自己电脑的显存配置选择适合的模型。

方法精度7B14B30B70B x B
Full ( bf16 or fp16)32120GB240GB600GB1200GB 18xGB
Full ( pure_bf16)1660GB120GB300GB600GB 8xGB
Freeze/LoRA/GaLore/APOLLO/BAdam1616GB32GB64GB160GB 2xGB
QLoRA810GB20GB40GB80GB xGB
QLoRA46GB12GB24GB48GB x/2GB
QLoRA24GB8GB16GB24GB x/4GB

2.3 下载模型

初步筛选

基于如下框架的模型可用于微调:LoRA 、Transformers 、PyTorch 、TensorFlow 等。

二次确认

点击模型详情,如果出现如下 ‘训练’ / ‘Train’ 标识,说明该模型是支持微调,当然有些模型不带 ‘训练’ 也可以微调,具体参考模型提供商介绍文档。

ModelScope:

HuggingFace:

下载

Qwen/Qwen2.5-Coder-7B-Instruct 模型为例,我这里使用命令行下载。


# 1. 安装 ModelScope
pip install modelscope

# 2. 下载完整模型库
modelscope download --model Qwen/Qwen3-4B-Instruct-2507

3. 数据集准备

本文主要介绍如何制作 Alpaca格式 和 ShareGPT格式 的数据集。

3.1 Alpaca格式

该格式数据集通常用于单轮指令微调(instruction tuning)。

格式:


[
  {
    "instruction": "指令",
    "input": "输入(可选)",
    "output": "输出"
  }
]

样例:


[
  {
    "instruction": "解释什么是量子纠缠。",
    "input": "",
    "output": "量子纠缠是指两个或多个粒子之间存在的量子态关联..."
  }
]

# 或者带有输入的情况

[
  {
    "instruction": "将下面的句子翻译为英语。",
    "input": "我喜欢机器学习。",
    "output": "I like machine learning."
  }
]

适用场景:单轮任务、领域特定微调(如问答、文本生成)。

3.2 ShareGPT格式

该格式数据集通常用于 多轮对话微调(chat tuning)。

标准格式:每行包含conversations字段,记录多轮对话,每轮有role(human/assistant)和content。


[
  {
    "conversations": [
      {"from": "human", "value": "你好!你是谁?"},
      {"from": "assistant", "value": "我是一个AI语言模型,很高兴见到你!"},
      {"from": "human", "value": "你能帮我写个Python算法吗?"},
      {"from": "assistant", "value": "当然可以!请告诉我算法的具体需求。"}
    ]
  }
]

变体:OPenAI格式


[
  {
    "messages": [
      {"role": "user", "content": "问题"},
      {"role": "assistant", "content": "回答"}
    ]
  }
]

适用场景:多轮对话、聊天机器人训练、RLHF预训练。

3.3 我的数据集

我微调的是内部的前端框架代码,数据集采用的 Alpaca 格式,以下是部分示例:
原始内容:


/**
  * 编辑某行记录
  * @method editRow
  * @param  {String} rowid    行id
  * @param  {Object} [option] 参数对象,内置'oper=edit'用来区分操作行为
*/
editRow: function (rowid, o) {
   this.getGrid().grid('editRow',rowid, o);
},

整理后的数据集:


  {
    "instruction": "请实现GridView的editRow方法",
    "input": "编辑某行记录",
    "output": "```js
		/**
		 * 编辑某行记录
		 * @method editRow
		 * @param {String} rowid 行id
		 * @param {Object} [option] 参数对象,内置'oper=edit'用来区分操作行为
		 */
		editRow: function (rowid, o) {
			this.getGrid().grid('editRow',rowid, o);
		},
		```"
  },
  {
    "instruction": "解释GridView中editRow方法的作用",
    "input": "",
    "output": "- 编辑某行记录。"
  },
  {
    "instruction": "editRow方法的参数有哪些?",
    "input": "",
    "output": "| 参数 | 类型 | 描述 |
|------|------|------|
| rowid | String | 行id |
| option | Object | 参数对象,内置'oper=edit'用来区分操作行为 |"
  }

建议

确保每个样本的代码是完整的,可运行的。同一个任务用不同的描述方式。

4. 环境准备

4.1 创建项目

建议使用 虚拟环境 管理 python 依赖,我这里使用 uv (也可以使用 conda)。


# 1. 安装 uv
pip install uv

# 2. 使用 uv 创建一个项目(先进入自己的项目工作空间)
uv init train-demo

# 3. 进入项目
cd .	rain-demo

# 4. 创建基于 python 3.11 的虚拟环境
uv venv --python=3.11

# 5. 使用PyCharm等IDE打开项目

项目目录结构如下:


good_train/
└── src/
    ├── datas/
    │   └── code_alpaca.json                 # 训练数据
    └── examples/
        └── code/
            ├── train_code.py                # 训练脚本
            ├── test_inference.py            # 推理脚本
            ├── merge_lora.py                # 合并脚本
            └── output/                      # 输出目录

其中 code_alpaca.json 为数据集,train_code.py 为微调代码,merge_lora.py 为合并LoRA权重代码,test_inference.py 为测试推理代码,目录 output 为微调后输出目录。

4.2 PyTorch安装

显卡对应的 Pytorch 版本可参考我之前的文章:

【踩坑笔记】50系显卡适配的 PyTorch 安装_cuda13.0对应pytorch-CSDN博客


# 1. 先卸载(可选)
uv pip uninstall torch torchvision

# 2. 安装 Pytorch 
uv pip install torch torchvision --index-url https://download.pytorch.org/whl/cu129

# 3. 验证,返回 True 说明安装成功
uv run python -c "import torch; print(torch.cuda.is_available())"

4.3 量化和微调工具包安装

安装 HuggingFace 生态和微调工具包:

# 1. 安装 HuggingFace 生态和微调工具包
uv pip install transformers datasets accelerate peft bitsandbytes safetensors

# 2. 安装 modelscope, 需要其 snapshot_download 加载 modelscope 下载的模型
uv pip install modelscope

介绍:

包名关键词主要作用
transformers预训练模型加载、训练、推理 BERT/GPT/LLaMA/Qwen 等各种 Transformer 模型。提供 pipeline Trainer 等高层接口。
datasets数据集处理高效下载、加载和切分数据集,支持 TB 级数据的内存映射。
accelerate分布式/混合精度简化多 GPU/TPU 训练、自动混合精度(fp16/bf16)。
peft参数高效微调支持 LoRA、Prefix Tuning、P-Tuning 等,只训练少量参数,显著降低显存需求。
bitsandbytes4bit/8bit 量化提供高效 8bit/4bit 量化加载与训练,配合 transformers 直接 load_in_4bit=True
safetensors安全权重格式更快更安全的模型权重文件格式( .safetensors),替代 .bin/ .pt

典型组合:

大模型推理: transformers + bitsandbytes + safetensorsLoRA/PEFT 微调: transformers + datasets + accelerate + peft (+ bitsandbytes)

4.4 我的本地库信息


torch: 2.8.0+cu129
transformers: 4.57.0
datasets: 4.1.1
peft: 0.17.1
modelscope: 1.31.0

5. 代码实现

下面将通过一步步讲解带你了解完整的 QLoRA 微调流程实现,完整代码将在文末提供

5.1 定义基本变量

定义数据集来源、数据输出目录以及模型文件。
注意: 这里我使用 modelscope 的仓库下载模型(如果你之前没有预下载模型,将会自动从该仓库下载模型),之后使用 transformers 来训练模型。


current_dir = os.path.dirname(os.path.abspath(__file__))
data_path = os.path.join(current_dir, "../../datas/code_alpaca.json")
output_dir = os.path.abspath(os.path.join(current_dir, "./output/qwen2.5-7b-qlora"))
os.makedirs(output_dir, exist_ok=True)

model_name = snapshot_download("Qwen/Qwen2.5-Coder-7B-Instruct")

5.2 量化加载模型(QLoRA)

配置 bitsandbytes 量化工具参数

# 配置 bitsandbytes 量化工具
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_use_double_quant=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.float16,
)

BitsAndBytesConfig类是 transformers 库中用于配置 bitsandbytes 量化工具 的配置类。其作用是通过量化(将模型参数从 32 位 / 16 位压缩到 4 位或 8 位)来显著减少模型的内存占用,同时尽可能保留模型性能,使得大模型能在资源有限的设备(如消费级 GPU)上运行或训练。

以下是其常用参数:

参数类型默认值说明
load_in_4bit bool False是否启用 4-bit 量化 True 表示启用)。与 load_in_8bit 互斥。
load_in_8bit bool False是否启用 8-bit 量化 True 表示启用)。与 load_in_4bit 互斥。
bnb_4bit_quant_type str "nf4"4-bit 量化类型,可选: "fp4"(浮点4位)或 "nf4"(正态优化4位,推荐)。仅在 load_in_4bit=True 时生效。
bnb_4bit_use_double_quant bool True是否启用 双重量化(double quantization),进一步压缩模型权重,降低显存占用。仅对 4bit 量化有效。
bnb_4bit_compute_dtype torch.dtype torch.float16计算时的精度类型,推荐 torch.float16 torch.bfloat16。仅对 4bit 量化有效。
llm_int8_threshold float 6.0离群值阈值。激活值超过该阈值的部分会使用 FP16 计算,以减少精度损失。仅对 8bit 量化有效。
llm_int8_has_fp16_weight bool False是否在 int8 模型中同时保留 FP16 权重,用于减少精度损失(通常不需要开启)。
llm_int8_enable_fp32_cpu_offload bool False是否将部分 FP32 计算卸载到 CPU,以节省显存。仅对 8bit 模型有效。
加载模型

model = AutoModelForCausalLM.from_pretrained(
    model_name,
    quantization_config=bnb_config,
    device_map="auto",
    trust_remote_code=True,
)

AutoModelForCausalLM.from_pretrained() transformers 库中用于从本地或远程加载预训练好的大语言模型,并返回一个可直接用于推理或微调的模型实例 。AutoModelForCausalLM 会自动选择适合“Causal Language Modeling(因果语言建模)”任务的模型类,比如 QwenForCausalLM、LlamaForCausalLM 等。

以下是其常用参数:

参数名类型默认值说明
pretrained_model_name_or_path str无(必填)模型名称或本地路径。可为: - HuggingFace/ModelScope 上的模型ID(如 "Qwen/Qwen2.5-Coder-7B-Instruct") - 本地模型路径(如 "./local_model"
quantization_config BitsAndBytesConfig None量化配置(如 BitsAndBytesConfig GPTQConfig),用于加载低精度量化模型(4bit/8bit)。
device_map str / dict "auto"设备分配策略:
"auto":自动分配到可用设备(优先 GPU,剩余到 CPU)
"cpu":全加载到 CPU
"cuda":全加载到 GPU
"字典":手动指定层到设备映射(如 {"lm_head": 0, "transformer.layers.0": 1} 多卡)
trust_remote_code bool False是否信任远程代码(当模型包含自定义 modeling_*.py 时需设为 True)
torch_dtype torch.dtype None模型加载的数据类型(如 torch.float16 torch.bfloat16 torch.float32),影响精度与内存占用。
low_cpu_mem_usage bool True启用低 CPU 内存模式(加载时减少内存峰值,适合大模型)。
use_safetensors bool True是否优先使用 .safetensors 权重文件(更安全、更快)。
cache_dir str None指定模型缓存路径(若未设置,默认使用 ~/.cache/huggingface/transformers)。
local_files_only bool False是否只从本地加载(不联网)。
offload_folder str None当显存不足时,部分层可临时卸载到磁盘路径(需配合 device_map="auto")。
加载 tokenizer 并设置 padding token

用于配置分词器的补齐(padding)行为,确保在批量处理文本时格式兼容。


tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token

5.3 配置 LoRA 适配层

1. LoraConfig 用于定义 LoRA 微调的所有可选参数,其是`peft`库中用于配置 **LoRA **微调方法的核心类。

lora_config = LoraConfig(
    r=8,
    lora_alpha=16,
    target_modules=[ "q_proj", "k_proj", "v_proj", "o_proj", "up_proj", "down_proj", "gate_proj" ],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM",
)
# 将LoRA应用到模型
model = get_peft_model(model, lora_config)

核心参数解析:

参数名类型默认值说明
r int 8LoRA 的秩(rank),控制低秩矩阵的维度。值越小,参数越少、计算越快,但可能限制表达能力。常见取值:4、8、16、32。
lora_alpha int 32LoRA 的缩放因子,与 r 共同决定低秩矩阵输出的权重(更新量 = 低秩矩阵输出 × (alpha/r))。通常设为 r 的 2-4 倍(如 r=8 时 alpha=16)。
target_modules List[str] ["q_proj", "v_proj"]指定应用 LoRA 的模型模块(因模型而异)。
1)LLaMA/OPT 类: q_proj, v_proj(基础)或 q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj(全注意力 + MLP,增强能力);
2)BERT 类: query, value
建议参考同模型 SOTA 配置,避免漏改层名(如不同版本模型层名可能有差异)。
lora_dropout float 0.05LoRA 层的 dropout 比例,防止过拟合。常设 0.05。
bias str "none"是否微调偏置项: none(不微调,默认,省显存)、 all(微调所有偏置)、 lora_only(仅微调 LoRA 相关偏置)。小样本任务可尝试 lora_only 提升性能,大模型建议 none 控制参数规模。
task_type str "CAUSAL_LM"任务类型,决定 LoRA 适配的模型输出头类型。常见值:
1) "CAUSAL_LM":因果语言模型(文本生成)
2) "SEQ_CLASSIFICATION":序列分类
3) "TOKEN_CLASSIFICATION":token 分类
4) "SEQ_2_SEQ_LM":序列到序列模型

可选参数解析:

参数名类型默认值说明
modules_to_save List[str] None除 LoRA 层外,还要保存的模块名称。例如 ["lm_head"]
layers_to_transform List[int] None仅在指定的层注入 LoRA(按层号索引)。
layers_pattern str None模型层命名规则,例如 "decoder_layer",通常配合 layers_to_transform 使用。
fan_in_fan_out bool False控制 LoRA 权重矩阵乘法顺序,某些模型(如 GPT-NeoX)需设为 True
enable_lora List[bool] None对应每个 target_module,是否启用 LoRA。
use_rslora bool False是否使用 Rank-Stabilized LoRA(改进版 LoRA,训练更稳定)。
init_lora_weights str "gaussian"LoRA 权重初始化方式。可选 "gaussian" "kaiming" "zeros" 等。
inference_mode bool False是否为推理模式(禁用梯度更新)。
use_dora bool False是否启用 DoRA,一种新的低秩替代方案(Dynamic Rank Adaptation)。
rank_pattern Dict[str, int] None为不同模块指定不同的 LoRA 秩 r(可覆盖全局设置)。

拓展:

Transformer 类模型下各模块(target_modules)介绍:

模块名所属层功能LoRA 加入作用
q_projMulti-Head Attention (MHA) 多头自注意力将输入映射到 Query 向量调整注意力查询的特征表示,改变注意力聚焦模式
k_projMHA将输入映射到 Key 向量调整注意力的匹配机制,影响“看哪里”
v_projMHA将输入映射到 Value 向量改变注意力加权后的信息输出
o_projMHA 输出将多头注意力输出映射回隐藏维度调整注意力信息整合后的输出
up_projFeed-Forward Network (MLP) 前馈网络FFN 的上投影矩阵改变中间隐藏层信息流
down_projFFNFFN 的下投影矩阵控制 FFN 输出的表示能力
gate_projFFN / Gated Linear Unit (GLU)FFN 中 gate 控制矩阵调整信息流的门控机制,对输出风格有影响
q_proj、k_proj、v_proj、o_proj 直接参与注意力计算,决定模型对上下文的理解和信息聚合能力。up_proj、down_proj、gate_proj 是前馈网络的核心,负责特征的非线性变换和增强,影响模型的表达能力。

5.4 加载与格式化数据集

将本地 Alpace 格式数据集转换成标准 Prompt 加载。

# 加载 Alpaca 数据集
dataset = load_dataset("json", data_files=data_path)
full_dataset = dataset["train"]

# 划分训练数据集和验证数据集
split_dataset = full_dataset.train_test_split(test_size=0.05, seed=42)
train_data = split_dataset["train"]
eval_data = split_dataset["test"]

# 格式化数据集
def format_batch(batch):
    prompts = []
    for inst, inp, outp in zip(batch["instruction"], batch["input"], batch["output"]):
        if not inst or not outp:  # 跳过空样本
            continue

        if inp:
            text = (
                f"### 指令:
{inst.strip()}

"
                f"### 输入:
{inp.strip()}

"
                f"### 回复:
{outp.strip()}"
            )
        else:
            text = (
                f"### 指令:
{inst.strip()}

"
                f"### 回复:
{outp.strip()}"
            )

        prompts.append(text)

    tokenized = tokenizer(
        prompts,
        truncation=True,
        max_length=1024,
        padding="max_length",
        return_tensors=None,
    )
    return tokenized

# 用 tokenizer 进行编码
tokenized_train = train_data.map(format_batch, batched=True, remove_columns=train_data.column_names)
tokenized_eval = eval_data.map(format_batch, batched=True, remove_columns=eval_data.column_names)

5.5 定义训练参数


training_args = TrainingArguments(
    output_dir=output_dir,	# 模型输出目录
    per_device_train_batch_size=1,	# 每个设备(GPU/CPU)的训练批次大小;显存小可设为 1~2
    per_device_eval_batch_size=1,	 
    gradient_accumulation_steps=8,	# 梯度累积步数,等效于 batch_size × steps
    warmup_steps=100,	# 学习率预热步数有助于训练稳定
    # max_steps=10,     # 最大训练步数或者使用 num_train_epochs
    num_train_epochs=3, 
    learning_rate=2e-5,	# 学习率;
    weight_decay=0.01,
    fp16=True,	 # 是否启用半精度训练(float16)
    eval_strategy=IntervalStrategy.STEPS, # 验证策略:按步数间隔进行验证
    eval_steps=90,
    save_strategy=SaveStrategy.STEPS,
    save_steps=90,
    save_total_limit=3,
    load_best_model_at_end=True,
    metric_for_best_model="eval_loss",
    greater_is_better=False,

    logging_steps=30,	# 日志打印间隔步数;每 1 步记录一次 loss、lr 等信息
    report_to="none",
    prediction_loss_only=True,
)

TrainingArguments transformers 库中用于配置模型训练过程的核心类,它封装了几乎所有训练相关的参数(如训练轮数、学习率、批处理大小、日志设置等),无需手动编写训练循环,可直接与 Trainer 类配合使用,大幅简化训练流程。

核心训练参数,直接影响微调效果:

参数名类型默认值说明
learning_rate float 5e-5学习率影响模型收敛速度与稳定性。LoRA/QLoRA 推荐 2e-5 ~ 2e-4(视模型规模调整:7B 模型可偏上限,13B+ 模型建议偏下限);小数据可适当偏大(如 1e-4),但需配合早停避免过拟合;微调全量参数时建议 1e-5 ~ 5e-5
warmup_ratio / warmup_steps float / int 0.0 / 0学习率预热阶段,避免初期震荡。建议 0.03~0.1(即总步数的 3%~10% 作为预热阶段),小样本 / 短训练可设固定步数(如 100~500);大模型(如 30B+)建议提高到 0.1~0.2
num_train_epochs int 3训练轮数。小数据集(<1k)建议 3~10,视过拟合情况调节(若验证集性能下降则提前终止);大数据集(>10k)可设 1~3,优先通过增大 batch 提升训练效率。。
per_device_train_batch_size int 8每个设备(GPU)上的训练 batch 大小。显存受限时可配合 gradient_accumulation_steps 控制等效 batch(建议等效 batch 在 16~64 之间,过小波动大,过大收敛慢)。
gradient_accumulation_steps int 1用于在显存受限时增大等效 batch(等效 batch = 单卡 batch × 卡数 × 积累步数)。常见 4~16(12GB 显存训练 7B 模型时推荐 8~16),但需注意积累步数过大会延缓参数更新频率。
weight_decay float 0.0L2 正则,防止过拟合。LoRA/小数据可设 0.01,过大会抑制学习。
lr_scheduler_type str "linear"学习率调度策略。
cosine 适合大多数场景(后期学习率缓慢下降,利于精细收敛);
linear 适合快速收敛;
constant 仅建议小样本且配合早停;
小样本/LoRA 推荐 "cosine"
optim str adamw_torch_fused / "adamw_torch"优化器类型。
PyTorch 版本 ≥ 2.8 时,默认值为 adamw_torch_fused(融合版 AdamW,速度更快)。
PyTorch 版本 < 2.8 时,默认值为 adamw_torch(普通版 AdamW,兼容性更广)。
max_grad_norm float 1.0梯度裁剪,防止梯度爆炸。默认 1.0 对多数任务足够;训练不稳定(loss 骤升)时可降至 0.5,稳定任务可提高到 2.0
fp16 / bf16 bool False半精度训练可大幅降低显存占用(约节省 50%),支持 bf16 GPU 可设 bf16=True
gradient_checkpointing bool False牺牲 ~20% 速度换取 ~40% 显存节省,12GB 显存训练 7B+ 模型强烈建议开启;全量微调或大 batch 场景必开。
eval_strategy str "no"建议 epoch(每轮评估)或 steps(按步评估)。小样本设 epoch(数据量小,轮次评估更有意义),大数据设 steps(如每 1000 步),便于及时监控过拟合。
eval_steps int None每多少步进行评估,小数据集可 50~200 步,大数据集可 1000~5000 步。
load_best_model_at_end bool False自动加载验证集性能最优模型,需配合 evaluation_strategy 使用。
max_steps int -1按步控制训练长度,优先于 num_train_epochs。小样本可 500~2000 步。 大数据可设 10000+;用于控制总更新次数,避免 epoch 计算受 batch 大小影响。
seed int 42保证实验可复现,多 seed 做平均减少随机性。
train_on_inputs bool TrueLoRA 指令微调是否计算 prompt loss,False 仅计算回答部分 loss。

其他重要参数:

参数名类型默认值说明
output_dir str模型输出目录,训练结果(模型、日志、检查点)保存目录。
overwrite_output_dir bool False若目录存在是否覆盖,慎用,避免误删重要模型。
per_device_eval_batch_size int 8每个设备上(GPU)的评估 batch 大小,大于训练 batch 可加速 eval,但不能超显存。
logging_steps int 500日志打印间隔,小样本可高频 10~50 步。
save_strategy str "steps"保存策略: "no", "steps", "epoch"
save_steps int 500保存间隔,建议与 eval_steps 对齐,便于回溯最优模型。
save_total_limit int None保留 checkpoint 数量,防止占满磁盘,建议 2~5。
save_safetensors bool True推荐 safetensors 格式,安全高效。
resume_from_checkpoint str None断点续训路径,保证数据与配置一致。
run_name str None实验名称,适配 wandb/tensorboard,可包含关键参数信息。
group_by_length bool False按序列长度分组 batch,减少 padding,提高效率,推荐 True。
report_to str / list ["tensorboard"]训练日志监控,可选 tensorboard / wandb / none
device str自动检测训练设备,单卡可 "cuda:0",多卡由 local_rank 控制。
local_rank int -1分布式进程索引,多卡训练必用,自动分配。
ddp_find_unused_parameters bool NoneLoRA 部分参数冻结时可设 True,否则 False 提高效率。
torch_compile bool FalsePyTorch 2.0+ 编译加速,LoRA/自定义层需测试兼容性。
tf32 bool NoneAmpere 及以上 GPU TensorFloat32 加速矩阵运算,可设 True。

5.6 开始训练


trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=tokenized_train,
    eval_dataset=tokenized_eval,
    data_collator=data_collator,
    callbacks=[
        # 监控训练过程中的内存(显存)使用情况,便于排查 OOM(内存溢出)问题
        MemoryMonitorCallback(),
        # 早停策略
        EarlyStoppingCallback(
            early_stopping_patience=3,
            early_stopping_threshold=0.001
        )
    ],
)

trainer.train()

Trainer transformers 库中的一个高级训练接口,封装了模型训练、验证、 num_train_epochs 评估的完整流程,支持单机单卡、单机多卡、多机多卡等多种训练模式,极大简化了 transformer 模型的训练代码编写。
参数解析:

参数名类型默认值说明
model nn.Module必填PyTorch 模型,可使用 AutoModelForXXX
args TrainingArguments必填训练参数配置。
train_dataset DatasetNone训练数据集(支持 HF Dataset 或 torch Dataset)。
eval_dataset DatasetNone验证/评估数据集。
tokenizer PreTrainedTokenizerNone用于数据编码和保存 tokenizer。
data_collator CallableNone用于生成 batch 的函数,支持 padding、mask 等。
compute_metrics CallableNone接收 predictions 和 labels 返回 metric dict 的函数。
callbacks List[TrainerCallback]None自定义训练回调,如 EarlyStopping。
optimizers (optimizer, scheduler)None自定义优化器和学习率调度器。

Trainer 提供训练、评估、预测、推理等 API :

方法说明
train(resume_from_checkpoint=None)开始训练,可选择从 checkpoint 恢复。
evaluate(eval_dataset=None)在验证集上进行评估,返回 metric dict。
predict(test_dataset)在测试集上进行预测,返回 PredictionOutput(predictions, label_ids, metrics)
compute_loss(model, inputs, return_outputs=False)可重写来自定义损失计算逻辑(用于 LoRA 或自定义任务)。
save_model(output_dir=None)保存当前模型及 tokenizer。
log(metrics)手动记录 metric,用于自定义日志记录。
push_to_hub(commit_message=None)将训练好的模型推送到 Hugging Face Hub。

进阶:

自定义 Callback ,定义一个每10步显示内存分配信息的回调以及过拟合检测回调。


class MemoryMonitorCallback(TrainerCallback):
    def on_log(self, args, state: TrainerState, control: TrainerControl, **kwargs):
        step = state.global_step
        if step % 10 == 0 or step == 1:
            print(f"
========== Step {step} ==========")
            if torch.cuda.is_available():
                print(f"已分配显存 = {torch.cuda.memory_allocated() / 1024 ** 3:.2f} GB")
                print(f"总预留显存 = {torch.cuda.memory_reserved() / 1024 ** 3:.2f} GB")

    def on_evaluate(self, args, state: TrainerState, control: TrainerControl, metrics=None, **kwargs):
        if metrics:
            eval_loss = metrics.get("eval_loss", 0)
            if len(state.log_history) > 1:
                train_loss = state.log_history[-2].get("loss", 0)
                print(f"
【过拟合检测】")
                print(f"  训练损失: {train_loss:.4f}")
                print(f"  验证损失: {eval_loss:.4f}")
                if eval_loss - train_loss > 0.5:
                    print(f"警告:可能出现过拟合!")

5.7 保存LoRA权重

保存 LoRA 权重

# 保存 LoRA 权重
# 把训练好的模型权重与分词器配置完整地保存到指定目录中,便于后续加载与推理
trainer.model.save_pretrained(output_dir)
tokenizer.save_pretrained(output_dir)

拓展: 后续如何使用训练好的模型权重和分词器配置。


from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel, PeftConfig

# 1. 加载 PEFT 配置
peft_model_dir = "./output"
config = PeftConfig.from_pretrained(peft_model_dir)

# 2. 加载基础模型
model = AutoModelForCausalLM.from_pretrained(config.base_model_name_or_path)

# 3. 将 LoRA 权重注入模型
model = PeftModel.from_pretrained(model, peft_model_dir)

# 4. 加载分词器
tokenizer = AutoTokenizer.from_pretrained(config.base_model_name_or_path)

5.8 训练日志

训练步数计算

我的总数据集为 531 条,其中训练数据集 504 条,验证数据集 27 条。
上图中 189 为训练总步数。其计算方式为:
总步数 = ceil( (训练样本数 × num_train_epochs) / 有效批次大小 )
有效批次大小 = per_device_train_batch_size × 设备数量(GPU/CPU数) × gradient_accumulation_steps
其中(num_train_epochs 、per_device_train_batch_size 和 gradient_accumulation_steps 为 TrainingArguments 的配置)


# 本文中
有效批次大小 = 1 * 1 * 8 = 8
总步数 = ceil(504 * 3) / 8 = 189

训练完成日志:

5.9 合并LoRA权重

合并 LoRA 权重到基础模型。

# 定义路径 
current_dir = os.path.dirname(os.path.abspath(__file__))
lora_dir = os.path.join(current_dir, "./output/qwen3-4b-qlora")
merged_dir = os.path.join(current_dir, "./output/qwen3-4b-qlora-merged")
model_name = snapshot_download("Qwen/Qwen3-4B-Instruct-2507")

# 加载完整精度的基础模型(不使用量化)
base_model = AutoModelForCausalLM.from_pretrained(
    model_name,
    torch_dtype=torch.float16,  # 使用 FP16,不使用 4-bit 量化
    device_map="auto",
    trust_remote_code=True,
)

# 加载 LoRA 权重
model_with_lora = PeftModel.from_pretrained(base_model, lora_dir)

# 合并 LoRA 权重
merged_model = model_with_lora.merge_and_unload()

# 保存合并后的模型
merged_model.save_pretrained(merged_dir)

# 保存 tokenizer
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
tokenizer.save_pretrained(merged_dir)

执行日志及生成的目录文件列表。

6. 效果测试

微调前后,输出内容对比,

前:

后:


可以看到模型的回答已经很接近我们的训练数据,但是还有很多不足,这需要我们不断的调整训练参数或者数据集来使其完美。这篇文章只是简单的微调教程,后续如何优化,我将在以后的博客中更新。

7. 完整代码

完整训练代码我已上传到 github : https://github.com/herogus/good_train

8. 参考文档

huggingface transformers 文档

huggingface peft 文档

Transformers 中文文档

llamafactory 中文文档

LoRA: Low-Rank Adaptation of Large Language Models

QLoRA: Efficient Finetuning of Quantized LLMs

  • 全部评论(0)
手机二维码手机访问领取大礼包
返回顶部