1. 从“炼丹”到“精调”:为什么参数是微调的命门?
如果你刚接触大模型微调,可能会觉得这玩意儿跟“炼丹”似的——把数据扔进去,调几个看不懂的参数,然后就开始祈祷模型别“炸炉”。我刚开始用LoRA、QLoRA这些轻量化工具时,也是这种感觉。看着LLaMA Factory或者Hugging Face Transformers里那一长串参数,什么learning_rate、per_device_train_batch_size、lora_alpha,头都大了。调高了怕过拟合,调低了怕学不动,整个过程充满了玄学。
但干了几个项目后,我意识到,这些参数根本不是玄学,而是精确的“控制面板”。大模型的微调,尤其是轻量化微调,本质上是在一个极其庞大且脆弱的参数空间里进行“微创手术”。我们手里的这些训练参数,就是手术刀、显微镜和麻醉剂的剂量。参数调得好,模型能精准学会新知识,保持原有能力;调得不好,轻则“手术失败”(模型学不到东西),重则“病人瘫痪”(模型原有能力崩溃,俗称“灾难性遗忘”)。
所以,这篇指南的目的,就是把这套“控制面板”上的每一个旋钮、每一个刻度,给你讲明白、讲透彻。我们不谈空洞的理论,就结合LoRA/QLoRA在LLaMA Factory这类工具中的实战,告诉你每个参数是什么、为什么这么设、以及我踩过哪些坑。让你从“凭感觉调参”进化到“心中有数地调参”。
2. 训练参数全景图:核心模块拆解与关联
在深入每个参数之前,我们得先有一张地图。大模型训练的参数虽然多,但可以归纳为几个核心模块,它们彼此关联,共同决定了训练的走向。我们可以将其分为四大配置块:
- 模型与数据配置块:决定了“用什么模型”和“学什么数据”。这是训练的基础。
- 优化器与学习率配置块:决定了“如何学习”。这是训练动力系统的核心,直接关系到模型能否收敛、收敛得快慢好坏。
- LoRA/QLoRA专用配置块:轻量化微调特有的“手术刀”参数,决定了在模型的哪个部位、以多大的强度进行修改。
- 训练循环与硬件配置块:决定了“训练的执行过程”,如何适配你的算力资源,以及训练何时停止。
它们之间的关系,我画了一个简单的思维导图来帮助理解(注意,这不是mermaid图表,而是文字描述的结构):
- 训练目标:由
模型配置和数据配置共同定义。 - 实现路径:
优化器与学习率配置提供了学习和更新的策略。 - 修改范围:
LoRA/QLoRA配置严格限定了策略施加的范围,确保轻量化。 - 执行环境:
训练循环与硬件配置将上述所有计划在具体的计算资源上按步骤执行。
接下来,我们就钻进每一个模块,把参数掰开揉碎了讲。
2.1 模型与数据配置:地基不打牢,房子肯定倒
这一部分的参数看似简单,但往往是新手第一个跟头的地方。
model_name_or_path(模型名称或路径)这是起点。可以是Hugging Face上的模型ID(如meta-llama/Llama-2-7b-hf),也可以是本地保存的模型目录路径。
注意:确保你拥有该模型的使用权限(例如Llama系列需要申请),并且本地路径下的模型文件是完整的(包括
config.json,pytorch_model.bin等)。
dataset_name_or_path(数据集名称或路径)同样,可以是HF数据集名或本地路径。这里的关键是数据格式。LLaMA Factory等工具通常要求数据是json或jsonl格式,并且包含特定的字段,如instruction(指令)、input(输入)、output(输出)。
- 我踩过的坑:曾经直接把爬取的对话文本存成
.txt就往里喂,结果训练脚本报错找不到字段。后来统一预处理成标准的jsonl格式,每个样本一个对象,清晰又规范。 - 数据质量:参数再好,垃圾数据进去也只能训练出垃圾模型。务必进行清洗(去重、去无效字符)、格式化,甚至必要的数据增强。
template(提示词模板)这是连接数据和模型的关键一环。模型并不是直接理解你的instruction和output,而是需要将它们按照模型预训练时的格式组织起来。例如,ChatML格式、Alpaca格式等。
- 为什么重要?如果模板用错,相当于你跟一个只会说英语的人用中文语法说英语单词,他根本无法理解。这会导致模型无法有效学习指令遵循能力。
- 实操:在LLaMA Factory中,通常选择与基础模型匹配的模板。例如,微调Llama2,就选择
llama2模板;微调Qwen,就选择qwen模板。不要自己胡乱发明。
cutoff_len(截断长度) &padding(填充策略)cutoff_len决定了模型一次性能看多长的文本。受限于显存和模型最大位置编码,必须将过长的样本截断。
- 如何设置:通常设置为模型支持的最大长度(如Llama2是4096)。但为了节省显存,也可以设小一点(如1024或512),前提是你的数据样本不太长。
- **padding
策略**:通常选择right(右侧填充)。因为大多数注意力机制在计算时会忽略填充位置,右侧填充对结果影响较小。batch_size`大于1时,必须填充到同一长度才能组成一个批次。
2.2 优化器与学习率:训练引擎的油门与变速箱
这是参数调优最核心、最微妙的部分。你可以把优化器想象成汽车的引擎类型(如AdamW),学习率及其调度就是控制这个引擎的油门和变速箱。
optim(优化器)主流选择是adamw_torch或adamw_8bit(如果你用了bitsandbytes库进行8位优化)。AdamW是Adam的改进版,加入了权重衰减(Weight Decay),能更好地防止过拟合。
- 选型理由:
AdamW自适应调整每个参数的学习率,训练初期收敛快,对于大模型这种参数海量的场景非常友好。几乎可以无脑选它。
learning_rate(学习率)这是最重要的超参数之一。它决定了参数每次更新的步长。
- 太大:步子迈大了容易“扯着蛋”,损失函数剧烈震荡甚至发散,无法收敛。
- 太小:步子太小,训练慢如蜗牛,还可能陷入局部最优解出不来。
- 经验范围:对于全参数微调,学习率通常在
1e-5到5e-5之间。对于LoRA/QLoRA微调,因为只更新少量参数,我们需要更大的学习率来驱动这些适配器快速学习,常用范围在1e-4到5e-4之间。我个人的常用起点是2e-4。 - 一个生动的类比:想象你在一个布满丘陵(损失函数曲面)的地图上找最低点(最优点)。学习率就是你的步长。全参数微调像是你要移动整个巨大的沙盘(所有参数),步子不敢太大,否则沙盘就散了。LoRA微调则像是你只在沙盘的几个关键点插上小旗子(适配器参数),只移动这些小旗子,所以可以迈开步子快速调整它们的位置。
lr_scheduler_type(学习率调度器类型)让学习率随着训练过程动态变化,这就是变速箱。
constant:恒定的学习率。简单粗暴,但后期可能因步长不变而无法精细收敛。linear:线性衰减。从设定的learning_rate线性衰减到0。这是最常用、最稳妥的选择。训练初期大步探索,后期小步精修。cosine:余弦衰减。学习率变化曲线像余弦函数的一半,平滑地下降。通常比linear效果稍好,更平滑。cosine_with_restarts:带重启的余弦衰减。在余弦下降的过程中,周期性地将学习率重置回初始值,有助于跳出局部最优。适用于训练周期(num_epochs)较长的场景。- 我的选择:对于大多数下游任务微调,
linear或cosine足矣。我默认用linear,因为它可预测且稳定。
warmup_ratio/warmup_steps(预热比例/步数)训练开始时,模型参数是随机的,直接上大的学习率可能导致不稳定。预热就是在训练初期,让学习率从0线性增长到设定的初始值。
- 作用:让优化器“热热身”,稳定初期训练。
- 设置:通常设为总训练步数的
0.1(10%)。例如总步数1000步,则预热100步。也可以直接设置warmup_steps=100。
weight_decay(权重衰减)一种正则化技术,通过对大的参数值施加惩罚,防止模型过拟合。可以理解为在损失函数里加了一项“参数不要太大”的约束。
- 典型值:
0.01或0.1。对于微调,尤其是数据量不大时,可以设置一个较小的值(如0.01)来抑制过拟合。 - 注意:有时我们会对模型的不同部分设置不同的
weight_decay,例如对LoRA参数不衰减或衰减更少,但对基础模型参数衰减更多。这需要在更底层的代码中配置,LLaMA Factory的高级配置可能提供选项。
2.3 LoRA/QLoRA专用配置:精准的微创手术刀
这是轻量化微调的精华所在。理解了它们,你就掌握了如何用最小的代价撬动大模型。
lora_rank(LoRA秩,又称r)这是LoRA最核心的参数。它决定了适配器(Adapter)矩阵的大小。原始参数矩阵W的更新量 ΔW 被分解为两个小矩阵的乘积:B * A,其中B的形状是[d_model, r],A的形状是[r, d_model]。这里的r就是lora_rank。
- 物理意义:
r可以理解为“内在秩”或“表达能力维度”。r越大,适配器可学习的模式越复杂,能力越强,但参数量也越多(参数量≈ 2 * d_model * r)。 - 如何设置:这是一个典型的权衡。常用值在
4, 8, 16, 32, 64之间。r=4或8:参数量极少(可能只占原模型0.1%),适合简单任务或极度追求轻量化。但表达能力有限。r=16或32:甜点区间。对于大多数指令微调、对话微调任务,r=16是一个非常好的起点,在效果和效率间取得了平衡。我80%的任务都用r=16。r=64或更高:用于更复杂的任务(如代码生成、复杂推理),但需要警惕过拟合。
- 一个实验结论:论文和实践都表明,在参数量相同的情况下,增加
r比增加lora_alpha对性能的提升更明显。所以优先调整r。
lora_alpha(LoRA缩放系数,又称α)在得到低秩更新 ΔW = B*A 后,我们并不直接用它替换原权重,而是用一个缩放系数来控制更新量:W_new = W + (alpha / r) * ΔW。
- 作用:控制LoRA适配器对原始模型的“影响强度”。
alpha越大,适配器带来的改变就越大。 - 与
r的关系:注意公式中是(alpha / r)。这意味着,alpha和r需要协同调整。通常我们固定alpha为一个值(如16, 32, 64),然后通过调整r来改变实际缩放比。 - 经验法则:一种常见的设置是让
alpha是r的两倍,即alpha = 2 * r。例如r=16, alpha=32。这通常能提供一个不错的初始强度。你可以将其视为一个超参数进行微调,但优先级低于r和learning_rate。
lora_dropout(LoRA丢弃率)在LoRA适配器的训练过程中,随机丢弃(置零)一部分神经元,是一种防止过拟合的正则化手段。
- 设置:范围在
0到0.5之间。对于数据量较大的任务,可以设为0或0.1。对于数据量小、容易过拟合的任务,可以尝试0.2或0.3。 - 我的习惯:除非过拟合迹象非常明显,否则我通常设为
0.1或直接0。因为LoRA参数量本身已经很少,过拟合风险相对全参数微调要低。
lora_target_modules(LoRA目标模块)指定将LoRA适配器添加到原始模型的哪些线性层(Linear Layers)。这是决定微调效果的关键之一。
- 常见选项:
q_proj,k_proj,v_proj,o_proj(注意力机制的查询、键、值、输出投影层),gate_proj,up_proj,down_proj(MLP层的前向、向上、向下投影层)。 - 如何选择:
- 默认/全量:
[“q_proj”, “v_proj”]或[“q_proj”, “k_proj”, “v_proj”, “o_proj”]。这是最常用的配置,修改注意力机制,让模型学会“关注”数据中重要的部分。 - 仅注意力层:
[“q_proj”, “v_proj”]。论文指出只加在query和value投影层,就能取得大部分效果,且参数量更少。这是我个人最推荐和常用的配置。 - 包含MLP层:如果任务涉及很强的知识记忆或模式转换(如翻译、风格转换),可以加上
gate_proj,up_proj,down_proj。但这会显著增加参数量。 all-linear:一些框架(如PEFT库)支持这个选项,会自动找到所有线性层添加LoRA。这是最激进的方式,参数量最大,效果可能最好但也最容易过拟合,通常不推荐。
- 默认/全量:
- 建议:从
[“q_proj”, “v_proj”]开始。如果效果不佳,再考虑加入k_proj,o_proj或MLP层。
quantization_bit(量化位数) - QLoRA专属这是QLoRA(量化LoRA)的灵魂。它决定了将基础模型的权重以多少位精度加载到显存中。
4:4位量化。显存占用最小,但可能会有一定的精度损失。对于7B模型,配合r=16的LoRA,甚至可以在12GB显存的消费级显卡上运行。8:8位量化。显存占用比4位多,但精度损失更小,更稳定。- 选择建议:如果你的显存非常紧张(例如只有一张12GB的RTX 3080),果断选择
4-bit。如果显存相对充裕(如24GB),可以选择8-bit以获得更稳定的训练。我自己的经验是,对于指令微调任务,4-bitQLoRA的效果已经非常接近8-bit,性价比极高。
2.4 训练循环与硬件配置:让计划在现实中跑起来
这部分参数将你的训练计划映射到具体的硬件资源和时间线上。
per_device_train_batch_size(单设备训练批次大小)一次前向传播和反向传播中,每个GPU(设备)处理的样本数量。
- 黄金法则:在不超出显存的前提下,尽可能设大。更大的
batch_size通常意味着梯度估计更稳定,训练更平滑,也可能更快收敛。 - 如何确定:这是一个试出来的值。从1开始,逐步增加(2, 4, 8…),直到程序抛出
CUDA out of memory错误。然后回退一步,就是你的安全值。QLoRA的引入可以让你使用比全参数微调大得多的batch_size。
gradient_accumulation_steps(梯度累积步数)当你的GPU无法容纳理想的batch_size时,这个参数就是救星。它让你在逻辑上模拟一个更大的批次。
- 原理:假设你设
per_device_train_batch_size=2,gradient_accumulation_steps=4。那么程序会:- 用2个样本计算一次梯度(但不更新参数)。
- 重复4次(累计8个样本的梯度)。
- 将这4次累积的梯度求平均,然后用这个平均梯度更新一次参数。
- 效果:这相当于你用了
2 * 4 = 8的逻辑批次大小进行了一次参数更新,但显存占用只相当于batch_size=2的时候。 - 设置:
effective_batch_size = per_device_train_batch_size * gradient_accumulation_steps * num_gpus。你需要根据任务和数据集大小,确定一个合适的effective_batch_size(例如32, 64, 128),然后根据你的显存情况,反推出gradient_accumulation_steps。
num_epochs(训练轮数)整个数据集被完整遍历多少次。
- 设置依据:取决于数据集大小和任务复杂度。数据量小(几千条)、任务简单,3-5个epoch可能就够了。数据量大、任务复杂,可能需要10个甚至更多epoch。
- 关键:一定要配合验证集和早停(Early Stopping)来使用!不要盲目设一个很大的epoch数然后干等。模型通常在中间某个epoch达到最佳,之后在训练集上损失继续下降,但在验证集上开始上升(过拟合)。
eval_strategy&eval_steps(评估策略与步数)eval_strategy可以是“steps”(按步数评估)或“epoch”(按轮次评估)。eval_steps是当策略为“steps”时,每多少步评估一次。
- 建议:对于长时间训练,设为
eval_strategy=“steps”和eval_steps=100或200,可以更频繁地监控模型在验证集上的表现,及时发现问题或触发早停。
save_strategy&save_steps(保存策略与步数)同上,控制模型检查点的保存频率。
- 建议:可以设置得比评估频率低一些,比如
save_strategy=“steps”和save_steps=500。避免保存太多检查点占用磁盘空间。务必开启load_best_model_at_end=True,让训练结束后自动加载验证集上性能最好的那个检查点。
fp16/bf16(混合精度训练)大幅减少显存占用、加快训练速度的利器。
fp16:半精度浮点数(16位)。大多数NVIDIA GPU(Volta架构及以后)都支持。bf16:脑浮点数(16位)。动态范围比fp16大,更不容易出现数值下溢(梯度变成0)的问题,训练更稳定。但需要Ampere架构及以后的GPU(如A100, RTX 30系列)支持。- 选择:如果你的硬件支持
bf16,优先使用它,稳定性更好。否则就用fp16。在QLoRA中,基础模型已经是4/8位整数量化,这里的fp16/bf16主要影响LoRA适配器参数和优化器状态的精度。
3. 参数组合实战:手把手调出一个配方
了解了每个参数后,我们来看如何将它们组合起来,针对不同的场景给出“配方”。请注意,这些配方是起点,需要根据你的实际任务和数据进行调整。
3.1 场景一:消费级显卡(如RTX 3090 24GB)上的指令微调
- 目标:让一个7B模型(如Llama-2-7b)学会遵循你的指令格式。
- 数据:几千到几万条高质量的指令-输出对。
- 硬件限制:单卡24GB显存。
参数配置思路与详解:
- 采用QLoRA (4-bit):这是关键,它让我们能在24GB上轻松运行7B模型。设置
quantization_bit=4。 - LoRA配置:这是微调能力的核心。选择中等表达能力的秩,
lora_rank=16。缩放系数采用经典比例,lora_alpha=32。目标模块聚焦于注意力机制最有效的部分,lora_target_modules=[“q_proj”, “v_proj”]。数据量不大,加一点正则化,lora_dropout=0.1。 - 优化器与学习率:因为是轻量化微调,学习率可以大一些。从
learning_rate=2e-4开始。优化器用adamw_8bit(配合QLoRA)。采用线性衰减lr_scheduler_type=“linear”,让学习率平稳下降。预热10%的训练步数,warmup_ratio=0.1。加一点权重衰减防止小数据集过拟合,weight_decay=0.01。 - 批次与累积:先试探单卡能承受的最大
batch_size。对于7B+QLoRA,per_device_train_batch_size可能可以达到8甚至16。假设我们设为8。我们希望有效批次大小在32左右,那么gradient_accumulation_steps = 32 / 8 = 4。 - 训练轮次与监控:数据量中等,设
num_epochs=5。每100步评估一次验证集,eval_strategy=“steps”,eval_steps=100。每500步保存一个检查点,save_strategy=“steps”,save_steps=500,并开启load_best_model_at_end=True。 - 精度:3090支持
bf16,优先使用,bf16=True。
最终配置示例(以LLaMA Factory的配置格式为例):
# 模型与数据 model_name_or_path=“meta-llama/Llama-2-7b-hf” dataset_name_or_path=“./my_instruction_data” template=“llama2” # LoRA配置 lora_rank=16 lora_alpha=32 lora_dropout=0.1 lora_target_modules=“[“q_proj”, “v_proj”]” quantization_bit=4 # 优化器 learning_rate=2e-4 optim=“adamw_8bit” lr_scheduler_type=“linear” warmup_ratio=0.1 weight_decay=0.01 # 训练循环 per_device_train_batch_size=8 gradient_accumulation_steps=4 num_epochs=5 eval_strategy=“steps” eval_steps=100 save_strategy=“steps” save_steps=500 load_best_model_at_end=True # 硬件 bf16=True3.2 场景二:多轮对话微调与过拟合应对
- 目标:微调一个模型,使其能进行符合特定风格(如客服、角色扮演)的多轮对话。
- 挑战:对话数据构造复杂,且数据量可能相对较少,容易过拟合。
参数调整策略:
- 强化正则化:
- 降低
lora_rank:从16降到8甚至4,减少可学习参数,降低模型复杂度。 - 提高
lora_dropout:从0.1提高到0.2或0.3,在训练时随机丢弃更多适配器神经元。 - 提高
weight_decay:从0.01提高到0.1,更严格地惩罚大参数值。
- 降低
- 更保守的学习率:使用稍小的学习率,例如
learning_rate=1e-4,让学习过程更平滑。 - 数据格式与模板:这一点至关重要。多轮对话数据需要被格式化成模型能理解的序列。通常使用类似
[INST] 第一轮用户话 [/INST] 第一轮助理回复 </s> [INST] 第二轮用户话 [/INST] 第二轮助理回复 </s>的格式。确保你的template和数据处理脚本正确拼接了多轮历史。 - 早停(Early Stopping):严格监控验证集损失。当验证集损失连续多个评估点不再下降(甚至上升)时,果断停止训练。在LLaMA Factory中,可以通过
metric_for_best_model=“eval_loss”和greater_is_better=False来实现,并设置early_stopping_patience=3(如果连续3次评估验证损失没有改善,则停止)。 - 减少训练轮次:将
num_epochs设小,比如3,依靠早停来防止过拟合。
3.3 场景三:代码生成任务微调
- 目标:让模型具备更好的代码生成或代码补全能力。
- 特点:任务对逻辑和格式要求严格,数据通常是代码片段或代码-注释对。
参数调整策略:
- 增大模型容量:代码任务通常需要更强的表达能力。可以考虑使用更大的
lora_rank,例如32或64。同时,可以将lora_target_modules扩展到包含MLP层(gate_proj,up_proj,down_proj),因为代码理解和生成可能涉及更复杂的特征变换。 - 学习率策略:可以考虑使用
cosine_with_restarts调度器,周期性的学习率重启可能有助于模型跳出在复杂代码语法模式中陷入的局部最优。 - 更长的上下文:代码文件可能很长。确保你的
cutoff_len设置得足够大(如2048或4096),同时要注意这会显著增加显存消耗,可能需要减小per_device_train_batch_size。 - 数据清洗:代码数据的质量极其重要。需要仔细处理缩进、换行符、特殊字符,并确保代码片段是语法正确的(可以通过简单的语法检查器过滤)。
4. 训练监控与诊断:看懂训练日志里的“心电图”
参数设好了,训练跑起来了,但工作还没完。你必须学会看训练日志,就像医生看心电图一样,从中诊断模型的“健康状况”。
关键观察指标:
训练损失(
train_loss):- 正常情况:随着训练步数增加,平滑地、持续地下降。
- 异常情况:
- 剧烈震荡:学习率可能太高了。尝试将
learning_rate降低为原来的1/2或1/5。 - 下降非常缓慢:学习率可能太低了,或者模型容量(
lora_rank)不足。尝试增大学习率或lora_rank。 - 后期不降反升:典型的过拟合迹象。需要加强正则化(增大
weight_decay,lora_dropout),或使用早停。
- 剧烈震荡:学习率可能太高了。尝试将
验证损失(
eval_loss):- 这是判断过拟合的黄金指标。
- 理想情况:随着训练进行,验证损失先下降,后趋于平稳或缓慢上升。
- 一旦发现验证损失开始连续上升,而训练损失还在下降,说明模型已经开始“死记硬背”训练数据,失去了泛化能力。此时应该停止训练,并加载验证损失最低的那个检查点。
学习率曲线:如果使用了
linear或cosine衰减,确保你看到的学习率值是在按预期下降的。这可以验证你的调度器设置是否正确。GPU显存使用情况:使用
nvidia-smi或训练框架自带的监控工具查看。确保没有发生OOM(内存溢出)。如果接近上限,可以尝试减小per_device_train_batch_size或cutoff_len,或者增加gradient_accumulation_steps。
一个典型的健康训练过程描述:前warmup_steps步,学习率从0线性上升到初始值,训练损失快速下降。预热结束后,学习率开始线性衰减,训练损失继续平稳下降,验证损失同步下降。在训练中后期,训练损失缓慢逼近0,验证损失达到一个最低点后开始有轻微抬头的趋势。此时早停触发,训练结束,保存最佳模型。
5. 常见问题排查:当训练出问题时
即使参数设得再小心,训练过程也可能出岔子。这里分享几个我亲身踩过的坑和解决办法。
问题1:训练损失为NaN或无限大(NaN/Inf loss)
- 现象:训练日志里突然出现
loss = nan或一个巨大的数字。 - 可能原因及解决:
- 学习率爆炸:最常见原因。立即大幅降低学习率(例如降到
1e-5)。同时检查是否使用了梯度裁剪(gradient_clipping),可以设置max_grad_norm=1.0来限制梯度大小,防止爆炸。 - 数据包含异常值:检查数据集中是否有非文本的乱码、空样本或极端长的样本。进行数据清洗。
- 混合精度训练不稳定:如果使用
fp16,尝试切换到bf16(如果硬件支持),或者暂时关闭混合精度训练(fp16=False)进行调试。
- 学习率爆炸:最常见原因。立即大幅降低学习率(例如降到
问题2:模型根本不学习(Loss几乎不变)
- 现象:训练了好几个epoch,损失值居高不下,几乎是一条水平线。
- 可能原因及解决:
- 学习率太低:尝试将学习率提高一个数量级(例如从
1e-5调到1e-4)。 - LoRA适配器未正确加载或应用:检查日志,确认LoRA参数确实被标记为“可训练”(trainable)。在LLaMA Factory中,确保
--use_lora参数已开启。可以打印模型参数,查看带lora前缀的参数量是否非零。 - 数据或模板错误:这是隐形杀手。模型接收到的输入可能完全是乱的。打印出几个训练样本,看看经过模板格式化后的输入文本到底是什么样子。确保指令、输出被正确拼接。
- 权重冻结错误:如果你手动冻结了基础模型参数,确保没有不小心把LoRA层也冻结了。
- 学习率太低:尝试将学习率提高一个数量级(例如从
问题3:训练速度异常缓慢
- 现象:每一步(step)耗时远超预期。
- 可能原因及解决:
gradient_accumulation_steps设置过大:虽然它节省显存,但会增加每一步的实际计算时间。在显存允许的情况下,尽量增大per_device_train_batch_size,减小gradient_accumulation_steps。- 数据加载瓶颈:数据集太大或存储在慢速磁盘上。使用数据流式加载或更快的存储。检查CPU使用率是否过高。
- 验证评估过于频繁:如果
eval_steps设得太小(如10),训练会频繁中断进行评估。可以适当增大eval_steps。
问题4:微调后模型“胡言乱语”或失去基础能力
- 现象:模型能回答你的指令,但语言混乱、事实错误,或者忘记了原有的通用知识。
- 可能原因及解决:
- 学习率过高或训练轮次太多:导致“灾难性遗忘”。基础模型的原始权重被剧烈的更新破坏了。降低学习率,减少训练轮次,并使用早停。
- LoRA的
alpha过大:lora_alpha相对于r过大,导致适配器更新过强。尝试减小alpha(例如保持alpha = r)。 - 数据质量差或噪声大:低质量数据会教坏模型。严格清洗数据。
调参是一个需要耐心和实验的过程。没有一套放之四海而皆准的“完美参数”。最好的方法就是:从一个可靠的基线配置开始(如本文提供的配方),根据训练日志反映出的“症状”,像医生一样有针对性地调整一两个最相关的参数,然后观察变化。做好实验记录,每次只改变一个变量,你就能逐渐积累起对自己任务和数据集的调参直觉。记住,我们的目标不是调出最漂亮的损失曲线,而是得到一个在实际应用中表现 robust 的模型。