Lora微调关键指标和实战
一、标准 LLM 指令微调(SFT 场景)
例如:
- 问答
- 对话
- 文本改写
- 总结
- 代码生成
这种属于 token-level 生成任务。
不推荐作为核心指标
- Accuracy
- F1
为什么?
因为生成任务:
- 输出长度不固定
- 同义表达很多
- 只要一个 token 不同,accuracy 就是 0
例如:
参考答案:
北京是中国的首都
模型输出:
中国的首都是北京
语义完全正确,但 token 级 accuracy 可能不高。
所以 F1/Accuracy 在生成任务里会严重失真。
最少需要:
①train/loss
交叉熵(Cross-Entropy)是衡量两个概率分布差异的指标。
在深度学习里,它通常表示:模型预测的概率分布 与 真实标签分布 之间的距离。
这是 LoRA 微调的第一判断指标。
原因:
- LoRA 本质是低秩参数更新
- 是否学到任务,本质反映在交叉熵是否下降
- 过拟合、学习率过大、r 过高都会体现在 loss 曲线上
你要关注:
| 现象 | 结论 |
|---|---|
| loss 快速 → 0 | LoRA 容量过大 / lr 过高 / 过拟合 |
| loss 下降很慢 | lr 太小 / LoRA 容量太小(r 太小 / target module 太少)/ 数据不够 |
| loss 震荡剧烈 | lr 太大 |
| loss 稳定下降并趋平 | 正常 |
如何区分“lr 太小”和“容量太小”?
| 操作 | 结果 |
|---|---|
| 提高 lr | loss 下降明显加快 → lr 原因 |
| 提高 lr | 几乎无变化 → 容量不足 |
②.eval/loss
和 train/loss 是同一种指标,只不过数据换成了验证集。
一、正常的 eval/loss 特征
1️⃣ 下降趋势与 train/loss 一致
- train/loss 下降 → eval/loss 也下降
- 说明模型不仅在记忆训练数据,也在泛化到验证集
2️⃣ 数值平稳,无剧烈波动
- 小幅波动正常(验证集较小或 batch size 小)
- 没有大幅上跳或异常跳变
3️⃣ 与训练阶段匹配
- 初期:eval/loss 下降快
- 中期:下降趋缓
- 后期:达到平台期,但仍略高于 train/loss(train < eval)
典型曲线:train/loss 平滑下降 → eval/loss 同步下降 → 最终平台轻微高于 train/loss
二、异常的 eval/loss 特征
1️⃣ eval/loss 快速上升
-
train/loss 下降 → eval/loss 却快速上升
-
原因:
- 模型过拟合训练集(train loss 很低,但泛化差)
- LoRA 容量太大(r 太大 / target modules 太多)
- dropout 太低,正则化不足
-
提示:
- 提前停止训练(early stopping)
- 或降低 r / 增加 dropout
2️⃣ eval/loss 波动剧烈
-
每轮验证差异很大
-
原因:
- 验证集太小 / batch size 太小
- 随机性太大(训练不稳定)
- lr 太高导致训练不稳定
-
提示:
- 稳定训练 → 减小 lr 或增加 eval batch size
- 多跑几次取平均
3️⃣ eval/loss 与 train/loss 差距过大
-
train/loss 很低,eval/loss 很高
-
原因:
- 过拟合
- 数据分布不一致(训练集 vs 验证集)
-
提示:
- 检查数据质量
- 调整容量 / dropout / α
4️⃣ eval/loss 不下降,长期平台
-
train/loss 正常下降,eval/loss 长期停滞
-
原因:
- LoRA 容量不足(r 太小)
- lr 太低 → 学不到泛化能力
- 数据噪声大
-
提示:
- 考虑提高 r 或增加 target module
- 调整 lr
三、判断 eval/loss 正常与异常的参考表
| eval/loss 特征 | 可能原因 | 结论 / 建议 |
|---|---|---|
| 平滑下降,略高于 train/loss | 正常 | 模型泛化良好 |
| 快速上升,train/loss 很低 | 过拟合 | 降低 r / 增加 dropout / early stopping |
| 长期平台,train/loss 下降 | 容量不足或 lr 太小 | 提高 r / lr |
| 剧烈波动 | lr 太高 / 验证集小 | 减小 lr / 增大 eval batch / 多次验证平均 |
| 突然爆炸 | 梯度异常 | 降低 lr,检查 α 和 dropout |
在Wandb生成val/loss
W&B 本身不会“生成” val/loss。
它只会记录你在代码里 主动计算并 log 的验证指标。
所以要让 W&B 出现 val/loss(或 eval/loss),本质上要完成三件事:
必须同时满足:
- 有验证集(eval_dataset)
- 训练过程中执行验证(evaluation loop)
- 把验证 loss 记录到 W&B
少任何一步,都不会出现。
如果你用 HuggingFace Trainer(最常见 LoRA 场景)
第一步:准备验证集
dataset = dataset.train_test_split(test_size=0.1)
train_dataset = dataset["train"]
eval_dataset = dataset["test"]
第二步:开启 evaluation
training_args = TrainingArguments(
output_dir="./output",
evaluation_strategy="steps", # 关键
eval_steps=200, # 每 200 step 验证一次
logging_steps=50,
report_to="wandb", # 确保开启 wandb
)
如果你写的是:
evaluation_strategy="no"
那永远不会出现 val/loss。
第三步:传入 eval_dataset
trainer = Trainer(
model=model,
args=training_args,
train_dataset=train_dataset,
eval_dataset=eval_dataset, # 必须传
)
只要满足以上条件,W&B 会自动出现:
eval/loss
注意:HF 默认字段名是 eval/loss,不是 val/loss。
三、如果你用 SFTTrainer(TRL 场景)
原理一样:
trainer = SFTTrainer(
model=model,
train_dataset=train_dataset,
eval_dataset=eval_dataset,
args=TrainingArguments(
evaluation_strategy="steps",
eval_steps=200,
report_to="wandb"
)
)
四、如果你是自写训练循环
那就需要手动 log:
wandb.log({
"val/loss": val_loss
}, step=global_step)
并且你必须写一个 validation forward:
model.eval()
with torch.no_grad():
for batch in val_loader:
outputs = model(**batch)
loss = outputs.loss
否则不会有。
五、常见为什么“开了也没有”
检查这几个点:
1️⃣ eval_dataset 是 None
→ 不会触发 evaluation
2️⃣ eval_steps 大于总 step
→ 训练结束前根本没执行 eval
3️⃣ 没设置 report_to="wandb"
→ 指标没上传
4️⃣ eval_accumulation_steps 配错导致没执行
六、工业推荐配置(LoRA 微调)
evaluation_strategy="steps"
eval_steps=200
logging_steps=50
load_best_model_at_end=True
metric_for_best_model="eval_loss"
greater_is_better=False
这样:
- 每 200 步验证
- 自动根据 eval_loss 保存最好模型
- 防止过拟合
③ train/grad_norm ——梯度向量整体大小 --- 稳定性指标 ⭐⭐⭐⭐
LoRA 很容易在:
- r 太大
- α 太大
- lr 太高
时出现梯度爆炸。
典型危险信号:
- grad_norm 突然飙升
- 波动剧烈
- loss 同时震荡
正常 LoRA 微调:
- 初期较高
- 然后缓慢下降
- 波动范围稳定
它是你判断是否需要:
- 降 lr
- 加 gradient clipping
- 降 LoRA rank
的关键指标。
④ train/entropy —— 过拟合预警指标 ⭐⭐⭐⭐
很多人忽略这个,但其实在 LLM 微调中非常重要。
熵下降代表模型越来越“自信”。
危险信号:
| 现象 | 说明 |
|---|---|
| entropy 急速下降 | 过拟合 |
| entropy 接近 0 | 模型开始塌缩 |
| entropy 和 loss 同时快速下降 | 过度记忆 |
LoRA 容量过大时特别容易出现。
它比 accuracy 更早暴露问题。
理想情况下:
perplexity
当是 “结构化分类/抽取” 微调任务的时候
用 loss 做 early stopping
用 macro-F1 选最优模型
主指标(业务指标) → F1(macro-F1 优先)
优化指标(训练稳定性) → eval/loss
- 意图识别(Intent Classification):≤10 个分类
- 动作分类(Action Classification):几十个分类
不同任务类别数和数据量对 F1 的期望是不同的,我给你一个系统分析:
一、意图识别(≤10 类)
- 类别少,数据量通常充足
- Macro-F1 相对容易达到高值
- 参考期望值:
| 数据量 | 类别数 | macro-F1 合理范围 |
|---|---|---|
| 小数据集 (<5k 样本) | ≤10 | 0.80–0.88 |
| 中等数据集 (5k–50k) | ≤10 | 0.85–0.92 |
| 大数据集 (>50k) | ≤10 | 0.88–0.95 |
说明:
- 少数类权重影响较小,Macro-F1 容易靠近 Accuracy
- 如果你看到 <0.75,说明模型还没学到规律 → 检查容量 / lr / 数据
二、动作分类(几十个类别)
- 类别多,数据不平衡可能严重
- 少数类 F1 往往拉低 Macro-F1
- 参考期望值:
| 数据量 | 类别数 | macro-F1 合理范围 |
|---|---|---|
| 小数据集 (<5k 样本) | 20~50 | 0.65–0.75 |
| 中等数据集 (5k–50k) | 20~50 | 0.70–0.80 |
| 大数据集 (>50k) | 20~50 | 0.75–0.85 |
说明:
- Macro-F1 相对意图识别低一些是正常的
- 业务上少数类的识别可以结合 Precision / Recall / top-k Accuracy 做辅助指标
三、微调策略建议
1️⃣ 先保证训练稳定
- 关注 train/eval loss,确保 LoRA 容量 + lr 合理
- 梯度正常 → loss 平稳下降
2️⃣ Macro-F1 作为业务指标
- 意图识别:F1 0.85–0.90 → 可以上线
- 动作分类:F1 0.70–0.80 → 可以接受,少数类可额外加权或做规则补偿
3️⃣ Early Stopping
- eval loss + macro-F1 联合监控
- 当 loss 平稳,macro-F1 不再明显提升 → 停训练
4️⃣ 类别不平衡处理
-
动作分类少数类可:
- 加权 loss(CrossEntropyLoss weight)
- 数据增强
- 重采样
四、总结
| 任务 | 类别数 | 数据量 | 期望 Macro-F1 |
|---|---|---|---|
| 意图识别 | ≤10 | 小→大 | 0.80–0.95 |
| 动作分类 | 20~50 | 小→大 | 0.65–0.85 |
F1 越高越好,但要结合 loss 曲线看训练是否健康。
动作分类低一些是正常现象,不必焦虑。

浙公网安备 33010602011771号