TorchVision RegNet 模型完全指南:网络设计空间与预训练权重实战
【免费下载链接】visionDatasets, Transforms and Models specific to Computer Vision项目地址: https://gitcode.com/gh_mirrors/vi/vision
本文基于当前仓库(GitHub 加速计划 / vi / vision)中的官方模型文档与源码,系统讲解 TorchVision 中 RegNet 系列图像分类模型。读者将掌握 RegNetX / RegNetY 两种设计空间族共 15 个模型构建器的用法、BlockParams参数化设计原理、多版本预训练权重(含 SWAG 迁移权重)的选取与推理预处理,以及基于references/classification训练配方的复现命令。
RegNet 是什么
RegNet(Regular Networks)源自论文Designing Network Design Spaces(arXiv:2003.13678),其核心思想是用可量化的参数直接定义网络架构,而不是像 ResNet、EfficientNet 那样依靠人工堆叠 stage 与通道数。论文作者通过一个简化的 AnyNet 设计空间逐步约束出 RegNet 设计空间,从而得到一系列在计算量(FLOPs)与精度之间取得良好平衡的网络。
在 TorchVision 中,RegNet 归属于图像分类模型家族,与 ResNet、EfficientNet 等并列于 models.rst 的 Classification 分类下(见 models.rst 中的 toctree 引用models/regnet)。当前仓库提供RegNetX(无 SE 模块)与 RegNetY(含 SE 模块)两个设计空间族,涵盖从 400MF 到 128GF 共 15 个不同计算量的变体。
模型构建器总览
官方文档 regnet.rst 明确说明:以下 15 个模型构建器均可用于实例化 RegNet 模型,支持或不支持预训练权重,且所有构建器内部都依赖torchvision.models.regnet.RegNet基类。
| 设计空间族 | 模型构建器 |
|---|---|
| RegNetY(含 SE) | regnet_y_400mf、regnet_y_800mf、regnet_y_1_6gf、regnet_y_3_2gf、regnet_y_8gf、regnet_y_16gf、regnet_y_32gf、regnet_y_128gf |
| RegNetX(无 SE) | regnet_x_400mf、regnet_x_800mf、regnet_x_1_6gf、regnet_x_3_2gf、regnet_x_8gf、regnet_x_16gf、regnet_x_32gf |
名称中的后缀(如400mf、1_6gf、32gf)表示该网络的目标计算量:mf为百万 FLOPs(MFLOPs),gf为十亿 FLOPs(GFLOPs)。这些构建器都通过 @register_model() 注册到torchvision.models命名空间,可直接从torchvision.models导入使用。
在 test/test_models.py 中,这些构建器被列入_model_impls之类的模型枚举清单参与测试;其中regnet_y_128gf因为参数量高达约 6.45 亿(见下文权重表),在 Windows CPU/CUDA 环境下被排除在默认测试之外(见 test/test_models.py),同样也被 test/test_extended_models.py 排除在扩展模型测试的批量实例化之外。
架构源码剖析
RegNet 的实现位于 torchvision/models/regnet.py,整体由 stem、trunk(多个 stage)与分类头三部分组成。RegNet类的forward流程为:stem → trunk_output → avgpool → flatten → fc(见 regnet.py)。
Stem:SimpleStemIN
class SimpleStemIN(Conv2dNormActivation): """Simple stem for ImageNet: 3x3, BN, ReLU."""即一个kernel_size=3, stride=2的卷积 + BatchNorm + ReLU 组合(见 regnet.py),将 3 通道输入下采样到stem_width(默认 32)通道。它复用了 torchvision/ops/misc.py 中的Conv2dNormActivation容器。
BottleneckTransform:核心变换
每个残差块内部的变换为1x1 → 3x3(分组卷积)→ [SE] → 1x1结构(见 regnet.py):
- 第一个
1x1卷积将通道数缩窄到w_b = round(width_out * bottleneck_multiplier); - 中间
3x3卷积以groups = w_b // group_width做分组卷积(这正是 RegNet 区别于普通 ResNet 的关键:通过group_width控制每个分组的宽度); - 若设置了
se_ratio,则插入SqueezeExcitation通道注意力模块,其压缩通道数为round(se_ratio * width_in); - 最后一个
1x1卷积恢复/扩展到width_out,且不带激活函数(activation_layer=None)。
ResBottleneckBlock:残差连接
should_proj = (width_in != width_out) or (stride != 1) if should_proj: self.proj = Conv2dNormActivation(width_in, width_out, kernel_size=1, stride=stride, ...) self.f = BottleneckTransform(...)当输入输出通道数不同或 stride 不为 1 时,自动添加 1x1 投影跳跃连接(见 regnet.py),前向计算x = proj(x) + f(x)后再过激活函数。
AnyStage:同宽度的块序列
一个 stage 由多个输出 shape 相同的块组成(见 regnet.py):stage 内第一个块使用 stage 的 stride 并接收上一 stage 的输出宽度,其余块 stride 为 1 且输入输出宽度相同。块命名形如block1-0、block1-1。
权重初始化
RegNet.__init__末尾执行 ResNet 风格初始化(见 regnet.py):卷积层按std=sqrt(2 / fan_out)的 Kaiming 正态初始化(BN 存在故无 bias),BatchNorm 的 weight 置 1、bias 置 0,全连接层按std=0.01初始化。
BlockParams:从 5 个参数生成整个网络
RegNet 的精髓在于用极少的超参数程序化地推导出每一层的宽度与深度,这一逻辑全部封装在BlockParams.from_init_params类方法中(见 regnet.py),其核心入参:
| 参数 | 含义 | 约束(源码校验) |
|---|---|---|
depth | 总块数(所有 stage 块数之和) | 正整数 |
w_0 | 起始块宽度 | w_0 > 0且w_0 % 8 == 0 |
w_a | 宽度增长斜率 | w_a >= 0 |
w_m | 对数空间中的宽度步进 | w_m > 1 |
group_width | 分组卷积的组宽度 | 正整数 |
bottleneck_multiplier | 瓶颈压缩倍数 | 默认1.0 |
se_ratio | SE 压缩比例 | 默认None(RegNetX 不用,RegNetY 用0.25) |
其计算分两步:
- 对数空间宽度量化(见 regnet.py):先按
widths_cont = arange(depth) * w_a + w_0得到连续宽度序列,再在 log 空间按block_capacity = round(log(w / w_0) / log(w_m))分桶,最后block_widths = round(w_0 * w_m^capacity / 8) * 8量化为8 的倍数(源码常量QUANT = 8)。w_a是宽度递增斜率,w_0是初始宽度,w_m控制宽度在对数空间的阶梯大小——这正是文档注释中所说的log(block_width) = log(w_0) + w_m * block_capacity。 - 按宽度突变切分 stage:宽度发生变化的相邻块之间即 stage 分界,随后把每个 stage 的 stride 统一设为 2(源码常量
STRIDE = 2),并调用_adjust_widths_groups_compatibilty保证 stage 宽度与分组宽度兼容(见 regnet.py)。
如果w_a < 0 or w_0 <= 0 or w_m <= 1 or w_0 % 8 != 0,会直接抛出ValueError("Invalid RegNet settings")(见 regnet.py)。
各变体的实际参数
每个构建器都通过BlockParams.from_init_params(...)传入论文给出的具体超参数,例如:
| 构建器 | depth | w_0 | w_a | w_m | group_width | se_ratio | 源码位置 |
|---|---|---|---|---|---|---|---|
regnet_y_400mf | 16 | 48 | 27.89 | 2.09 | 8 | 0.25 | regnet.py |
regnet_y_800mf | 14 | 56 | 38.84 | 2.40 | 16 | 0.25 | regnet.py |
regnet_y_1_6gf | 27 | 48 | 20.71 | 2.65 | 24 | 0.25 | regnet.py |
regnet_y_3_2gf | 21 | 80 | 42.63 | 2.66 | 24 | 0.25 | regnet.py |
regnet_y_8gf | 17 | 192 | 76.82 | 2.19 | 56 | 0.25 | regnet.py |
regnet_y_16gf | 18 | 200 | 106.23 | 2.48 | 112 | 0.25 | regnet.py |
regnet_y_32gf | 20 | 232 | 115.89 | 2.53 | 232 | 0.25 | regnet.py |
regnet_y_128gf | 27 | 456 | 160.83 | 2.52 | 264 | 0.25 | regnet.py |
regnet_x_400mf | 22 | 24 | 24.48 | 2.54 | 16 | — | regnet.py |
regnet_x_800mf | 16 | 56 | 35.73 | 2.28 | 16 | — | regnet.py |
regnet_x_1_6gf | 18 | 80 | 34.01 | 2.25 | 24 | — | regnet.py |
regnet_x_3_2gf | 25 | 88 | 26.31 | 2.25 | 48 | — | regnet.py |
regnet_x_8gf | 23 | 80 | 49.56 | 2.88 | 120 | — | regnet.py |
regnet_x_16gf | 22 | 216 | 55.59 | 2.10 | 128 | — | regnet.py |
regnet_x_32gf | 23 | 320 | 69.86 | 2.00 | 168 | — | regnet.py |
可见 RegNetX 全部不设se_ratio(无 SE 模块),而 RegNetY 统一使用se_ratio=0.25——这是两者唯一的本质区别。从bottleneck_multiplier默认 1.0 来看,当前实现采用单倍瓶颈宽度。
预训练权重体系
遵循 TorchVision 自 v0.13 起的 Multi-weight support API,每个 RegNet 构建器都对应一个WeightsEnum权重枚举类(如RegNet_Y_400MF_Weights、RegNet_X_32GF_Weights),可通过weights=关键字显式选取权重版本,默认weights=None表示随机初始化(见 regnet.py 的 docstring 说明)。
权重版本类型
从源码可以归纳出以下权重来源:
- IMAGENET1K_V1:使用简单的训练配方复现论文结果(
recipe指向references/classification的 small / medium / large 模型章节); - IMAGENET1K_V2:基于 TorchVision 新版训练配方(含 FixRes 类策略,RegNetX 各版本注明
new-recipe-with-fixres)训练,精度全面超越 V1,且DEFAULT均指向 V2; - IMAGENET1K_SWAG_E2E_V1:对 SWAG 自监督预训练权重在 ImageNet-1K 上端到端微调得到,仅在
regnet_y_16gf、regnet_y_32gf、regnet_y_128gf三个大模型上提供; - IMAGENET1K_SWAG_LINEAR_V1:冻结 SWAG trunk + 在 ImageNet-1K 上训练线性分类头,同样只在大模型上提供。
SWAG 系权重的预处理与普通版本不同:E2E 版使用crop_size=384, resize_size=384, interpolation=BICUBIC,LINEAR 版使用crop_size=224, resize_size=224, interpolation=BICUBIC(见 regnet.py)。普通版本 V1 仅用crop_size=224,V2 则增加resize_size=232的 FixRes 式预处理。
ImageNet-1K 精度与算量表
以下数据全部来自 regnet.py 中各Weights的_metrics/_ops/num_params元数据(单 crop 评估,单位为 %,GFLOPs):
| 构建器 | 权重版本 | Acc@1 / Acc@5 | GFLOPs | 参数量 | 文件大小 (MB) |
|---|---|---|---|---|---|
| regnet_y_400mf | V1 | 74.046 / 91.716 | 0.402 | 4,344,144 | 16.806 |
| regnet_y_400mf | V2 | 75.804 / 92.742 | 0.402 | 4,344,144 | 16.806 |
| regnet_y_800mf | V1 | 76.420 / 93.136 | 0.834 | 6,432,512 | 24.774 |
| regnet_y_800mf | V2 | 78.828 / 94.502 | 0.834 | 6,432,512 | 24.774 |
| regnet_y_1_6gf | V1 | 77.950 / 93.966 | 1.612 | 11,202,430 | 43.152 |
| regnet_y_1_6gf | V2 | 80.876 / 95.444 | 1.612 | 11,202,430 | 43.152 |
| regnet_y_3_2gf | V1 | 78.948 / 94.576 | 3.176 | 19,436,338 | 74.567 |
| regnet_y_3_2gf | V2 | 81.982 / 95.972 | 3.176 | 19,436,338 | 74.567 |
| regnet_y_8gf | V1 | 80.032 / 95.048 | 8.473 | 39,381,472 | 150.701 |
| regnet_y_8gf | V2 | 82.828 / 96.330 | 8.473 | 39,381,472 | 150.701 |
| regnet_y_16gf | V1 | 80.424 / 95.240 | 15.912 | 83,590,140 | 319.49 |
| regnet_y_16gf | V2 | 82.886 / 96.328 | 15.912 | 83,590,140 | 319.49 |
| regnet_y_16gf | SWAG_E2E | 86.012 / 98.054 | 46.735 | 83,590,140 | 319.49 |
| regnet_y_16gf | SWAG_LINEAR | 83.976 / 97.244 | 15.912 | 83,590,140 | 319.49 |
| regnet_y_32gf | V1 | 80.878 / 95.340 | 32.28 | 145,046,770 | 554.076 |
| regnet_y_32gf | V2 | 83.368 / 96.498 | 32.28 | 145,046,770 | 554.076 |
| regnet_y_32gf | SWAG_E2E | 86.838 / 98.362 | 94.826 | 145,046,770 | 554.076 |
| regnet_y_32gf | SWAG_LINEAR | 84.622 / 97.480 | 32.28 | 145,046,770 | 554.076 |
| regnet_y_128gf | SWAG_E2E | 88.228 / 98.682 | 374.57 | 644,812,894 | 2461.564 |
| regnet_y_128gf | SWAG_LINEAR | 86.068 / 97.844 | 127.518 | 644,812,894 | 2461.564 |
| regnet_x_400mf | V1 | 72.834 / 90.950 | 0.414 | 5,495,976 | 21.258 |
| regnet_x_400mf | V2 | 74.864 / 92.322 | 0.414 | 5,495,976 | 21.257 |
| regnet_x_800mf | V1 | 75.212 / 92.348 | 0.8 | 7,259,656 | 27.945 |
| regnet_x_800mf | V2 | 77.522 / 93.826 | 0.8 | 7,259,656 | 27.945 |
| regnet_x_1_6gf | V1 | 77.040 / 93.440 | 1.603 | 9,190,136 | 35.339 |
| regnet_x_1_6gf | V2 | 79.668 / 94.922 | 1.603 | 9,190,136 | 35.339 |
| regnet_x_3_2gf | V1 | 78.364 / 93.992 | 3.177 | 15,296,552 | 58.756 |
| regnet_x_3_2gf | V2 | 81.196 / 95.430 | 3.177 | 15,296,552 | 58.756 |
| regnet_x_8gf | V1 | 79.344 / 94.686 | 7.995 | 39,572,648 | 151.456 |
| regnet_x_8gf | V2 | 81.682 / 95.678 | 7.995 | 39,572,648 | 151.456 |
| regnet_x_16gf | V1 | 80.058 / 94.944 | 15.941 | 54,278,536 | 207.627 |
| regnet_x_16gf | V2 | 82.716 / 96.196 | 15.941 | 54,278,536 | 207.627 |
| regnet_x_32gf | V1 | 80.622 / 95.248 | 31.736 | 107,811,560 | 412.039 |
| regnet_x_32gf | V2 | 83.014 / 96.288 | 31.736 | 107,811,560 | 412.039 |
值得注意的规律:同等算力下 RegNetY 精度普遍高于 RegNetX(SE 模块带来的增益),而 RegNetY 的参数量也相应更大;regnet_y_128gf是唯一不提供 V1/V2 标准权重、只提供 SWAG 迁移权重的变体,且其DEFAULT指向 SWAG_E2E(见 regnet.py)。
快速上手:加载预训练模型做推理
推荐的做法是使用weights.transforms()自动获取对应权重版本的正确预处理,避免因预处理不匹配导致精度下降。参考 models.rst 中分类模型的通用推理流程,以下给出 RegNet 专属示例:
import torch from torchvision.io import decode_image from torchvision.models import regnet_y_8gf, RegNet_Y_8GF_Weights # Step 1: 用 DEFAULT 权重(即 IMAGENET1K_V2)实例化模型 weights = RegNet_Y_8GF_Weights.DEFAULT model = regnet_y_8gf(weights=weights) model.eval() # 切换 BN 到评估模式 # Step 2: 初始化该权重对应的推理预处理(含 resize 到 232、crop 到 224 等) preprocess = weights.transforms() # Step 3: 读取并预处理图片(以仓库内的测试图片为例) img = decode_image("test/assets/encode_jpeg/grace_hopper_517x606.jpg") batch = preprocess(img).unsqueeze(0) # Step 4: 前向推理并输出类别 prediction = model(batch).squeeze(0).softmax(0) class_id = prediction.argmax().item() score = prediction[class_id].item() category_name = weights.meta["categories"][class_id] print(f"{category_name}: {100 * score:.1f}%")关键点说明:
- 类别名列表存放在
weights.meta["categories"](即 ImageNet-1K 的 1000 类),由 _meta.py 中的_IMAGENET_CATEGORIES提供(见 regnet.py 的_COMMON_META); - 传入预训练权重时,
_regnet会自动用len(weights.meta["categories"])覆盖num_classes(见 regnet.py),因此无需手动指定; - 若加载权重失败或哈希校验不通过,会抛出错误,因为
_regnet使用weights.get_state_dict(progress=progress, check_hash=True)校验下载文件完整性(见 regnet.py); - 权重默认下载到
TORCH_HOME指定的缓存目录,可参考 models.rst 的说明; - 显式传入
weights=None或不传weights时,得到随机初始化模型;旧版pretrained=True写法已被弃用(见 models.rst)。
指定不同权重版本
from torchvision.models import regnet_y_16gf, RegNet_Y_16GF_Weights # 显式指定版本(枚举或字符串均可) model_v2 = regnet_y_16gf(weights=RegNet_Y_16GF_Weights.IMAGENET1K_V2) model_swag = regnet_y_16gf(weights="IMAGENET1K_SWAG_E2E_V1") # 字符串形式等价 assert regnet_y_16gf(weights="IMAGENET1K_V1") is not None选型建议:追求最高精度且算力充足时优先IMAGENET1K_SWAG_E2E_V1;在 224 输入尺寸下获得高精度则用IMAGENET1K_SWAG_LINEAR_V1;常规场景直接用DEFAULT即可。
加载不带预训练权重的模型
import torch from torchvision.models import regnet_x_400mf model = regnet_x_400mf(weights=None) # 随机初始化,1000 类 model_finetune = regnet_x_400mf(num_classes=10) # 自定义类别数 x = torch.rand(1, 3, 224, 224) print(model(x).shape) # torch.Size([1, 1000])从零训练:官方训练配方
仓库在 references/classification 提供了可复现 ImageNet-1K 精度的训练脚本(入口为train.py),README.md 中按模型规模给出三组 RegNet 专用命令:
Small 模型(regnet_x_400mf、regnet_x_800mf、regnet_x_1_6gf、regnet_y_400mf、regnet_y_800mf、regnet_y_1_6gf):
torchrun --nproc_per_node=8 train.py\ --model $MODEL --epochs 100 --batch-size 128 --wd 0.00005 --lr=0.8\ --lr-scheduler=cosineannealinglr --lr-warmup-method=linear\ --lr-warmup-epochs=5 --lr-warmup-decay=0.1注意:
regnet_y_400mf需要把学习率改为 0.4 才能复现论文的 Acc@1。
Medium 模型(regnet_x_3_2gf、regnet_x_8gf、regnet_x_16gf、regnet_y_3_2gf、regnet_y_8gf):
torchrun --nproc_per_node=8 train.py\ --model $MODEL --epochs 100 --batch-size 64 --wd 0.00005 --lr=0.4\ --lr-scheduler=cosineannealinglr --lr-warmup-method=linear\ --lr-warmup-epochs=5 --lr-warmup-decay=0.1Large 模型(regnet_x_32gf、regnet_y_16gf、regnet_y_32gf):
torchrun --nproc_per_node=8 train.py\ --model $MODEL --epochs 100 --batch-size 32 --wd 0.00005 --lr=0.2\ --lr-scheduler=cosineannealinglr --lr-warmup-method=linear\ --lr-warmup-epochs=5 --lr-warmup-decay=0.1三组配方遵循同一规律:模型越大,batch-size 与学习率越小(128/0.8 → 64/0.4 → 32/0.2),权重衰减统一为0.00005,均使用 100 epochs、余弦退火调度与 5 epochs 线性 warmup。V2 权重之所以精度显著高于 V1,正是因为后者使用了改进的新版训练配方(含 FixRes 等策略)。SWAG 系权重的复现方式见_COMMON_SWAG_META中记录的迁移学习方案(见 regnet.py)。
测试验证
当前仓库通过以下方式保证 RegNet 实现的正确性:
- test/test_models.py 将 15 个 RegNet 构建器纳入模型清单,配合
test/expect/目录下的ModelTester.test_regnet_*_expect.pkl期望文件做前向输出对比验证; - test/test_extended_models.py 在扩展模型批量测试中显式排除
regnet_y_128gf(因其规模过大),其余变体均参与实例化与推理验证; BlockParams.from_init_params内置参数合法性校验,非法组合直接抛ValueError,从源头杜绝了无法整除/宽度失配的配置。
小结
RegNet 是"参数即架构"设计哲学在 TorchVision 中的完整落地:开发者只需给出depth / w_0 / w_a / w_m / group_width / se_ratio六个超参数,即可由 BlockParams 程序化推导出整个网络。配合多版本预训练权重(V1 / V2 / SWAG)、自动化的weights.transforms()预处理与 references/classification 的复现配方,RegNetX / RegNetY 既是精度导向任务(SWAG_E2E 可达 88.2% Top-1)的有力候选,也是算力受限场景(400MF 级约 0.4 GFLOPs)下高效基线模型的优选。
更深入的实现细节可继续阅读:
- 模型源码:torchvision/models/regnet.py
- 官方文档:docs/source/models/regnet.rst
- 模型总览:docs/source/models.rst
- 训练配方:references/classification/README.md
- 权重期望值:test/expect
【免费下载链接】visionDatasets, Transforms and Models specific to Computer Vision项目地址: https://gitcode.com/gh_mirrors/vi/vision
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考