模块M02: 计算机视觉基础¶
阶段: Stage 4 - 深度学习 预计学习时间: 3-4小时(理论)+ 3-4小时(实践) 难度: ⭐⭐⭐⭐ 中高等
📚 学习目标¶
完成本模块后,你将能够:
- ✅ 理解卷积神经网络(CNN)的核心原理与架构设计
- ✅ 掌握卷积层、池化层、全连接层的作用与计算过程
- ✅ 熟悉经典CNN架构(LeNet、AlexNet、VGG、ResNet、EfficientNet)
- ✅ 理解目标检测的核心概念(YOLO、Faster R-CNN、DETR)
- ✅ 掌握图像分割技术(U-Net、Mask R-CNN、Segment Anything)
- ✅ 能够使用预训练模型进行迁移学习与模型微调
🎯 核心知识点¶
1. 卷积神经网络 (CNN) 基础¶
1.1 为什么需要 CNN?¶
传统的全连接神经网络在处理图像时存在以下问题:
问题示例:
CNN 的三大优势: 1. 参数共享 (Parameter Sharing): 同一个卷积核在整个图像上滑动 2. 局部连接 (Local Connectivity): 每个神经元只连接局部区域 3. 平移不变性 (Translation Invariance): 对物体位置不敏感
1.2 卷积层 (Convolutional Layer)¶
卷积操作是 CNN 的核心,用于提取图像特征。
数学定义:
参数说明:
- Kernel Size: 卷积核大小(常用 3×3, 5×5, 7×7)
- Stride: 步长(默认1,影响输出尺寸)
- Padding: 填充('SAME'保持尺寸,'VALID'不填充)
- Channels: 输入/输出通道数
输出尺寸计算:
Output_height = (Input_height - Kernel_height + 2 × Padding) / Stride + 1
Output_width = (Input_width - Kernel_width + 2 × Padding) / Stride + 1
示例:
import torch.nn as nn
# 输入: (batch_size, 3, 224, 224)
conv = nn.Conv2d(
in_channels=3, # RGB 3通道
out_channels=64, # 输出64个特征图
kernel_size=3, # 3×3卷积核
stride=1, # 步长1
padding=1 # 填充1(保持尺寸)
)
# 输出: (batch_size, 64, 224, 224)
特征提取层次: - 浅层卷积: 检测边缘、角点、纹理 - 中层卷积: 检测形状、部件(眼睛、轮子) - 深层卷积: 检测复杂对象(人脸、汽车)
可视化:参见 notebooks/stage4/03-cnn-image-classification.ipynb 第1节
1.3 池化层 (Pooling Layer)¶
池化用于降低特征图的空间维度,减少计算量和过拟合。
两种常用池化:
| 池化类型 | 操作 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| Max Pooling | 取区域最大值 | 保留显著特征、鲁棒性强 | 丢失位置信息 | 目标检测、分类 |
| Average Pooling | 取区域平均值 | 平滑特征、保留背景 | 特征不明显 | 全局特征提取 |
示例:
# Max Pooling (2×2窗口,stride=2)
maxpool = nn.MaxPool2d(kernel_size=2, stride=2)
# 输入: (batch, 64, 224, 224)
# 输出: (batch, 64, 112, 112) # 尺寸减半
1.4 批归一化 (Batch Normalization)¶
批归一化加速训练、提高稳定性。
公式:
其中: -μ: 批次均值
- σ²: 批次方差
- γ, β: 可学习参数
- ε: 数值稳定项 (通常1e-5)
优点: - 缓解梯度消失/爆炸 - 允许更大学习率 - 减少对初始化的依赖 - 一定程度的正则化效果
放置位置:
# 推荐顺序: Conv → BN → Activation
conv = nn.Conv2d(3, 64, 3, padding=1)
bn = nn.BatchNorm2d(64)
relu = nn.ReLU()
# 前向传播: x → conv(x) → bn(x) → relu(x)
2. 经典 CNN 架构演进¶
2.1 LeNet-5 (1998)¶
历史意义: 第一个成功的卷积神经网络,用于手写数字识别(MNIST)。
网络结构:
输入(32×32×1)
↓
Conv(5×5, 6) → AvgPool(2×2) → Conv(5×5, 16) → AvgPool(2×2)
↓
FC(120) → FC(84) → FC(10)
参数量: ~60K 特点: 简单、易训练,现代标准看已过时
2.2 AlexNet (2012)¶
历史意义: ImageNet 2012冠军,开启深度学习时代。
关键创新: 1. 使用 ReLU 激活函数(替代Sigmoid/Tanh) 2. 引入 Dropout 正则化(防止过拟合) 3. 使用 数据增强(随机裁剪、翻转) 4. GPU并行训练(双GPU架构)
网络结构:
输入(224×224×3)
↓
Conv(11×11, 96, stride=4) → MaxPool(3×3, stride=2)
↓
Conv(5×5, 256) → MaxPool(3×3, stride=2)
↓
Conv(3×3, 384) → Conv(3×3, 384) → Conv(3×3, 256)
↓
MaxPool(3×3, stride=2) → FC(4096) → Dropout(0.5)
↓
FC(4096) → Dropout(0.5) → FC(1000)
参数量: ~60M ImageNet Top-5错误率: 15.3% (2012年)
2.3 VGG-16/19 (2014)¶
核心思想: "更深" + "小卷积核"(全部用3×3)
为什么用小卷积核? - 2个3×3卷积 = 1个5×5卷积(感受野相同) - 但参数更少:2×(3×3) = 18 < 1×(5×5) = 25 - 更多非线性(2个ReLU vs 1个ReLU)
VGG-16 结构:
输入(224×224×3)
↓
Conv3-64 × 2 → MaxPool
↓
Conv3-128 × 2 → MaxPool
↓
Conv3-256 × 3 → MaxPool
↓
Conv3-512 × 3 → MaxPool
↓
Conv3-512 × 3 → MaxPool
↓
FC(4096) → FC(4096) → FC(1000)
参数量: VGG-16 ~138M, VGG-19 ~144M ImageNet Top-5错误率: 7.3%
缺点: 参数量巨大、训练慢、显存占用高
2.4 ResNet (2015)¶
核心创新: 残差连接 (Residual Connection),解决深层网络退化问题。
残差块 (Residual Block):
输入 x
↓
┌───────┐
│ 恒等 │
└───────┘
↓
┌─────────────┐
│ Conv-BN-ReLU│
│ Conv-BN │
└─────────────┘
↓
x + F(x) ← 残差连接
↓
ReLU
数学表达:
其中F(x) 是残差映射(2-3层卷积)。
为什么有效?
- 如果恒等映射最优,网络只需学习 F(x) = 0
- 梯度可以直接通过快捷连接传播,缓解梯度消失
ResNet家族: | 模型 | 层数 | 参数量 | ImageNet Top-5 错误率 | |------|------|--------|---------------------| | ResNet-18 | 18 | 11.7M | ~10.8% | | ResNet-34 | 34 | 21.8M | ~9.2% | | ResNet-50 | 50 | 25.6M | ~7.1% | | ResNet-101 | 101 | 44.5M | ~6.4% | | ResNet-152 | 152 | 60.2M | ~5.7% |
代码示例:
class ResidualBlock(nn.Module):
def __init__(self, in_channels, out_channels, stride=1):
super().__init__()
self.conv1 = nn.Conv2d(in_channels, out_channels, 3, stride, padding=1)
self.bn1 = nn.BatchNorm2d(out_channels)
self.conv2 = nn.Conv2d(out_channels, out_channels, 3, padding=1)
self.bn2 = nn.BatchNorm2d(out_channels)
# 快捷连接(如果维度不匹配,需要1×1卷积调整)
if stride != 1 or in_channels != out_channels:
self.shortcut = nn.Sequential(
nn.Conv2d(in_channels, out_channels, 1, stride),
nn.BatchNorm2d(out_channels)
)
else:
self.shortcut = nn.Identity()
def forward(self, x):
residual = self.shortcut(x)
out = F.relu(self.bn1(self.conv1(x)))
out = self.bn2(self.conv2(out))
out += residual # 残差连接
return F.relu(out)
2.5 EfficientNet (2019)¶
核心思想: 复合缩放 (Compound Scaling) - 同时调整深度、宽度、分辨率。
传统方法 vs 复合缩放:
传统方法:
- 加深度: ResNet-50 → ResNet-101
- 加宽度: ResNet-50 (width×1.5)
- 加分辨率: 224×224 → 299×299
复合缩放:
depth = α^φ, width = β^φ, resolution = γ^φ
约束: α · β² · γ² ≈ 2
EfficientNet家族: | 模型 | 参数量 | ImageNet Top-1准确率 | 推理速度 | |------|--------|---------------------|---------| | EfficientNet-B0 | 5.3M | 77.1% | 基准 | | EfficientNet-B1 | 7.8M | 79.1% | 1.2× | | EfficientNet-B3 | 12M | 81.6% | 1.8× | | EfficientNet-B7 | 66M | 84.3% | 6.1× |
优势: 在相同计算量下准确率更高,或在相同准确率下速度更快。
3. 目标检测 (Object Detection)¶
目标检测 = 分类 + 定位
输出格式:
[
{"class": "cat", "bbox": [x1, y1, x2, y2], "confidence": 0.95},
{"class": "dog", "bbox": [x3, y3, x4, y4], "confidence": 0.88}
]
3.1 两阶段检测器: Faster R-CNN¶
流程:
优点: 准确率高 缺点: 速度慢(~5 FPS)
3.2 单阶段检测器: YOLO 系列¶
核心思想: 将检测问题转化为回归问题,一次性预测所有边界框。
YOLO v1-v11 演进: | 版本 | 发布年份 | 关键创新 | mAP@0.5 | 速度 | |------|---------|---------|---------|------| | YOLOv1 | 2016 | 单阶段检测 | 63.4% | 45 FPS | | YOLOv3 | 2018 | 多尺度预测 | 57.9% | 30 FPS | | YOLOv5 | 2020 | 工程优化 | 65.8% | 140 FPS | | YOLOv8 | 2023 | Anchor-free | 53.9% | 80 FPS | | YOLOv11 | 2024 | Transformer融合 | 54.7% | 90+ FPS |
YOLOv11 架构:
应用场景: 实时视频检测、自动驾驶、工业质检
3.3 基于Transformer: DETR¶
核心创新: 将目标检测视为 集合预测问题,无需NMS后处理。
架构:
输入图像 → CNN Backbone → Flatten
↓
Transformer Encoder
↓
Transformer Decoder (N个查询向量)
↓
并行预测N个对象(class + bbox)
优点: 端到端训练、无需手工设计anchor 缺点: 训练慢、小目标检测效果一般
4. 图像分割 (Image Segmentation)¶
4.1 语义分割 (Semantic Segmentation)¶
目标: 为每个像素分配类别标签(不区分实例)
经典架构: U-Net
编码器(下采样) 解码器(上采样)
↓ ↑
Conv-Pool ─────跳跃连接───→ UpConv-Concat
↓ ↑
Conv-Pool ─────跳跃连接───→ UpConv-Concat
↓ ↑
Conv-Pool UpConv-Concat
跳跃连接作用: 融合高分辨率浅层特征与高语义深层特征。
应用: 医学影像分割、自动驾驶场景理解
4.2 实例分割 (Instance Segmentation)¶
目标: 区分同类别的不同实例
Mask R-CNN:
输出: 每个实例的类别 + 边界框 + 像素级掩码
4.3 全景分割 (Panoptic Segmentation)¶
目标: 语义分割 + 实例分割的统一
应用: 自动驾驶(需要识别道路、行人、车辆等)
4.4 最新进展: Segment Anything (SAM)¶
核心思想: 零样本分割,输入提示(点/框/文本)即可分割任意对象。
架构:
应用: 交互式标注、视频对象分割
5. 迁移学习 (Transfer Learning)¶
5.1 为什么需要迁移学习?¶
挑战: - 从零训练大型CNN需要百万级标注数据 - 训练时间长(几天到几周) - 计算资源昂贵(多卡GPU)
解决方案: 使用在ImageNet上预训练的模型,迁移到目标任务。
5.2 迁移学习策略¶
策略1: 固定特征提取器(数据量<1000)
# 加载预训练ResNet
model = torchvision.models.resnet50(pretrained=True)
# 冻结所有卷积层
for param in model.parameters():
param.requires_grad = False
# 只训练最后的全连接层
model.fc = nn.Linear(2048, num_classes)
策略2: 微调 (Fine-tuning)(数据量1000-10000)
model = torchvision.models.resnet50(pretrained=True)
# 冻结前几层,微调后几层
for name, param in model.named_parameters():
if "layer4" in name or "fc" in name:
param.requires_grad = True
else:
param.requires_grad = False
策略3: 全网络微调(数据量>10000)
model = torchvision.models.resnet50(pretrained=True)
model.fc = nn.Linear(2048, num_classes)
# 使用较小学习率
optimizer = torch.optim.Adam([
{'params': model.fc.parameters(), 'lr': 1e-3}, # 新层大学习率
{'params': model.layer4.parameters(), 'lr': 1e-4}, # 后层中学习率
{'params': model.layer3.parameters(), 'lr': 1e-5} # 前层小学习率
])
5.3 预训练模型来源¶
PyTorch Hub:
Torchvision Models:
from torchvision import models
resnet50 = models.resnet50(weights=models.ResNet50_Weights.IMAGENET1K_V1)
efficientnet_b0 = models.efficientnet_b0(weights=models.EfficientNet_B0_Weights.IMAGENET1K_V1)
Hugging Face Transformers (Vision Transformer):
🛠️ 实践环节¶
任务1: 手写CNN图像分类器¶
目标: 从零实现一个CNN,在CIFAR-10上达到70%+准确率
关键代码 (notebooks/stage4/03-cnn-image-classification.ipynb 第3节):
class SimpleCNN(nn.Module):
def __init__(self, num_classes=10):
super().__init__()
self.features = nn.Sequential(
nn.Conv2d(3, 32, 3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2, 2),
nn.Conv2d(32, 64, 3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2, 2),
nn.Conv2d(64, 128, 3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2, 2)
)
self.classifier = nn.Sequential(
nn.Flatten(),
nn.Linear(128 * 4 * 4, 256),
nn.ReLU(),
nn.Dropout(0.5),
nn.Linear(256, num_classes)
)
def forward(self, x):
x = self.features(x)
x = self.classifier(x)
return x
任务2: 使用预训练模型进行迁移学习¶
目标: 在自定义数据集上微调ResNet-50,超越从零训练的模型
步骤: 1. 加载预训练ResNet-50 2. 替换最后的全连接层 3. 冻结前80%的层 4. 使用小学习率微调 5. 对比从零训练 vs 迁移学习的收敛速度
预期结果: - 从零训练: 需要50+ epochs达到60%准确率 - 迁移学习: 5 epochs即可达到80%准确率
任务3: 可视化CNN特征图¶
目标: 理解CNN每层学到的特征
可视化内容: - 第1层: 边缘检测器(水平、垂直、对角线) - 第3层: 纹理检测器 - 第5层: 形状检测器 - 最后一层: 高级语义特征
代码:
# 提取中间层特征
activations = {}
def get_activation(name):
def hook(model, input, output):
activations[name] = output.detach()
return hook
model.layer1.register_forward_hook(get_activation('layer1'))
model.layer2.register_forward_hook(get_activation('layer2'))
# 前向传播
_ = model(image)
# 可视化
plt.imshow(activations['layer1'][0, 0].cpu(), cmap='viridis')
📖 扩展阅读¶
经典论文¶
- ImageNet Classification with Deep CNNs (AlexNet, 2012)
- 链接: https://papers.nips.cc/paper/2012/file/c399862d3b9d6b76c8436e924a68c45b-Paper.pdf
-
阅读时间: 1小时
-
Deep Residual Learning for Image Recognition (ResNet, 2015)
- 链接: https://arxiv.org/abs/1512.03385
-
阅读时间: 1.5小时
-
You Only Look Once: Unified, Real-Time Object Detection (YOLOv1, 2016)
- 链接: https://arxiv.org/abs/1506.02640
-
阅读时间: 1小时
-
U-Net: Convolutional Networks for Biomedical Image Segmentation (2015)
- 链接: https://arxiv.org/abs/1505.04597
- 阅读时间: 45分钟
在线资源¶
- CS231n (Stanford): http://cs231n.stanford.edu/
- PyTorch Vision Tutorials: https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html
- Papers with Code (CV排行榜): https://paperswithcode.com/area/computer-vision
实战项目推荐¶
完成本模块后,建议尝试以下项目:
- 🚀 P01: 工业视觉检测 - TensorFlow迁移学习
- 🚀 P02: YOLOv11实时检测 - 双框架实现(推荐)
- 🚀 P04: 自动驾驶图像分割 - U-Net/DeepLab双框架
❓ 常见问题 (FAQ)¶
Q1: CNN 为什么比全连接网络更适合处理图像?¶
A: 三个核心原因: 1. 参数共享: 同一个卷积核在整个图像上复用,减少参数量 2. 局部连接: 利用图像的空间局部性,每个神经元只关注局部区域 3. 平移不变性: 对物体在图像中的位置不敏感
Q2: 如何选择合适的CNN架构?¶
A: 根据应用场景选择: - 移动端/边缘设备: EfficientNet-B0, MobileNetV3 (参数量<10M) - 服务器端高精度: ResNet-101, EfficientNet-B7 (准确率优先) - 实时检测: YOLOv8, YOLOv11 (速度优先) - 通用场景: ResNet-50 (性能与速度平衡)
Q3: 迁移学习什么时候效果好?¶
A: 满足以下条件效果最佳: 1. 数据量小: <10,000张图像 2. 任务相似: 目标任务与ImageNet类似(都是自然图像) 3. 类别相关: 如ImageNet包含"狗"类别,迁移到狗种识别效果好
不适用场景: - 医学影像(X光、CT): 与自然图像差异大 - 卫星遥感图像: 与ImageNet差异大 - 建议: 寻找领域内的预训练模型(如ChexNet for医疗)
Q4: 如何调试CNN模型?¶
A: 5步排查法:
1. 过拟合单个batch: 确保模型有足够容量
2. 检查梯度: 使用torch.autograd.grad_check
3. 可视化特征图: 检查是否学到有意义的特征
4. 学习率调优: 使用学习率查找器(LR Finder)
5. 数据增强: 防止过拟合
Q5: 为什么模型在验证集上准确率很低?¶
A: 可能原因: 1. 过拟合: 训练集准确率高但验证集低 → 增加Dropout/正则化 2. 欠拟合: 训练集准确率也低 → 增加模型容量/训练更久 3. 数据泄露: 验证集分布与训练集不同 → 检查数据划分 4. 学习率太大: Loss震荡不收敛 → 降低学习率
✅ 学习检查清单¶
完成本模块后,你应该能够:
- 解释卷积操作的数学原理并手动计算输出尺寸
- 说出至少3个经典CNN架构及其关键创新点
- 实现一个包含卷积层、池化层、BN层的简单CNN
- 使用预训练ResNet-50进行迁移学习
- 可视化CNN不同层的特征图
- 解释残差连接为什么能解决梯度消失问题
- 区分语义分割、实例分割、全景分割
- 比较YOLO与Faster R-CNN的优缺点
⏭️ 下一步¶
完成本模块后,你可以:
- 继续学习: 模块M03: 自然语言处理基础
- 实战项目: 从项目列表中选择感兴趣的项目开始实践
- 深入研究: 阅读经典论文,理解最新技术进展
准备好了吗?打开 03-cnn-image-classification.ipynb 开始动手实践! 🚀