CNN 网络架构的设计
深入探索CNN架构设计的演进历程,从手工设计到网络架构搜索(NAS),理解RegNet的设计空间优化方法

展开文章目录
- 1. AnyNet:系统化的网络设计空间
- 1.1 网络架构组成
- 1.2 ResNeXt块的参数化设计
- 1.3 AnyNet代码实现
- 2. 网络设计空间的分布和参数分析
- 2.1 设计空间复杂度问题
- 2.2 NDS方法的核心假设
- 2.3 累积分布函数(CDF)分析
- 2.4 渐进式约束实验
- 2.5 CNN架构设计原则
- 3. RegNet:规则化的网络设计
- 3.1 RegNet设计理念
- 3.2 网络宽度的线性增长模型
- 3.3 RegNetX32实现
- 3.4 RegNetX32参数分析
- 3.5 RegNetY:注意力增强版本
- 4. 模型训练与性能评估
- 4.1 训练配置
- 4.2 训练结果分析
- 5. 总结与展望
- 5.1 CNN架构设计的发展历程
- 5.2 核心贡献与设计原则
- 5.3 技术影响与未来展望
- 参考资料
1. AnyNet:系统化的网络设计空间
1.1 网络架构组成

AnyNet架构详解
茎 (Stem) 的功能与设计:
设计细节:
- 使用步幅为2的3×3卷积层实现下采样
- 包含批量归一化层提高训练稳定性
- 遵循深度CNN早期快速降维的标准实践
主体 (Body) 的多阶段设计:
设计原则:
- 每阶段空间分辨率减半 (面积减为1/4)
- 逐步增加特征通道数
- 使用ResNeXt块作为基本构建单元
- 第一个块负责维度变换,后续块进行特征精炼
头 (Head) 的标准化设计:
适应性设计:
- 可根据具体任务调整 (分类、检测、分割)
- 标准化的接口便于模块化设计
- 支持不同的输出维度需求
1.2 ResNeXt块的参数化设计
ResNeXt参数详解
瓶颈比率 的作用机制:
当输出通道数为 时,中间通道数为 :
分组卷积组数 的权衡:
AnyNet的超参数空间:
1.3 AnyNet代码实现
from dataclasses import dataclass
import torch.nn as nn
from torch import Tensor
from ResNet import ResNeXtBlock
@dataclass
class StageConfig:
"""网络主体中,每个 Stage 的配置"""
depth: int # 块数量
groups: int # 分组卷积块的组数
out_channels: int # 输出通道数
bottleneck_ratio: int # 瓶颈比率
class AnyNet(nn.Module):
def __init__(self, in_channels: int, stem_out_channels: int, num_classes: int, arch_params: list[StageConfig]):
"""
:param in_channels: 输入数据的通道数
:param stem_out_channels: 网络 stem 部分的输出通道数
:param num_classes: 分类任务的类别数
:param arch_params: 网络主体的架构参数列表
"""
super().__init__()
self.stem = self._create_stem(in_channels, stem_out_channels) # 创建 Stem
self.body = nn.Sequential() # 创建 Body
next_stage_in_channels = stem_out_channels
for idx, stage_config in enumerate(arch_params):
self.body.append(
self._create_stage(next_stage_in_channels, stage_config.out_channels, depth=stage_config.depth,
groups=stage_config.groups, bottleneck_ratio=stage_config.bottleneck_ratio)
)
next_stage_in_channels = stage_config.out_channels
self.head = self._create_head(next_stage_in_channels, num_classes) # 创建 Head(分类头)
self._initialize_weights()
@classmethod
def _create_stem(cls, in_channels: int, out_channels: int) -> nn.Sequential:
stem = nn.Sequential(nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=2, padding=1, bias=False),
nn.BatchNorm2d(out_channels), nn.ReLU(inplace=True))
return stem
@classmethod
def _create_stage(cls, in_channels: int, out_channels: int, depth: int, groups: int,
bottleneck_ratio: int) -> nn.Sequential:
"""
创建由多个 ResNeXtBlock 块构成的 Stage
:param in_channels: 输入通道数
:param out_channels: 输出通道数
:param depth: 当前 Stage 的 ResNeXtBlock 块数
:param groups: 分组卷积的组数
:param bottleneck_ratio: 瓶颈比率
"""
stage = nn.Sequential()
stage.append( # 第一个块
ResNeXtBlock(in_channels, out_channels, stride=2, groups=groups, bottleneck_ratio=bottleneck_ratio)
)
for _ in range(1, depth):
stage.append( # 剩余的块
ResNeXtBlock(out_channels, out_channels, stride=1, groups=groups, bottleneck_ratio=bottleneck_ratio)
)
return stage
@classmethod
def _create_head(cls, in_channels: int, num_classes: int) -> nn.Sequential:
head = nn.Sequential(nn.AdaptiveAvgPool2d((1, 1)), nn.Flatten(), nn.Linear(in_channels, num_classes))
return head
def _initialize_weights(self):
for m in self.modules():
if isinstance(m, nn.Conv2d):
nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
elif isinstance(m, nn.BatchNorm2d):
nn.init.constant_(m.weight, 1)
nn.init.constant_(m.bias, 0)
def forward(self, x: Tensor) -> Tensor:
"""
:param x: 形状为 [B, C, H, W]
:return: 形状为 [B, num_classes]
"""
x = self.stem(x) # Stem
x = self.body(x) # Body
x = self.head(x) # Head
return x
查看AnyNet模型结构分析
if __name__ == "__main__":
from torchinfo import summary
params = [
StageConfig(depth=3, groups=1, out_channels=256, bottleneck_ratio=4),
StageConfig(depth=4, groups=1, out_channels=512, bottleneck_ratio=4),
StageConfig(depth=6, groups=1, out_channels=1024, bottleneck_ratio=4),
StageConfig(depth=3, groups=1, out_channels=2048, bottleneck_ratio=4),
]
model = AnyNet(in_channels=3, stem_out_channels=64, num_classes=1000, arch_params=params)
summary(model, input_size=(1, 3, 224, 224))===============================================================================================
Layer (type:depth-idx) Output Shape Param #
===============================================================================================
AnyNet [1, 1000] --
├─Sequential: 1-1 [1, 64, 112, 112] --
│ └─Conv2d: 2-1 [1, 64, 112, 112] 1,728
│ └─BatchNorm2d: 2-2 [1, 64, 112, 112] 128
│ └─ReLU: 2-3 [1, 64, 112, 112] --
├─Sequential: 1-2 [1, 2048, 7, 7] --
│ └─Sequential: 2-4 [1, 256, 56, 56] --
│ │ └─ResNeXtBlock: 3-1 [1, 256, 56, 56] 74,112
│ │ └─ResNeXtBlock: 3-2 [1, 256, 56, 56] 70,400
│ │ └─ResNeXtBlock: 3-3 [1, 256, 56, 56] 70,400
│ └─Sequential: 2-5 [1, 512, 28, 28] --
│ │ └─ResNeXtBlock: 3-4 [1, 512, 28, 28] 377,856
│ │ └─ResNeXtBlock: 3-5 [1, 512, 28, 28] 280,064
│ │ └─ResNeXtBlock: 3-6 [1, 512, 28, 28] 280,064
│ │ └─ResNeXtBlock: 3-7 [1, 512, 28, 28] 280,064
│ └─Sequential: 2-6 [1, 1024, 14, 14] --
│ │ └─ResNeXtBlock: 3-8 [1, 1024, 14, 14] 1,509,376
│ │ └─ResNeXtBlock: 3-9 [1, 1024, 14, 14] 1,117,184
│ │ └─ResNeXtBlock: 3-10 [1, 1024, 14, 14] 1,117,184
│ │ └─ResNeXtBlock: 3-11 [1, 1024, 14, 14] 1,117,184
│ │ └─ResNeXtBlock: 3-12 [1, 1024, 14, 14] 1,117,184
│ │ └─ResNeXtBlock: 3-13 [1, 1024, 14, 14] 1,117,184
│ └─Sequential: 2-7 [1, 2048, 7, 7] --
│ │ └─ResNeXtBlock: 3-14 [1, 2048, 7, 7] 6,033,408
│ │ └─ResNeXtBlock: 3-15 [1, 2048, 7, 7] 4,462,592
│ │ └─ResNeXtBlock: 3-16 [1, 2048, 7, 7] 4,462,592
├─Sequential: 1-3 [1, 1000] --
│ └─AdaptiveAvgPool2d: 2-8 [1, 2048, 1, 1] --
│ └─Flatten: 2-9 [1, 2048] --
│ └─Linear: 2-10 [1, 1000] 2,049,000
===============================================================================================
Total params: 25,537,704
Trainable params: 25,537,704
Non-trainable params: 0
Total mult-adds (Units.GIGABYTES): 4.03
===============================================================================================
Input size (MB): 0.60
Forward/backward pass size (MB): 181.04
Params size (MB): 102.15
Estimated Total Size (MB): 283.80
===============================================================================================2. 网络设计空间的分布和参数分析
2.1 设计空间复杂度问题
2.2 NDS方法的核心假设
2.3 累积分布函数(CDF)分析
CDF分析方法
CDF的数学表示:
从设计空间分布 中采样 个网络,错误率为 :
其中 为指示函数:
- 当 时,
- 当 时,
CDF曲线的解读规则:
网络采样与评估:
2.4 渐进式约束实验

NDS方法通过逐步引入参数约束,比较约束前后的CDF曲线变化来确定设计原则的重要性:
实验阶段
AnyNetXA → AnyNetXB:统一瓶颈比率
AnyNetXB → AnyNetXC:统一分组卷积组数
AnyNetXC:通道数变化模式比较
AnyNetXD:阶段深度变化模式
2.5 CNN架构设计原则
3. RegNet:规则化的网络设计
3.1 RegNet设计理念
3.2 网络宽度的线性增长模型
线性增长模型
线性增长的理论基础:
RegNetX系列网络:
RegNet vs 传统设计:
| 方面 | 传统手工设计 | NAS方法 | RegNet方法 |
|---|---|---|---|
| 设计复杂度 | 高 | 极高 | 中等 |
| 计算成本 | 低 | 极高 | 中等 |
| 通用性 | 低 | 低 | 高 |
| 可解释性 | 中等 | 低 | 高 |
| 设计洞察 | 有限 | 有限 | 丰富 |
3.3 RegNetX32实现
class RegNetX32(AnyNet):
def __init__(self, in_channels, num_classes: int):
super().__init__(
in_channels=in_channels, stem_out_channels=32, num_classes=num_classes,
arch_params=[
StageConfig(depth=4, groups=16, out_channels=32, bottleneck_ratio=1),
StageConfig(depth=6, groups=16, out_channels=80, bottleneck_ratio=1)
]
)
查看RegNetX32模型结构分析
if __name__ == "__main__":
from torchinfo import summary
model = RegNetX32(in_channels=1, num_classes=10)
summary(model, input_size=(1, 1, 96, 96))===============================================================================================
Layer (type:depth-idx) Output Shape Param #
===============================================================================================
RegNetX32 [1, 10] --
├─Sequential: 1-1 [1, 32, 48, 48] --
│ └─Conv2d: 2-1 [1, 32, 48, 48] 288
│ └─BatchNorm2d: 2-2 [1, 32, 48, 48] 64
│ └─ReLU: 2-3 [1, 32, 48, 48] --
├─Sequential: 1-2 [1, 80, 12, 12] --
│ └─Sequential: 2-4 [1, 32, 24, 24] --
│ │ └─ResNeXtBlock: 3-1 [1, 32, 24, 24] 2,304
│ │ └─ResNeXtBlock: 3-2 [1, 32, 24, 24] 1,280
│ │ └─ResNeXtBlock: 3-3 [1, 32, 24, 24] 1,280
│ │ └─ResNeXtBlock: 3-4 [1, 32, 24, 24] 1,280
│ └─Sequential: 2-5 [1, 80, 12, 12] --
│ │ └─ResNeXtBlock: 3-5 [1, 80, 12, 12] 7,824
│ │ └─ResNeXtBlock: 3-6 [1, 80, 12, 12] 7,520
│ │ └─ResNeXtBlock: 3-7 [1, 80, 12, 12] 7,520
│ │ └─ResNeXtBlock: 3-8 [1, 80, 12, 12] 7,520
│ │ └─ResNeXtBlock: 3-9 [1, 80, 12, 12] 7,520
│ │ └─ResNeXtBlock: 3-10 [1, 80, 12, 12] 7,520
├─Sequential: 1-3 [1, 10] --
│ └─AdaptiveAvgPool2d: 2-6 [1, 80, 1, 1] --
│ └─Flatten: 2-7 [1, 80] --
│ └─Linear: 2-8 [1, 10] 810
===============================================================================================
Total params: 52,730
Trainable params: 52,730
Non-trainable params: 0
Total mult-adds (Units.MEGABYTES): 10.19
===============================================================================================
Input size (MB): 0.04
Forward/backward pass size (MB): 6.49
Params size (MB): 0.21
Estimated Total Size (MB): 6.74
===============================================================================================3.4 RegNetX32参数分析
3.5 RegNetY:注意力增强版本
RegNetY特性
挤压-激励(SE)模块:
RegNetX vs RegNetY性能对比:
| 指标 | RegNetX | RegNetY | 提升 |
|---|---|---|---|
| 参数量 | 基准 | +5~10% | 小幅增加 |
| 计算量 | 基准 | +2~5% | 微量增加 |
| 准确率 | 基准 | +1~3% | 显著提升 |
| 推理速度 | 基准 | -2~5% | 轻微下降 |
RegNetX vs RegNetY选择指南:
4. 模型训练与性能评估
4.1 训练配置
if __name__ == "__main__":
import torch
from torch import optim
from training_tools import fashionMNIST_loader, Trainer
BATCH_SIZE = 128
EPOCHS_NUM = 10
LEARNING_RATE = 0.05
model = RegNetX32(in_channels=1, num_classes=10)
train_loader, test_loader = fashionMNIST_loader(BATCH_SIZE, resize=96)
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), LEARNING_RATE)
platform = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
with Trainer(model, train_loader, test_loader, criterion, optimizer, platform) as trainer:
trainer.train(EPOCHS_NUM)
4.2 训练结果分析
查看RegNetX32完整训练过程
第 001/10 轮,训练损失:0.9418,训练精度:66.48%,测试损失:4.7452,测试精度:21.97%
第 002/10 轮,训练损失:0.4853,训练精度:82.67%,测试损失:1.0351,测试精度:65.65%
第 003/10 轮,训练损失:0.3922,训练精度:86.08%,测试损失:1.5781,测试精度:56.69%
第 004/10 轮,训练损失:0.3465,训练精度:87.70%,测试损失:1.8860,测试精度:55.66%
第 005/10 轮,训练损失:0.3207,训练精度:88.58%,测试损失:0.5745,测试精度:79.57%
第 006/10 轮,训练损失:0.3003,训练精度:89.22%,测试损失:0.3773,测试精度:87.31%
第 007/10 轮,训练损失:0.2861,训练精度:89.77%,测试损失:0.6627,测试精度:78.40%
第 008/10 轮,训练损失:0.2742,训练精度:90.25%,测试损失:0.3845,测试精度:86.95%
第 009/10 轮,训练损失:0.2613,训练精度:90.56%,测试损失:0.3343,测试精度:88.11%
第 010/10 轮,训练损失:0.2536,训练精度:90.89%,测试损失:0.3222,测试精度:88.16%
性能分析
RegNetX32训练表现:
与其他CNN架构的对比:
| 模型 | 参数量 | 最佳测试精度 | 训练稳定性 | 设计复杂度 |
|---|---|---|---|---|
| LeNet | ~60K | ~85% | 高 | 低 |
| AlexNet | ~60M | ~88% | 中 | 中 |
| VGG | ~138M | ~90% | 中 | 中 |
| ResNet | ~25M | ~93% | 高 | 高 |
| RegNetX32 | 53K | 88.16% | 高 | 中 |
RegNet的应用价值:
5. 总结与展望
5.1 CNN架构设计的发展历程
5.2 核心贡献与设计原则
5.3 技术影响与未来展望
参考资料
如果这篇记录对你有帮助,可以留下一句回应。

DISCUSSION
讨论与回应
欢迎补充细节、指出问题,或分享与这篇文章有关的经验。
昵称与邮箱为必填项,邮箱仅用于头像和回复通知,不会公开。网址可以留空。