CNN 实战:用 ResNet 做图像分类
经验驱动。CNN 的基本前向我用纯 numpy 手搓跑通了(真实 shape 在下面);再讲 ResNet 怎么在这个基础上”加深不退化”。完整 ResNet 训练需要 torch + GPU,本机未装 torch,那部分给出规范实现并诚实标注。
CNN 在算什么(先跑通最小单元)
CNN 本质是一连串”卷积提特征 → 激活 → 池化降维 → 展平 → 全连接分类”。我用一个 8×8×3 的图,手搓一个最小 CNN 前向,看每个阶段 shape 怎么变:
1 | conv = conv2d(img, w, b) # 8x8x3 -> 6x6x2 (2 个 3x3 卷积核) |
真跑结果:
1 | 输入图 shape: (8, 8, 3) |
这证明卷积 → 池化 → 全连接这条链路数学上是通的。
ResNet 解决了什么问题
上面这个太浅,分类效果有限。堆深一点(20、50 层)按理说更强,但朴素深 CNN 会出现退化:层数多了训练误差反而上升。ResNet 的解法是残差连接(skip connection):
1 | # 残差块:输出 = F(x) + x,让网络学"残差"而非整层映射 |
F(x)+x 保证至少不比浅层差(恒等映射永可达),于是能安全地堆到 50/101/152 层。ImageNet 上 ResNet-50 至今仍是很多视觉任务的 backbone。
规范的 ResNet-50 训练骨架(torch,待 GPU 环境跑)
1 | import torch, torch.nn as nn |
踩坑实录
- 卷积输出尺寸算错:
out = (in - k + 2p)/s + 1,padding 没配好就 shape 对不上,numpy 手搓时最容易暴露。 - 通道数对不齐:卷积核的
C_in必须等于输入通道,多分支合并时尤其要检查。 - 池化把空间压没:连续大 stride 池化会让特征图变 0 维,展平直接崩。
- 真训练要 torch/GPU:上面 numpy 只证前向;ResNet-50 全量训练得在 GPU 上跑,本机未装 torch,留待真环境。
小结
CNN 的最小前向用 numpy 就能跑通(卷积→激活→池化→分类,真实 shape 已验证);ResNet 在这个基础上加残差连接解决”深了反而退化”的难题,是视觉 backbone 的基石。面试聊 CNN,能讲清”卷积在提什么、ResNet 为什么能深”,比说”我用过 ResNet”更有料。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 河岳日星的博客!


