发布于 ,更新于 

LLaMA-Factory微调实战

1. 资源

微调需要的硬件资源(显存),如果资源不够可以使用QLoRA(量化)

方法 精度 7B 14B 30B 70B xB
Full (bf16 or fp16) 32 120GB 240GB 600GB 1200GB 18xGB
Full (pure_bf16) 16 60GB 120GB 300GB 600GB 8xGB
Freeze/LoRA/GaLore/APOLLO/BAdam 16 16GB 32GB 64GB 160GB 2xGB
QLoRA 8 10GB 20GB 40GB 80GB xGB
QLoRA 4 6GB 12GB 24GB 48GB x/2GB
QLoRA 2 4GB 8GB 16GB 24GB x/4GB

本文档使用LoRA微调方法,机器使用腾讯云 V100 32G显存 试用7天 49元

注意剩余磁盘大小(100G以上),后面的下载模型都比较大,7b基座模型需要20G,32b基座模型需要50G

2. 安装

官网安装步骤 https://github.com/hiyouga/LLaMA-Factory/blob/main/README_zh.md#%E5%AE%89%E8%A3%85-llama-factory

python管理官网使用uv,这里我们使用miniconda或者腾讯云自带的miniforge3

1
2
3
4
5
6
git clone https://github.com/hiyouga/LLaMA-Factory.git
conda create -n llama_factory python=3.10
conda activate llama_factory
cd LLaMA-Factory
#安装LLaMA-Factory
pip install -e '.[torch,metrics]'

上述的安装命令完成了如下几件事

  1. 新建一个LLaMA-Factory 使用的python环境(可选)
  2. 安装LLaMA-Factory 所需要的第三方基础库(requirements.txt包含的库)
  3. 安装评估指标所需要的库,包含nltk, jieba, rouge-chinese
  4. 安装LLaMA-Factory本身,然后在系统中生成一个命令 llamafactory-cli(具体用法见下方教程)

查看显存使用情况

1
nvidia-smi

校验cuda安装情况

1
2
3
4
import torch
torch.cuda.current_device()
torch.cuda.get_device_name(0)
torch.__version__

校验llamafactory-cli安装情况、查看llamafactory-cli的命令参数

1
llamafactory-cli train -h

安装modelscope,用于国内下载模型

1
pip install modelscope

3. LoRa微调

3.1 使用webui进行微调

我个人是使用命令行进行微调的,这里我仅用来自动下载基座模型,页面微调部分仅供参考

3.1.1 运行webui

默认端口7860

1
2
3
4
5
6
#USE_MODELSCOPE_HUB=1表示使用modelscope下载模型(国内),也可以手动下载
USE_MODELSCOPE_HUB=1 llamafactory-cli webui
#后台运行
USE_MODELSCOPE_HUB=1 nohup llamafactory-cli webui > webui.log 2>&1 &
#CUDA_VISIBLE_DEVICES=0 USE_MODELSCOPE_HUB=1 llamafactory-cli webui
#CUDA_VISIBLE_DEVICES=0 GRADIO_SHARE=1 GRADIO_SERVER_PORT=7860 llamafactory-cli webui

3.1.2 下载模型

选择模型 –> chat –> 加载模型,注意检查点路径为空

在终端查看加载模型日志

模型文件地址 /root/.cache/modelscope/hub/

加载完成后就下载好了,可以在页面上发一个问题测试一下效果,然后点击卸载模型以释放显存,用于后面微调任务

3.1.3 数据集准备

数据集格式:https://github.com/hiyouga/LLaMA-Factory/blob/main/data/README_zh.md

实战示例可以在下文3.2 使用命令行进行微调查看

3.1.4 训练

webui上按需要配置参数,我是用命令行训练的,详细参数参考后文的命令行参数

训练成功后会在 ./saves 文件目录下生成适配器,页面上也会有日志和损失函数曲线

3.1.5 测试效果

可以点击评估chat两个Tab页来测试

注意使用chat时,需要先选择检查点路径(适配器),然后加载模型,测试完记得卸载模型

3.2 使用命令行进行微调

3.2.1 测试Demo

3.2.1.1 数据集

系统自带identity.json数据集(已默认在data/dataset_info.json 注册为identity)

1
2
sed -i 's/{{name}}/TiAI/g'  identity.json 
sed -i 's/{{author}}/TaiRong AI 团队/g' identity.json

提问:你是谁?

回答中包含 TiAI或者TaiRong AI 团队 表示微调成功了

小技巧:页面上选择莫个数据集后,可以点击预览,判断格式有没有问题。 正常预览则格式正确。

3.2.1.2 训练参数

qwen_lora_sft.yaml:

qwen_lora_sft.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
### model
model_name_or_path: /root/.cache/modelscope/hub/models/Qwen/Qwen2.5-7B-Instruct
trust_remote_code: true

### method
stage: sft
do_train: true
finetuning_type: lora
lora_rank: 8
lora_target: all

### dataset
dataset: identity
template: qwen
cutoff_len: 2048
max_samples: 10000
overwrite_cache: true
preprocessing_num_workers: 16
dataloader_num_workers: 4

### output
output_dir: ./saves/Qwen2.5-7B-Instruct/lora/train_2025-04-07-qwen-4
logging_steps: 10
save_steps: 500
plot_loss: true
overwrite_output_dir: true
save_only_model: false

### train
per_device_train_batch_size: 1
gradient_accumulation_steps: 8
learning_rate: 1.0e-4
num_train_epochs: 3.0
lr_scheduler_type: cosine
warmup_ratio: 0.1
bf16: true
ddp_timeout: 180000000
resume_from_checkpoint: null

### eval
# eval_dataset: alpaca_en_demo
# val_size: 0.1
# per_device_eval_batch_size: 1
# eval_strategy: steps
# eval_steps: 500
3.2.1.3 训练
1
llamafactory-cli train examples/train_lora/qwen_lora_sft.yaml
3.2.1.4 测试效果

1 使用webui查看微调效果:默认端口7860

1
2
3
4
5
CUDA_VISIBLE_DEVICES=0 llamafactory-cli webchat \
--model_name_or_path /root/.cache/modelscope/hub/models/Qwen/Qwen2.5-7B-Instruct \
--adapter_name_or_path ./saves/Qwen2.5-7B-Instruct/lora/train_2025-04-07-qwen-4 \
--template qwen \
--finetuning_type lora

2 使用命令行查看微调效果:

上述命令 webchat改成chat即可

3.2.2 实战Demo1: 微调 决策平台指标集xml生成任务

3.2.2.1 数据集

指标集 indicator_cus_set.json

1
2
3
4
{
"instruction": "在指标库增加指标,生成两个集合,第一个集合名为身份信息,指标为姓名,手机号,身份证,第二个集合指标为年龄,性别,分数,时间,根据指标名判断数据类型,根据上述条件生成xml文件",
"output": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><variable-library><category name=\"身份信息\" type=\"Custom\" clazz=\"identity_info\" id=\"unique_id_1\"><var name=\"name\" label=\"姓名\" type=\"String\" default-value=\"\" act=\"In\"/><var name=\"phone\" label=\"手机号\" type=\"String\" default-value=\"\" act=\"In\"/><var name=\"id_card\" label=\"身份证\" type=\"String\" default-value=\"\" act=\"In\"/></category><category name=\"其他信息\" type=\"Custom\" clazz=\"other_info\" id=\"unique_id_2\"><var name=\"age\" label=\"年龄\" type=\"Integer\" default-value=\"0\" act=\"In\"/><var name=\"gender\" label=\"性别\" type=\"String\" default-value=\"\" act=\"In\"/><var name=\"score\" label=\"分数\" type=\"Double\" default-value=\"0.0\" act=\"In\"/><var name=\"time\" label=\"时间\" type=\"Date\" default-value=\"\" act=\"In\"/></category></variable-library>"
},

修改data/dataset_info.json 注册数据集

1
2
3
4
5
6
7
"indicator_set": {
"file_name": "indicator_cus_set.json",
"columns": {
"prompt": "instruction",
"response": "output"
}
}
3.2.2.2 参数配置

qwen_lora_sft_dpxml.yaml :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
### model
model_name_or_path: /root/.cache/modelscope/hub/models/Qwen/Qwen2.5-7B-Instruct
trust_remote_code: true

### method
stage: sft
do_train: true
finetuning_type: lora
lora_rank: 8
lora_target: all

### dataset
dataset: indicator_set
template: qwen
cutoff_len: 2048
max_samples: 1000
overwrite_cache: true
preprocessing_num_workers: 16
dataloader_num_workers: 4

### output
output_dir: ./saves/Qwen2.5-7B-Instruct/lora/train_2025-04-07-qwen-5
logging_steps: 2
save_steps: 500
plot_loss: true
overwrite_output_dir: true
save_only_model: false

### train
per_device_train_batch_size: 4
gradient_accumulation_steps: 2
learning_rate: 5.0e-5
num_train_epochs: 3.0
lr_scheduler_type: cosine
warmup_ratio: 0.1
bf16: true
ddp_timeout: 180000000
resume_from_checkpoint: null

### eval
# eval_dataset: alpaca_en_demo
# val_size: 0.1
# per_device_eval_batch_size: 1
# eval_strategy: steps
# eval_steps: 500
3.2.2.3 训练
1
llamafactory-cli train examples/train_lora/qwen_lora_sft_dpxml.yaml 

训练日志:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
[INFO|trainer.py:2409] 2025-04-07 10:15:48,957 >> ***** Running training *****
[INFO|trainer.py:2410] 2025-04-07 10:15:48,957 >> Num examples = 147
[INFO|trainer.py:2411] 2025-04-07 10:15:48,957 >> Num Epochs = 3
[INFO|trainer.py:2412] 2025-04-07 10:15:48,957 >> Instantaneous batch size per device = 4
[INFO|trainer.py:2415] 2025-04-07 10:15:48,957 >> Total train batch size (w. parallel, distributed & accumulation) = 8
[INFO|trainer.py:2416] 2025-04-07 10:15:48,957 >> Gradient Accumulation steps = 2
[INFO|trainer.py:2417] 2025-04-07 10:15:48,957 >> Total optimization steps = 54
[INFO|trainer.py:2418] 2025-04-07 10:15:48,961 >> Number of trainable parameters = 20,185,088
{'loss': 1.1239, 'grad_norm': 0.5634056329727173, 'learning_rate': 1.6666666666666667e-05, 'epoch': 0.11}
{'loss': 1.2533, 'grad_norm': 0.8026983141899109, 'learning_rate': 3.3333333333333335e-05, 'epoch': 0.22}
{'loss': 0.9674, 'grad_norm': 0.46333494782447815, 'learning_rate': 5e-05, 'epoch': 0.32}
{'loss': 1.0919, 'grad_norm': 0.7045181393623352, 'learning_rate': 4.9786121534345265e-05, 'epoch': 0.43}
{'loss': 0.9633, 'grad_norm': 0.7544155716896057, 'learning_rate': 4.914814565722671e-05, 'epoch': 0.54}
{'loss': 1.0001, 'grad_norm': 0.6755673885345459, 'learning_rate': 4.8096988312782174e-05, 'epoch': 0.65}
{'loss': 0.8118, 'grad_norm': 0.5852521657943726, 'learning_rate': 4.665063509461097e-05, 'epoch': 0.76}
{'loss': 0.6543, 'grad_norm': 0.4262760281562805, 'learning_rate': 4.4833833507280884e-05, 'epoch': 0.86}
{'loss': 0.6299, 'grad_norm': 0.42453885078430176, 'learning_rate': 4.267766952966369e-05, 'epoch': 0.97}
{'loss': 0.6612, 'grad_norm': 0.6028416156768799, 'learning_rate': 4.021903572521802e-05, 'epoch': 1.05}
{'loss': 0.4792, 'grad_norm': 0.524094820022583, 'learning_rate': 3.7500000000000003e-05, 'epoch': 1.16}
{'loss': 0.5175, 'grad_norm': 0.6283194422721863, 'learning_rate': 3.456708580912725e-05, 'epoch': 1.27}
{'loss': 0.4073, 'grad_norm': 0.5512032508850098, 'learning_rate': 3.147047612756302e-05, 'epoch': 1.38}
{'loss': 0.38, 'grad_norm': 0.5038961172103882, 'learning_rate': 2.8263154805501297e-05, 'epoch': 1.49}
{'loss': 0.2868, 'grad_norm': 0.6777130365371704, 'learning_rate': 2.5e-05, 'epoch': 1.59}
{'loss': 0.3206, 'grad_norm': 0.6378408074378967, 'learning_rate': 2.173684519449872e-05, 'epoch': 1.7}
{'loss': 0.2742, 'grad_norm': 0.4203081429004669, 'learning_rate': 1.852952387243698e-05, 'epoch': 1.81}
{'loss': 0.294, 'grad_norm': 0.7391402721405029, 'learning_rate': 1.5432914190872757e-05, 'epoch': 1.92}
{'loss': 0.2507, 'grad_norm': 0.70897376537323, 'learning_rate': 1.2500000000000006e-05, 'epoch': 2.0}
{'loss': 0.1965, 'grad_norm': 0.2932491600513458, 'learning_rate': 9.780964274781984e-06, 'epoch': 2.11}
{'loss': 0.2315, 'grad_norm': 0.5419987440109253, 'learning_rate': 7.3223304703363135e-06, 'epoch': 2.22}
{'loss': 0.2513, 'grad_norm': 0.3444525897502899, 'learning_rate': 5.166166492719124e-06, 'epoch': 2.32}
{'loss': 0.2094, 'grad_norm': 0.3029688000679016, 'learning_rate': 3.3493649053890326e-06, 'epoch': 2.43}
{'loss': 0.2569, 'grad_norm': 0.36653071641921997, 'learning_rate': 1.9030116872178316e-06, 'epoch': 2.54}
{'loss': 0.2305, 'grad_norm': 0.32134708762168884, 'learning_rate': 8.51854342773295e-07, 'epoch': 2.65}
{'loss': 0.211, 'grad_norm': 0.32094964385032654, 'learning_rate': 2.1387846565474045e-07, 'epoch': 2.76}
{'loss': 0.226, 'grad_norm': 0.33298182487487793, 'learning_rate': 0.0, 'epoch': 2.86}

日志总结

Num examples = 147 总数据数量

Num Epochs = 3 训练轮次 num_train_epochs: 3.0

Instantaneous batch size per device = 4 每个设备每批次训练的的数据量(越高越吃显存,也越快)per_device_train_batch_size: 4

Gradient Accumulation steps = 2 梯度累计步数 gradient_accumulation_steps: 2

Total train batch size (w. parallel, distributed & accumulation) = 8 总的每批次训练数据量 [4 * 2 ]

Total optimization steps = 54 总训练步数 (147 / (4*2) ) * 3

可以看出学习率早期增大warmup_ratio: 0.1 后面逐步减少lr_scheduler_type: cosine

参数 output_dir: ./saves/Qwen2.5-7B-Instruct/lora/train_2025-04-07-qwen-5 目录下有训练后的适配器,训练日志文件和损失函数png

正常的损失函数png:逐步收敛

3.2.1.4 测试效果
1
2
3
4
5
6
7
8
9
10
11
12
#ui chat测试
CUDA_VISIBLE_DEVICES=0 llamafactory-cli webchat \
--model_name_or_path /root/.cache/modelscope/hub/models/Qwen/Qwen2.5-7B-Instruct \
--adapter_name_or_path ./saves/Qwen2.5-7B-Instruct/lora/train_2025-04-07-qwen-5 \
--template qwen \
--finetuning_type lora
#命令行chat测试
CUDA_VISIBLE_DEVICES=0 llamafactory-cli chat \
--model_name_or_path /root/.cache/modelscope/hub/models/Qwen/Qwen2.5-7B-Instruct \
--adapter_name_or_path ./saves/Qwen2.5-7B-Instruct/lora/train_2025-04-07-qwen-5 \
--template qwen \
--finetuning_type lora

我们使用命令行chat测试:正确输出了结果

3.2.1.5 出现的问题以及解决

1 损失函数图像混乱,没有稳步收敛

​ 可能原因:数据样本少

​ 解决方法:9.2.0 小数据集优化重复数据

​ 可能原因:数据样本少导致总的训练steps很少, 损失函数日志记录少

​ 解决方法:减少logging_steps:logging_steps: 2

3.3 API调用

3.3.1 openai规范

3.3.1.1 运行:

这里的API_PORT是7680(自定义),上述的webui的端口是7860

1
2
3
4
5
6
conda activate llama_factory
CUDA_VISIBLE_DEVICES=0 API_PORT=7680 llamafactory-cli api \
--model_name_or_path /root/.cache/modelscope/hub/models/Qwen/Qwen2.5-7B-Instruct \
--adapter_name_or_path /root/LLaMA-Factory/saves/Qwen2.5-7B-Instruct/lora/train_qwen_04_03_2 \
--template qwen \
--finetuning_type lora

model_name_or_path 基础模型绝对路径

adapter_name_or_path 微调后的适配器绝对路径

3.3.1.2 调用:

按照openai使用:

apikey: 0

Baseurl: http://{host}:{API_PORT}/v1

1
2
3
4
5
6
7
import os
from openai import OpenAI
port = 8000
client = OpenAI(
api_key="0",
base_url="http://localhost:{}/v1".format(os.environ.get("API_PORT", 8000)),
)

3.3.2 ollama

合并适配器和基础模型后导出,并转成ollama可以加载的文件

参考:https://zhuanlan.zhihu.com/p/695287607 文章中的13. 进阶-导出GGUF,部署Ollama

3.3.3 vllm

3.4 LoRA模型合并导出

如果想把训练的LoRA和原始的大模型进行融合,输出一个完整的模型文件的话,可以使用如下命令。合并后的模型可以自由地像使用原始的模型一样应用到其他下游环节,当然也可以递归地继续用于训练。

本脚本参数改编自 LLaMA-Factory/examples/merge_lora/llama3_lora_sft.yaml at main · hiyouga/LLaMA-Factory

1
2
3
4
5
6
7
8
9
CUDA_VISIBLE_DEVICES=0 llamafactory-cli export \
--model_name_or_path xxx \
--adapter_name_or_path ./saves/xxx \
--template xxxx \
--finetuning_type lora \
--export_dir output/xxx \
--export_size 2 \
--export_device cpu \
--export_legacy_format False

3.5 评测 benchmark

3.6 导出GGUF,部署Ollama

参考:https://zhuanlan.zhihu.com/p/695287607 文章中的13. 进阶-导出GGUF,部署Ollama

Ollama部署参考我之前的博客文章:

9. 参数和优化

9.1 常用重要参数

训练重要参数 没有列出的可以使用 llamafactory-cli train -h 查看

名称 描述 建议
model_name_or_path 模型名称或路径
stage 训练阶段,可选: rm(reward modeling), pt(pretrain), sft(Supervised Fine-Tuning), PPO, DPO, KTO, ORPO
do_train true用于训练, false用于评估
finetuning_type 微调方式。可选: freeze, lora, full
lora_target 采取LoRA方法的目标模块,默认值为 all
dataset 使用的数据集,使用”,”分隔多个数据集
template 数据集模板,请保证数据集模板与模型相对应。 基座模型和template对应查看https://github.com/hiyouga/LLaMA-Factory/blob/main/README_zh.md#%E6%A8%A1%E5%9E%8B
对于所有“基座”(Base)模型,template 参数可以是 default, alpaca, vicuna 等任意值。但“对话”(Instruct/Chat)模型请务必使用对应的模板
请务必在训练和推理时采用完全一致的模板
output_dir 输出路径
logging_steps 日志输出步数间隔
save_steps 模型断点保存间隔
overwrite_output_dir 是否允许覆盖输出目录
per_device_train_batch_size 每个设备上训练的批次大小 批次大小根据 GPU 内存设置,推荐值为 16 到 64。内存有限时可以结合梯度累积使用
gradient_accumulation_steps 梯度积累步数 (通过累积多个小批次的梯度来更新模型) 如果 GPU 内存有限,可以设置 2 到 8 的累积步数,模拟大批次训练
max_grad_norm 梯度裁剪阈值 默认1.0
learning_rate 学习率 建议初始学习率为 1e-5 到 5e-5
lr_scheduler_type 学习率曲线,可选 linear, cosine, polynomial, constant 等。
num_train_epochs 训练周期数 默认3.0 (表示训练的总轮数,通常是整个数据集被遍历的次数) 对于大部分微调任务,3 到 5 轮训练是一个合适的设置。如果数据集较大或训练时间受限,可以适当减少轮数。对于较小的数据集,可以增加轮数,以提高模型的收敛度
bf16 是否使用 bf16 格式
warmup_ratio 学习率预热比例(热身比例决定了学习率在训练开始时逐步增加的比例。热身阶段有助于在训练初期防止模型收敛过快) 一般推荐设置为 0.05 到 0.1,即总训练步数的 5% 到 10% 作为热身阶段
warmup_steps 学习率预热步数 一般不设置,设置warmup_ratio即可
push_to_hub 是否推送模型到 Huggingface
quantization_bit 用于量化模型的位数,降低内存占用 对于资源受限设备,推荐使用 4-bit 或 8-bit 量化来减少内存和加速推理
cutoff_len 指定每个输入序列的最大长度。超出此长度的输入将被截断 建议根据任务和数据集的特性选择合适的 cutoff_len。对于需要处理较长文本的任务(如问答系统),可以选择较大的序列长度。但需要注意,序列长度过长会增加训练时间和显存占用
deepspeed DeepSpeed 是用于加速和优化大规模分布式训练的库。通过该参数,你可以启用 DeepSpeed,并指定使用哪种优化模式(如 ZeRO) 如果在多 GPU 或分布式环境下运行,建议启用 DeepSpeed。ZeRO 优化可以显著减少显存占用,使得你能够在有限的硬件资源下运行更大规模的模型
infer_backend 启用推理所使用的引擎架构,默认使用huggingface架构,设置为vLLM则会使用vllm引擎架构 可根据需要选择

lora参数

参数名称 类型 介绍
additional_target[非必须] [str,] 除 LoRA 层之外设置为可训练并保存在最终检查点中的模块名称。使用逗号分隔多个模块。默认值为 None
lora_alpha[非必须] int LoRA 缩放系数。一般情况下为 lora_rank * 2, 默认值为 None
lora_dropout float LoRA 微调中的 dropout 率。默认值为 0
lora_rank int LoRA 微调的本征维数 rr 越大可训练的参数越多。默认值为 8
lora_target str 应用 LoRA 方法的模块名称。使用逗号分隔多个模块,使用 all 指定所有模块。默认值为 all
loraplus_lr_ratio[非必须] float LoRA+ 学习率比例(λ = ηB/ηA)。 ηA, ηB 分别是 adapter matrices A 与 B 的学习率。LoRA+ 的理想取值与所选择的模型和任务有关。默认值为 None
loraplus_lr_embedding[非必须] float LoRA+ 嵌入层的学习率, 默认值为 1e-6
use_rslora bool 是否使用秩稳定 LoRA(Rank-Stabilized LoRA),默认值为 False
use_dora bool 是否使用权重分解 LoRA(Weight-Decomposed LoRA),默认值为 False
pissa_init bool 是否初始化 PiSSA 适配器,默认值为 False
pissa_iter int PiSSA 中 FSVD 执行的迭代步数。使用 -1 将其禁用,默认值为 16
pissa_convert bool 是否将 PiSSA 适配器转换为正常的 LoRA 适配器,默认值为 False
create_new_adapter bool 是否创建一个具有随机初始化权重的新适配器,默认值为 False

9.2 理解和优化

优化经验:https://lightning.ai/pages/community/lora-insights/

9.2.0 小数据集优化

参数 推荐值/策略 说明
学习率 1e-55e-5 小数据集需要更小的学习率,避免破坏预训练模型的已有知识。
Batch Size 4-8 小批量训练减少显存占用,同时增加梯度更新频率。
Epochs 10-30 小数据可能需更多轮次学习,但需配合早停(Early Stopping)。
Dropout 0.3-0.5 提高 Dropout 比例,增强模型正则化能力。
Weight Decay 0.01-0.1 加大权重衰减限制参数规模,防止过拟合。
LoRA Rank 8-16 降低 LoRA 的秩(Rank),减少可训练参数。
LoRA Alpha 2×Rank(如 Rank=8 → Alpha=16) 平衡 LoRA 适配器的更新强度。
Max Length 与数据分布匹配(如 512 避免过长截断导致信息丢失,同时减少计算开销。

(1) 防止过拟合

  • 数据增强
    对小样本进行同义词替换、回译(Back Translation)、句子重组等,扩充数据多样性。
  • 早停(Early Stopping)
    监控验证集损失(eval_loss),当连续 3-5 轮无改善时终止训练。
  • 冻结部分参数
    冻结预训练模型的大部分层,仅微调顶层或特定模块(如分类头)。
  • 交叉验证
    使用 K-Fold 交叉验证(如 5-Fold),最大化利用有限数据。

(2) 提升训练效率

  • 混合精度训练
    开启 fp16bf16 模式加速训练,节省显存。
  • 梯度累积(Gradient Accumulation)
    若 Batch Size 较小,设置梯度累积步数(如 4)模拟大批量训练。
  • 小量多次实验
    快速尝试不同超参组合(如学习率、LoRA Rank),观察验证集效果。

(3) 适配小数据的训练技巧

  • 重复数据
    适当重复数据(如复制 2-3 次),但需谨慎避免过拟合。
  • 动态掩码(Dynamic Masking)
    若任务支持,在输入序列中随机掩码部分 Token,增强鲁棒性。
  • 小模型优先
    若数据量极小(如 <1000 条),优先选择较小的基座模型(如 LLaMA-7B 而非 13B)

9.2.1 学习率 learning_rate

9.2.1.1 定义

定义:学习率(通常用符号 α 或 lr 表示)控制模型在训练过程中根据梯度更新参数的幅度。

公式表示(梯度下降法):

$$ θ_{t+1}=θ_{t}−α⋅∇J(θ_t) $$

其中:

  • $θ$:模型参数
  • $∇J(θ)$:损失函数对参数的梯度 可简单理解为损失函数 J 在 θ 处 的导数
  • $α$:学习率 可简单理解步长

公式目的:找到损失函数的最小值

太大:参数更新步长过大,可能跳过最优解,导致损失值震荡甚至发散。

太小:收敛速度缓慢,容易陷入局部极小值,训练时间显著增加。

所以需要动态调整学习率

找山谷最低点
想象你蒙眼下山,学习率是每一步的步长:

  • 步长太大 → 可能在山谷两侧反复横跳,无法到底部。
  • 步长太小 → 需要极多步才能到达,甚至卡在半坡。
9.2.1.1 优化

固定初始学习率

1
learning_rate: 5e-5  # 固定值

学习率预热 Learning Rate Warmup

训练初期逐步增大学习率,避免初始梯度不稳定。

1
warmup_ratio: 0.1  # 前10%的训练步数用于预热

学习率衰减(Learning Rate Decay

  • 常见方法:

    衰减类型 公式 特点
    线性衰减 αt=α0⋅(1−t/T) 简单但可能衰减过快
    余弦退火(Cosine) αt=α0⋅1+cos⁡(πt/T)2 平滑收敛,适合微调
    指数衰减 αt=α0⋅γt 需手动设置衰减率 γγ
  • 示例配置(余弦退火):

    1
    lr_scheduler_type="cosine",  # 余弦退火

自适应学习率优化器

  • 特点:优化器根据梯度自动调整参数的学习率。

  • 常用优化器:

    优化器 公式特点
    Adam/AdamW 为每个参数维护独立的学习率,结合动量(一阶矩)和梯度平方(二阶矩)的指数衰减平均。
    Adagrad 对频繁更新的参数降低学习率,适合稀疏数据。
    RMSprop 基于梯度平方的滑动平均调整学习率,缓解 Adagrad 的激进衰减。
  • 注意:即使使用自适应优化器,初始学习率仍需合理设置(例如 Adam 的典型初始值在 1e-41e-5)。

  • 示例配置:llamafactory默认adamw_torch

1
--optim adamw_torch

初始学习率的选择

  • 经验法则
    • 小数据集/微调任务:1e-55e-5
    • 预训练或大数据集:1e-43e-4
    • 图像任务:通常比 NLP 任务大 1-2 个数量级(如 3e-4
  • 学习率范围测试(LR Range Test)
    在训练初期(如 1 个 epoch)内,从极小值(如 1e-7)到较大值(如 1e-2)线性增加学习率,观察损失变化。

理想区域:选择损失下降最快且稳定的区间

监控训练过程

  • 观察损失曲线
    • 损失持续下降 → 学习率合适。
    • 损失剧烈震荡 → 学习率可能过大。
    • 损失下降缓慢 → 学习率可能过小。
  • 验证集指标:若验证集损失在多个 epoch 内不改善,可能需要降低学习率或早停。

动态调整策略

  • 手动调整:根据验证集表现逐步降低学习率(如每次减半)。

  • 自动调整

    • ReduceLROnPlateau:当验证损失停滞时自动降低学习率。

      1
      2
      3
      lr_scheduler_type="reduce_on_plateau",  # 需框架支持
      patience=3, # 等待 3 次评估无改善后降低 lr
      factor=0.5, # 学习率乘以 0.5

对于小数据集微调(如 LLaMA Factory 场景),建议从较低学习率开始,配合余弦退火和早停策略,确保模型稳定收敛

9.2.2 gradient_accumulation_steps

梯度累计步数

目的:降低GPU显存占用

原理:当执行多次迭代之后,一旦累积梯度达到目标“虚拟”批量大小,才会更新权重。而不是每次迭代都更新权重

Gradient accumulation is a way to virtually increase the batch size during training, which is very useful when the available GPU memory is insufficient to accommodate the desired batch size. In gradient accumulation, gradients are computed for smaller batches and accumulated (usually summed or averaged) over multiple iterations instead of updating the model weights after every batch. Once the accumulated gradients reach the target “virtual” batch size, the model weights are updated with the accumulated gradients

9.2.3 lora_rank和lora_alpha

本征秩lora_rank

lora_rank越高,训练的参数约多,表达力越强,但是会过拟合。

A higher “r” means more expressive power but can lead to overfitting, while a lower “r” can reduce overfitting at the expense of expressiveness.

经验 :lora_alpha一般设置为lora_rank的两倍。不断提高lora_rank和lora_alpha测试最好的效果(损失函数最接近于0)