fix(backbones): 修复 shufflenet 无法构建,并让换骨架不再踩配置合并的坑

- shufflenet_v2_x1_0 列在支持清单里却直接 AttributeError:ShuffleNetV2 既不是
  扁平 children 也没有 .features,需要按 conv1/maxpool/stage2..4/conv5 自己拼。
  该 bug 同时影响 SimCLR 与检测模型
- 新增参数化测试覆盖清单里的每个 arch:能前向、声明的 out_channels 与实际一致
- 配置支持 `_replace_: true`:子字典整块替换而不与 base 合并。换骨架时
  tiny_conv 的 widths/depths 会残留并传给新骨架,此前无论用 --set 还是 _base_
  都绕不开,只能改原文件
- Registry.build 提前校验字段,报错直接指出是哪些字段不被接受、该怎么办,
  取代裸 TypeError
- README 补充可选骨架表与三种改法(含不该用 --set 改 name 的说明)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Shaun Zhou
2026-09-04 15:28:49 +08:00
co-authored by Claude Opus 5
parent e4bd794025
commit e581d9b3d7
7 changed files with 204 additions and 8 deletions
+45
View File
@@ -353,6 +353,51 @@ view_transforms: # 生成两个视图的随机增强
> `RandomResizedCrop` 的 `scale` 下限别低于 0.4:裁太狠会让两个视图都只剩背景,
> "背景 vs 背景"被当成正样本对,学出来的特征会退化。
#### 换一个骨架
`simclr.backbone` 用的是和检测模型同一套注册表,可选:
| `name` | `arch` | out_channels | 说明 |
| --- | --- | --- | --- |
| `tiny_conv` | — | 256(可调) | 自研深度可分离卷积,默认,最轻 |
| `torchvision` | `resnet18` / `resnet34` | 512 | 通用基线 |
| `torchvision` | `resnet50` | 2048 | 最强也最重,MPS 上注意 batch |
| `torchvision` | `mobilenet_v3_small` / `_large` | 576 / 960 | 面向实时部署 |
| `torchvision` | `shufflenet_v2_x1_0` | 1024 | 同上 |
全是纯卷积(ViT/Swin 不在支持范围,本项目要部署在实时设备上)。改法是**整块替换**
`simclr.backbone`,因为两种骨架的字段完全不同(`widths/depths/block` vs `arch/pretrained`):
```yaml
# configs/cluster/film.yaml
simclr:
backbone:
name: torchvision
arch: resnet18
pretrained: true # 先用 ImageNet 权重起步,再在本批数据上自监督微调
in_channels: 3
```
如果不想改原文件,用 `_base_` 继承时要加 `_replace_: true`——子字典默认是**合并**而不是
替换,不加的话 base 里 `tiny_conv` 的 `widths/depths` 会残留下来传给新骨架:
```yaml
_base_: [configs/cluster/film.yaml]
simclr:
backbone:
_replace_: true # 整块换掉,不与 base 合并
name: torchvision
arch: resnet18
pretrained: true
```
> **不要用 `--set simclr.backbone.name=torchvision`**:它只改名字,旧骨架的专有字段仍在,
> 会报 `构建 'torchvision' 时收到它不接受的字段 ['block', 'depths', 'widths']`。
> 换组件请改配置文件。
注意 `simclr.feature_stages`:`torchvision` 系列的 `features` 是 `nn.Sequential`,可以填
`[5, 6]` 这类中间层下标;`tiny_conv` 不是,必须保持 `null`(取最终输出)。
SimCLR 训练同样接了 SwanLab(配置在 `simclr.swanlab`,字段与 `train.swanlab` 相同,
默认 `mode: local` 不需要登录)。训练跑起来后另开一个终端: