ViT 微调指南:数据量定冻结策略,三旋钮调出高准确率
【免费下载链接】pytorch-image-modelsThe largest collection of PyTorch image encoders / backbones. Including train, eval, inference, export scripts, and pretrained weights -- ResNet, ResNeXT, EfficientNet, NFNet, Vision Transformer (ViT), MobileNetV4, MobileNet-V3 & V2, RegNet, DPN, CSPNet, Swin Transformer, MaxViT, CoAtNet, ConvNeXt, and more项目地址: https://gitcode.com/GitHub_Trending/py/pytorch-image-models
解决在 pytorch-image-models(timm)里做 ViT 微调、换到自定义数据后准确率上不去的问题:先看数据量决定冻哪些层,再调学习率、数据增强、正则化三个旋钮,出问题按症状排查。全文给出完整的决策与诊断路径。
🧊 先判断:你的数据量适合哪种微调
结论先说:冻结多少层,由数据量决定,而不是由模型大小决定。ViT 的 12 个 encoder block(见 timm/models/vision_transformer.py)参数贵、易过拟合,数据少时全量微调基本等于把预训练知识冲掉。
| 数据量 | 冻结策略 | 学习率量级 | Drop Path |
|---|---|---|---|
| < 1 万 | 冻结底部 10~12 个 block,只训顶部 1~2 个 block + 分类头 | 1e-5 ~ 2e-5(分类头可放大 10 倍) | 0.0 ~ 0.1 |
| 1 万 ~ 10 万 | 全部解冻 | 2e-5 ~ 5e-5 | 0.1 |
| > 10 万 | 全部解冻,全量微调 | 5e-5 ~ 1e-4 | 0.1 ~ 0.2 |
两个补充点:
- 分类头永远是新初始化的,永远要训,且可以比 encoder 用更大的学习率。
- 数据量卡在临界区间时,先用小学习率全量跑,发现过拟合再回退到冻结方案,比一开始就保守更安全。
🎛️ 三个旋钮:学习率、增强、正则化
1️⃣ 学习率:从小区间起步,必配 warmup
模型按数据量选好冻结方案后,学习率直接取上表对应区间。ViT 对大学习率非常敏感,第一 epoch loss 跳变甚至 NaN,多半是学习率大了 5~10 倍,直接降到 3e-5 重试。
调度推荐余弦退火 + warmup,工厂实现见 timm/scheduler/:
- 总轮数 30 轮左右,warmup 5 轮,
min_lr收到 1e-6 - 优化器用 AdamW,权重衰减 0.05
如果发现 warmup 结束后 loss 仍上下震荡,说明 warmup 太短,拉长到 8~10 轮;如果 loss 一路平走、acc 纹丝不动,多半是学习率太小或层冻多了。
2️⃣ 数据增强:够用就好,别堆砌
增强的作用是让模型学不到"死记硬背"的捷径,而不是越多越强。一组在 timm 里开箱即用的推荐配置:
| 参数 | 值 | 作用 |
|---|---|---|
| 自动增强 | rand-m9-mstd0.5-inc1 | RandAugment,主力增强 |
| color_jitter | 0.4 | 颜色抖动 |
| re_prob / re_mode | 0.25 /pixel | 随机擦除,兼作正则 |
| interpolation | bicubic | ViT 对插值方式敏感,别用 nearest |
出现什么信号说明调错了:val acc 停滞但 train acc 还在涨 → 增强不够,把re_prob加到 0.3 或提高 RandAugment 的 mstd;loss 收敛明显变慢、前几轮 acc 低得离谱 → 增强过强,把 color_jitter 降到 0.3 以下。
3️⃣ 正则化:Drop Path、标签平滑、EMA 三件套
- Drop Path:
drop_path_rate设 0.1 起步,过拟合时加到 0.2。它是按深度线性递增的随机深度,比全连接层 dropout 更适合 Transformer。 - 标签平滑:
LabelSmoothingCrossEntropy(smoothing=0.1),防止模型对预训练分布过度自信。 - EMA:维护一份权重的指数滑动平均,衰减率取 0.9999(timm/utils/model_ema.py 的
ModelEmaV3默认值)。验证和导出用 EMA 权重,不用原始权重,通常白捡 0.3~1 个点。
训练循环核心就这么短:
model_ema = ModelEmaV3(model, decay=0.9999) for x, y in loader: out = model(x) loss = criterion(out, y) loss.backward() optimizer.step() optimizer.zero_grad() model_ema.update(model)🩺 不收敛、过拟合、推理慢?按症状查
别瞎调参,先看症状对号入座,一次只改一个变量:
| 症状 | 第一怀疑 | 对应手段 |
|---|---|---|
| 前 1 epoch loss 不降或出 NaN | 学习率过高、归一化不一致 | 降到 3e-5;确认用 ImageNet 均值/标准差归一化 |
| loss 震荡,warmup 完仍不平稳 | warmup 太短、调度太激进 | warmup 拉到 8~10 轮,换余弦退火 |
| train acc 接近 100%,val 不动 | 过拟合 | drop_path 加到 0.2;re_prob0.25;标签平滑 0.1;改用 EMA 权重评估 |
| train、val 双双低迷 | 冻得太多 / 学习率太小 | 多解冻 2 个 block,学习率上调一档;确认分类头在可训练状态 |
| 推理慢 | 裸 eager 推理 | torch.compile(model)+ 混合精度,或换更小变体(vit_small、蒸馏版) |
排查顺序建议:先确认归一化和数据管道(错得最冤),再动学习率,最后才碰增强和正则。
🚀 还想更进一步
- 分层学习率衰减:timm.optim 里的
param_groups_layer_decay可以给不同深度 block 分配不同学习率,大数据量全量微调时收益明显。 - 蒸馏:用预训练 ViT 当教师,在小数据集上蒸馏一个小一号的学生模型,数据少时比硬微调更稳。
- 高分辨率训练:
vit_base_patch16_224在 384/448 输入下微调,适合精细分类任务,代价是显存翻倍。
把数据量定冻结、三个旋钮调到位,大多数微调困境都能解掉;剩下的,交给症状表。
【免费下载链接】pytorch-image-modelsThe largest collection of PyTorch image encoders / backbones. Including train, eval, inference, export scripts, and pretrained weights -- ResNet, ResNeXT, EfficientNet, NFNet, Vision Transformer (ViT), MobileNetV4, MobileNet-V3 & V2, RegNet, DPN, CSPNet, Swin Transformer, MaxViT, CoAtNet, ConvNeXt, and more项目地址: https://gitcode.com/GitHub_Trending/py/pytorch-image-models
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考