fix(simclr): 续训以配置为准,不再被存档里的超参静默覆盖
optimizer.load_state_dict 会整体覆盖 param_groups,把 lr / weight_decay 连同动量缓冲 一起还原成存档时的值。改了 yaml 再续训,改动会被静默吃掉:配置写 lr=5e-4, 实际仍按存档的 1e-3 训,scheduler.base_lrs 也是旧值。 改为「配置文件是唯一真相源,存档只提供进度」: - 加载优化器状态前先抄下配置构造出的每组超参,加载后按组写回,只留下动量缓冲; 按组写回也保住了 build_optimizer 的分组结构(BN 与 bias 那组 weight_decay=0) - 调度器统一按当前配置重建再快进到已训 epoch,不再恢复存档状态(它带着旧的 T_max 与 base_lrs)。cosine/step/multistep 都是 epoch 的确定性函数, 快进与恢复状态等价,因此不存在第二种行为 - 存档里额外记下当时的 optimizer/scheduler 配置,续训时逐项列出差异, 明确说明按当前配置执行 - 补回归测试:改 lr/weight_decay/总轮数后续训,三者都按 yaml 生效, 分组结构与动量缓冲不受影响 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
703ba7076b
commit
b7505a743d
@@ -302,8 +302,21 @@ uv run python scripts/cluster_unlabeled.py --config configs/cluster/film.yaml \
|
||||
```
|
||||
|
||||
日志会打印"已载入训练状态 …:从 epoch N 接着练到 40"。恢复的不只是权重,还有**投影头、
|
||||
优化器动量、学习率调度进度和 step 计数**——少了这些,续训等于把动量和 cosine 进度清零,
|
||||
损失会先反弹一段。
|
||||
优化器动量缓冲和 step 计数**——少了这些,续训等于把动量清零,损失会先反弹一段。
|
||||
|
||||
> **配置文件是唯一真相源。** 存档只提供"进度"(权重、动量、已训到第几轮);
|
||||
> `epochs`、`lr`、`weight_decay`、调度器一律以当前 yaml 为准。所以续训时可以顺手调超参:
|
||||
>
|
||||
> ```bash
|
||||
> uv run python scripts/cluster_unlabeled.py --config configs/cluster/film.yaml \
|
||||
> --work-dir runs/simclr \
|
||||
> --set method=simclr simclr.epochs=60 simclr.optimizer.lr=5e-4 \
|
||||
> simclr.resume=runs/simclr/simclr_last.pth
|
||||
> ```
|
||||
>
|
||||
> 与存档不一致时日志会逐项列出(`配置与存档不一致,按当前配置执行:总轮数 40 -> 60;
|
||||
> optimizer.lr 0.001 -> 0.0005`),不会出现"改了没生效"。学习率调度按新的总轮数重建
|
||||
> 并快进到当前 epoch,不会沿用存档里的 T_max。
|
||||
|
||||
> `resume` 与 `checkpoint` 语义不同,二选一(同时给会报错):
|
||||
> **`resume`** = 载入完整状态**接着训练**(要 `simclr_last.pth`);
|
||||
|
||||
Reference in New Issue
Block a user