第 J8 周:ResNeXt-50 算法解析

🔗 声明

  • 本文为「365 天深度学习训练营」内部学习记录。
  • 本文参考 K 同学啊课程内容完成,仅用于个人学习与交流。
  • 猴痘病识别数据集仅用于学习交流,请勿对外分享数据集。
  • 本篇为个人在 J8 关卡上的实践记录。
  • 论文: Aggregated Residual Transformations for Deep Neural Networks(ResNeXt,CVPR 2017)

第 J8 周:ResNeXt-50 算法解析

ResNeXt(Residual Networks with Aggregated Transformations)由 Facebook AI Research 在 2016 年提出,2017 年发表于 CVPR。它沿用 ResNet 的残差相加,把 Inception 那种「多路变换」收成同构分支 ,用分组卷积一次写完,再用 基数(cardinality) 控制并行路径数。本周对照 ResNet50V2 与 DenseNet,并用 ResNeXt-50(32×4d)完成猴痘二分类。

📌 本周任务

  1. 阅读 ResNeXt 论文,弄清作者为什么要加「基数」这一维
  2. 对比此前的 ResNet50V2 、DenseNet
  3. 用 ResNeXt-50 完成猴痘病识别

🏡 我的环境

  • 语言:Python 3.10
  • 工具:脚本 train_j8.py
  • 框架:PyTorch 2.5.1+cu121,GPU:RTX 4060 Ti
  • 数据集:与 T4/J5/J6 同源 data → ../t4/45-data(两类:Monkeypox / Others,共 2142 张)

训练设定(与 J5/J6 对齐):

项 设定
划分 8:2,seed=42
输入 224×224,ImageNet 归一化;训练水平翻转
优化 AdamW,lr=1e-4,batch=16,epochs=10
初始化 随机初始化(不加载预训练)
结构 ResNeXt-50 32×4d (cardinality=32,base_width=4,层数 [3,4,6,3])

一、作者要解决什么问题?

加深、加宽都能涨点,但手工设计每一条分支(Inception 那种)又难又贵。论文的策略是:在相近参数量和计算量下,用一个新维度换精度------基数 C:一个 block 里相同变换路径的条数。

容量可以沿三轴扩:

维度 含义 谁在用
深度 Depth 堆更多层 ResNet、DenseNet
宽度 Width 加通道 Wide ResNet
基数 Cardinality 加并行同构路径 ResNeXt

聚合方式:各路径做变换后 求和 (实现上就是 groups=C 的 3×3),再和恒等映射残差相加。


二、一个 block:ResNet 与 ResNeXt

以输入 256 通道的 bottleneck 为例。

ResNet: 1×1 把 256 压到 64(4 倍),3×3 处理这 64 通道,再 1×1 拉回 256,与输入相加。

ResNeXt-50 32×4d: 中间宽度按

\\text{width} = \\text{planes} \\times \\frac{\\text{base_width}}{64} \\times C

第一阶段 planes=64、C=32、base_width=4 时,width = 128。也就是 32 组、每组 4 通道(课程里说的「压缩 64 倍到 4 通道」),分组 3×3 各自卷积,组间不混通道,最后 1×1 还原到 256 再残差相加。

层数配置与 ResNet-50 相同:[3, 4, 6, 3],所以叫 ResNeXt-50;101 层则把第三阶段从 6 改成 23。


三、分组卷积在省什么?

普通卷积里每个核看全部输入通道。分组卷积把通道切开,每个核只看本组通道,输出再在通道维拼回去。组数等于基数时,3×3 的参数大约按组数下降,省下来的预算可以拿去增加路径数,而不是把单路做得更宽。

论文在 ImageNet 上的结论:固定复杂度时,加大基数往往比单纯加宽或加深更划算。这是大规模数据上的结论;小数据从零短训不一定复现这个排序(见第六节)。


四、和 ResNet50V2、DenseNet 怎么比

三者都在解决「深层怎么把特征传下去」,接法不同。

ResNet50V2(J2) DenseNet121(J3) ResNeXt-50(本周)
跨层方式 残差 相加,且相加后不再 ReLU(预激活) 块内全层 concat 残差 相加(后激活,同 ResNet V1)
块内变换 单路 bottleneck 每层只长出 (k) 个新通道 C 条同构路径,用分组卷积实现
设计旋钮 深度、预激活顺序 growth rate、压缩率 (\theta) cardinality / base_width
参数量级 ~2351 万(3 类头) ~696 万 ~2298 万(2 类头;1000 类约 2500 万)
当时任务 膝关节三分类,最优 Test ACC 89.2% 膝关节三分类,88.9% 猴痘二分类,见下

结构上可以记三句话:

  • ResNet50V2 关心恒等路径是否被 ReLU 截断:BN-ReLU-Conv 放在支路里,相加后直接输出。
  • DenseNet 不相加,把前面所有层在通道维接起来,用很少的新增通道换特征重用,所以更轻。
  • ResNeXt 不改残差公式,只把 (F(x)) 从「一条宽卷积」换成「多条窄的分组卷积再聚合」。它更接近 ResNet,和 DenseNet 的 concat 不是一条路线。

J2/J3 的准确率来自膝关节数据,不能和本周猴痘数字直接比高低。同协议、同数据的参照是 J5 的 SE-DenseNet121(79.0%)和 J6 的 Inception v1(87.2%)。


五、PyTorch 实现要点

中间宽度和分组 3×3:

python 复制代码
width = int(planes * (base_width / 64.0)) * cardinality
self.conv2 = nn.Conv2d(
    width, width, kernel_size=3, stride=stride, padding=1,
    groups=cardinality, bias=False,
)

前向仍是标准 bottleneck,最后残差相加:

python 复制代码
out = self.relu(self.bn1(self.conv1(x)))
out = self.relu(self.bn2(self.conv2(out)))
out = self.bn3(self.conv3(out))
if self.downsample is not None:
    identity = self.downsample(x)
return self.relu(out + identity)

工厂函数给出 50 / 101:

python 复制代码
resnext_config = {
    "ResNeXt50": {"layers": [3, 4, 6, 3], "cardinality": 32, "base_width": 4},
    "ResNeXt101_32x4d": {"layers": [3, 4, 23, 3], "cardinality": 32, "base_width": 4},
    "ResNeXt101_64x4d": {"layers": [3, 4, 23, 3], "cardinality": 64, "base_width": 4},
}

形状自检(1000 类头):输入 [2, 3, 224, 224] → 输出 [2, 1000]。本周分类头改为 2 类。


六、训练日志

复制代码
device: cuda
classes: ['Monkeypox', 'Others'] n= 2142
ResNeXt50 params=22,984,002

Epoch: 1, Train_acc:59.9%, Train_loss:0.728, Test_acc:60.4%, Test_loss:0.812, Lr:1.00E-04
Epoch: 2, Train_acc:64.2%, Train_loss:0.650, Test_acc:60.1%, Test_loss:0.790, Lr:1.00E-04
Epoch: 3, Train_acc:66.1%, Train_loss:0.650, Test_acc:66.4%, Test_loss:0.597, Lr:1.00E-04
Epoch: 4, Train_acc:67.7%, Train_loss:0.605, Test_acc:63.6%, Test_loss:0.648, Lr:1.00E-04
Epoch: 5, Train_acc:67.5%, Train_loss:0.606, Test_acc:61.1%, Test_loss:0.669, Lr:1.00E-04
Epoch: 6, Train_acc:70.1%, Train_loss:0.572, Test_acc:62.9%, Test_loss:0.711, Lr:1.00E-04
Epoch: 7, Train_acc:71.2%, Train_loss:0.556, Test_acc:71.6%, Test_loss:0.540, Lr:1.00E-04
Epoch: 8, Train_acc:73.4%, Train_loss:0.532, Test_acc:74.1%, Test_loss:0.532, Lr:1.00E-04
Epoch: 9, Train_acc:76.9%, Train_loss:0.492, Test_acc:70.2%, Test_loss:0.572, Lr:1.00E-04
Epoch:10, Train_acc:77.8%, Train_loss:0.480, Test_acc:70.9%, Test_loss:0.588, Lr:1.00E-04
ResNeXt50 best_test_acc=0.7413

结果解读

项 数值
参数量 22,984,002(2 类头)
最优 Test ACC 74.1%(第 8 轮)
最优 Test Loss 0.532

同数据、同超参:

模型 参数量 最优 Test ACC
SE-DenseNet121(J5) ~699 万 79.0%
Inception v1(J6) ~598 万 87.2%
ResNeXt-50 32×4d(J8) ~2298 万 74.1%

训练 ACC 还在爬(第 10 轮 77.8%),测试在第 8 轮见顶后回落。模型比 J5/J6 大一个数量级,2142 张图、10 个 epoch、从零训练,容量用不满,基数带来的收益在这个设定里体现不出来。这和论文「同等复杂度下 ResNeXt 优于 ResNet」并不矛盾:那边是 ImageNet 规模和充分训练。

复现命令:

bash 复制代码
/home/sqc/micromamba/envs/torch2.1-cuda12.1/bin/python train_j8.py

权重:best_model_resnext50.pth;明细:j8_result.txt / j8_result.json。


七、个人小结

  1. 基数 是第三条扩容轴:不手写异构分支,用 groups=cardinality 得到 C 条同构变换,再求和并残差相加。
  2. 和 ResNet50V2:残差公式同类,但 ResNeXt 仍是后激活 bottleneck;V2 的预激活解决的是恒等路径被截断,ResNeXt 解决的是 (F(x)) 怎么拆成多路。
  3. 和 DenseNet:一个相加、一个 concat。DenseNet 用特征重用换更少参数;ResNeXt 参数量仍在 ResNet-50 量级。
  4. 实验 :猴痘二分类最优 Test ACC 74.1%。小数据短训下它不如更轻的 Inception v1 / SE-DenseNet;要看见论文里的基数优势,需要更长训练或预训练微调。
相关推荐
哈__1 小时前
260+异构同步链路:DDL语法自动翻译在大规模数据同步中的实现原理
人工智能·自然语言处理·机器翻译
虎鲸不是鱼1 小时前
【虎鲸进化论 13】CI/CD:它在服务器上铺了条流水线
服务器·人工智能·ci/cd·大模型·自进化agent
voipmaker1 小时前
融合通信调度录音的困局:基于 MediaX 网关实现对讲语音 AI 事件萃取
人工智能·ai·音视频·语音识别·实时音视频·信息与通信·iot
明志数科1 小时前
机器人数据采集行业供给侧出清:重资产模式的结构性约束与质量工程转向
大数据·人工智能
龙亘川2 小时前
电子签章服务与核验业务建模:从在线签署、可信核验到归档追溯的全流程闭环
大数据·人工智能·智慧城市·开源软件
杨杨杨大侠8 小时前
RAG、记忆、上下文,这几个东西到底怎么串起来?
人工智能·agent
system_error_x9 小时前
MCP协议开发实战:从零搭建AI Agent工具链
人工智能
Sayai9 小时前
ComfyUI+混元视频实战:12G 显存跑 13G 模型,5 分钟出片(国产开源,附模型与工作流)
人工智能·aigc·音视频·comfyui·hunyuanvideo·混元视频
燧机科技SuiJi10 小时前
山体坍塌落石滑坡泥石流监测系统 落石泥石流监控摄像机
大数据·人工智能·深度学习·yolo