DINOv3超参数调优:学习率、权重衰减、批次大小一次配对的速查表
【免费下载链接】dinov3Reference PyTorch implementation and models for DINOv3项目地址: https://gitcode.com/GitHub_Trending/di/dinov3
刚把 DINOv3 的 config 复制下来跑,loss 在前几个 epoch 正常下降,warmup 一结束就慢慢爬到不再动了——大概率不是数据的问题,而是学习率、批次大小和权重衰减这三者没按项目里的缩放规则一起配对。DINOv3 的调参和一般网络不一样:config 里写的 lr 只是"基准值",训练启动时会按总批次大小乘一个缩放系数,你只改其中一个参数而不理解这条链路,数字看着对、实际全错。
先给结论:各模型规模默认超参数速查
| 配置场景 | 学习率(peak) | 预热 | 权重衰减 | 每 GPU 批次 | 梯度裁剪 | 来源文件 |
|---|---|---|---|---|---|---|
| 默认 ViT-L 预训练 | 0.001 | 10 epoch | 0.04 → 0.4 | 64 | 3.0 | dinov3/configs/ssl_default_config.yaml |
| ViT-L ImageNet-1K 线性评测 | 0.001 | 10 epoch | 0.04 → 0.4 | 以官方最新配置为准 | 3.0 | dinov3/configs/train/vitl_im1k_lin834.yaml |
| ViT-L 蒸馏 | 0.0002 | 0 | 0.04 | 3 | 3.0 | dinov3/configs/train/dinov3_vitl16_lvd1689m_distilled.yaml |
| ViT-7B 预训练 | 5.0e-05 | 100 epoch | 0.04 | 16 | 30.0 | dinov3/configs/train/dinov3_vit7b16_pretrain.yaml |
| ViT-7B 高分辨率适配 | 1.25e-05(end) | 0 | 0.04 | 8 | 30.0 | dinov3/configs/train/dinov3_vit7b16_high_res_adapt.yaml |
| ConvNeXt 蒸馏 | 1e-4 | 80 epoch | 0.02 → 0.2 | 以官方最新配置为准 | 3.0 | dinov3/configs/train/distillation_convnext/convnext_base_p16.yaml |
以上数字全部直接取自仓库dinov3/configs/下的官方 yaml,不是经验估计。注意预训练和适配场景的裁剪阈值差了 10 倍(3.0 vs 30.0),这个区别下面会讲。
三个超参数,逐个拆
学习率:config 里写的只是缩放前的基准值
它控制每步参数更新的步长,但 DINOv3 里你填的数字不等于实际生效的数字。默认缩放规则是sqrt_wrt_1024,训练脚本dinov3/train/train.py里会执行:
lr_peak *= 4 * math.sqrt(batch_size_per_gpu * world_size / 1024.0)也就是说总批次 1024 时 lr 不变,批次翻倍只让 lr 增长 1.41 倍而不是 2 倍——这是 DINOv3 预训练和很多博客写的"线性缩放"最大的不同,项目里也保留了linear_wrt_256规则可选,但官方预训练配置全部用 sqrt 规则。什么时候才需要动它:你改了总批次大小(加卡或减卡),就不用手动改 lr,缩放规则会自动处理;需要手动改的只有两种情况——换了缩放规则本身,或者做像 7B 高分辨率适配那样的微调(官方把 end 压到 1.25e-05 这种小值)。另外patch_embed_lr_mult: 0.2意味着 patch 嵌入层的学习率永远是主干的 0.2 倍,调参时别把它忘了。
权重衰减:两个值,一个起步一个收尾
它控制参数更新的 L2 惩罚强度,防止过拟合。DINOv3 的默认写法是一个区间:
weight_decay: 0.04 weight_decay_end: 0.4起步 0.04 是 DINO 系模型的常规值,收尾 0.4 用于训练后期收紧参数。什么时候动它:绝大多数微调场景 0.04 起步就够用,不需要碰 end;只有在训练后期明显过拟合(验证 loss 持续差于训练 loss)时再考虑加大 end。注意 ConvNeXt 蒸馏配置里是 0.02 → 0.2,和 ViT 默认不同——不同架构的官方推荐值不一样,以对应 yaml 为准。
批次大小:改的是内存压力,不是收敛速度
它决定每步用多少样本,直接影响显存占用和上面那条缩放公式的输入。默认配置是每 GPU 64 个样本、OFFICIAL_EPOCH_LENGTH: 1250,一个"官方 epoch"是固定迭代数而不是跑完全部数据。什么时候动它:显存不够就降,比如 ViT-7B 预训练官方配的就是每卡 16;显存富余就升。但记住 lr 会自动随它缩放,所以"加卡"和"改批次"在效果上等价,不存在"加卡白送收敛加速"这种好事。
动手调:从跑通到调优的四步流程
Step 1,原封不动跑一遍官方默认 config,比如dinov3/configs/ssl_default_config.yaml对应的 ViT-L 预训练。判断标准:前 100 个 iteration 内 loss 从高位平滑下降、没有 NaN,日志里会打印缩放后的实际 lr,和你手算的4·sqrt(总批次/1024)一致。
Step 2,把数据集路径和输出目录换成你自己的,模型规模先别动,让整条链路(数据加载、FSDP 分片、checkpoint)走通。判断标准:checkpointing配置的保存周期(默认 period 3750)后磁盘上出现 checkpoint 文件。
Step 3,按你的实际卡数改批次大小,只改batch_size_per_gpu一个数,确认日志里缩放后的 lr 落在预期区间。判断标准:总批次越小实际 lr 越低,如果卡数从 8 张减到 2 张,warmup 期可以同步缩短,观察 loss 下降斜率是否和满卡时可比。
Step 4,单变量调参,一次只动一个(学习率、权重衰减、批次三选一),每轮跑够一个OFFICIAL_EPOCH_LENGTH的迭代再下结论。判断标准:对比同一 checkpoint 频率下的 loss 曲线和内置 eval 指标,变化幅度明显大于噪声再认定调参有效。
这几个坑别踩
现象:loss 正常降了 20 个 epoch,之后突然抬头甚至飙升。原因:大概率是权重衰减或 lr 的 cosine 尾部没对齐——DINOv3 用线性预热加余弦退火(linear_warmup_cosine_decay,见dinov3/train/cosine_lr_scheduler.py),如果你手动改了 epoch 数却没同步改schedules.lr里的cosine_epochs,lr 会在不该低的时候还很高。怎么处理:改完 epoch 数检查schedules段里 warmup、cosine 各项 epoch 之和是否合理,让余弦段覆盖训练后期。
现象:减卡后 loss 曲线比满卡时抖得多。原因:批次变小后实际 lr 按 sqrt 规则降下来了,但 7B 这种大模型配的是 30.0 的裁剪阈值,小模型 3.0,阈值过大时偶发大梯度会直接打进参数里。怎么处理:按模型规模用官方对应的clip_grad值,小模型别沿用 30.0。
现象:换了 3D 架构(ConvNeXt)直接套 ViT 的 lr 配置,收敛极慢。原因:不同架构的官方学习率差距很大,ConvNeXt 蒸馏配置 peak 是 1e-4、预热 80 epoch,比 ViT-L 默认的 0.001 低一个量级。怎么处理:跨架构迁移时以目标架构的官方 yaml 为基准,不从 ViT 配置推。
现象:手动把warmup_epochs调大想更稳,结果 loss 全程趴在高位不动。原因:预热期内 lr 是从 0 线性爬的,warmup 占总步数比例过大等于训练后期才刚爬到 peak。怎么处理:warmup 通常控制在总 epoch 的 10% 以内(默认 100 epoch 配 10 个 epoch 预热;7B 是 1000 epoch 配 100),按比例来。
现象:改了batch_size_per_gpu之后 eval 指标反而变差,怀疑是学习率没调好。原因:可能先查错地方了——DINOv3 里 lr 缩放只看总批次,如果你同时改了OFFICIAL_EPOCH_LENGTH,总迭代数和调度长度都变了,等效 lr 轨迹完全不同。怎么处理:一次只改一个维度,先固定 epoch 长度再动批次。
按硬件和任务选配置
| GPU 规模(总卡数) | ViT-S/B 小模型 | ViT-L | ViT-7B |
|---|---|---|---|
| 8 卡 | 每卡 64,lr 基准 0.001,clip 3.0 | 每卡 64 起步,显存紧则降 | 每卡 16 起步,clip 30.0 |
| 32 卡 | 每卡 64(总批次 2048,lr 自动 ×1.41) | 每卡 32~64 | 每卡 8~16(显存富余再升) |
| 128 卡 | 每卡 16~32(总批次过大时 lr 增长放缓) | 每卡 16~32 | 每卡 4~8 |
表内数字来自各官方 yaml 的batch_size_per_gpu和缩放规则;超出这张表范围时通用原则就一条:按4·sqrt(总批次/1024)算实际 lr,总批次离 1024 越远,单位样本的 lr 越"便宜",大批次场景可以适当加 peak、小批次场景别硬抬。
调完怎么确认没翻车
盯三个指标。第一是loss 曲线的形状:正常应该是预热段单调下降、余弦段缓慢收敛,前期锯齿抖动幅度随 lr 下降而收窄;异常时先查clip_grad是否匹配模型规模,再看缩放日志里的实际 lr。第二是梯度范数:config 里有monitor_gradient_norm开关,打开后如果范数周期性尖峰,多半是批次里混进了难样本或裁剪阈值过松,先查数据增强参数(crops段)而不是 lr。第三是内置 eval 指标:默认每 12500 个 iteration 跑一次高频 eval(eval_period_iterations),eval 曲线和训练 loss 背离说明在过拟合,回头看权重衰减的 end 值。eval 相关脚本在dinov3/eval/下,线性探针入口是dinov3/eval/linear.py,里面也自带scale_lr按批次缩放,评测试图时同样别手改 lr。
先把ssl_default_config.yaml原样跑通、确认日志里的缩放 lr 和你预期一致,之后一次只改学习率这一个变量做对比,其他参数一律不动。
【免费下载链接】dinov3Reference PyTorch implementation and models for DINOv3项目地址: https://gitcode.com/GitHub_Trending/di/dinov3
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考