引言
卷积神经网络(Convolutional Neural Network, CNN)是深度学习在计算机视觉领域最成功的模型之一。从图像分类到目标检测,从语义分割到图像生成,CNN 无处不在。
1. 为什么需要 CNN
1.1 全连接网络的问题
对于 224×224 的 RGB 图像,展平后有 224×224×3=150,528 个输入。如果第一个隐藏层有 1000 个神经元,则需要约 1.5 亿个参数!
问题:
- 参数爆炸:参数过多导致过拟合和计算困难
- 忽略空间结构:展平操作丢失了像素的空间关系
- 缺乏平移不变性:同一物体在不同位置需要重新学习
1.2 CNN 的设计直觉
CNN 的核心思想来自视觉神经科学:
- 局部感受野:神经元只对视野中的局部区域响应
- 权值共享:相同的特征检测器用于整个图像
- 层次化表示:从边缘到形状到物体的逐层抽象
2. 卷积运算
2.1 数学定义
对于输入 x 和卷积核 w,卷积运算(实际上是互相关):
(x∗w)(i,j)=m∑n∑x(i+m,j+n)⋅w(m,n)
2.2 卷积层参数
输入:H×W×Cin(高度 × 宽度 × 输入通道)
卷积核:K×K×Cin×Cout
输出大小:
Hout=SH−K+2P+1
其中:
- K:卷积核大小
- P:填充(padding)
- S:步幅(stride)
2.3 多通道卷积
对于 RGB 图像(3 通道),每个卷积核也有 3 层,分别与对应通道卷积后求和:
y=c=1∑Cinxc∗wc+b
2.4 1×1 卷积
1×1 卷积不改变空间尺寸,但可以:
- 改变通道数:降维或升维
- 增加非线性:每个卷积后跟激活函数
- 跨通道信息交互
3. 池化层
3.1 最大池化
取窗口内的最大值:
y=(m,n)∈windowmaxx(i+m,j+n)
作用:
3.2 平均池化
y=∣W∣1(m,n)∈W∑x(i+m,j+n)
3.3 全局平均池化 (GAP)
对整个特征图求平均,常用于分类网络的最后:
yc=H×W1i,j∑xc(i,j)
优点:无参数,减少过拟合。
4. 激活函数
4.1 ReLU
ReLU(x)=max(0,x)
优点:
问题:Dead ReLU(神经元永久失效)
4.2 Leaky ReLU
LeakyReLU(x)={xαxif x>0if x≤0
4.3 GELU
GELU(x)=x⋅Φ(x)
其中 Φ 是标准正态分布的 CDF。在 Transformer 中广泛使用。
5. 经典 CNN 架构
5.1 LeNet-5 (1998)
1 2 3 4 5 6
| Input (32×32×1) ↓ Conv 5×5, 6 filters → 28×28×6 ↓ AvgPool 2×2 → 14×14×6 ↓ Conv 5×5, 16 filters → 10×10×16 ↓ AvgPool 2×2 → 5×5×16 ↓ FC 120 → FC 84 → Output 10
|
5.2 AlexNet (2012)
ImageNet 竞赛的突破性工作,深度学习复兴的标志。
创新点:
- 使用 ReLU 激活函数
- 使用 Dropout 防止过拟合
- 数据增强(随机裁剪、翻转)
- GPU 训练
5.3 VGGNet (2014)
核心思想:使用小卷积核(3×3)堆叠代替大卷积核。
两个 3×3 卷积 = 一个 5×5 感受野,但参数更少:
2×(32)=18<52=25
VGG-16 结构:
1 2 3 4 5 6
| [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
|
5.4 GoogLeNet/Inception (2014)
Inception 模块:并行使用不同大小的卷积核,然后拼接。
1 2 3 4 5
| Input / | | \ 1×1 3×3 5×5 MaxPool \ | | / Concatenate
|
使用 1×1 卷积降维减少计算量。
5.5 ResNet (2015)
核心创新:残差连接(Skip Connection)
y=F(x)+x
网络学习残差 F(x)=y−x,而不是直接学习 y。
残差块:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class ResidualBlock(nn.Module): def __init__(self, channels): super().__init__() self.conv1 = nn.Conv2d(channels, channels, 3, padding=1) self.bn1 = nn.BatchNorm2d(channels) self.conv2 = nn.Conv2d(channels, channels, 3, padding=1) self.bn2 = nn.BatchNorm2d(channels) def forward(self, x): identity = x out = F.relu(self.bn1(self.conv1(x))) out = self.bn2(self.conv2(out)) out += identity return F.relu(out)
|
为什么有效:
- 梯度可以直接通过跳跃连接回传
- 允许训练非常深的网络(152+ 层)
- 隐式集成了不同深度的网络
6. 批量归一化
6.1 定义
对于 mini-batch 中的每个特征:
x^i=σB2+ϵxi−μB
yi=γx^i+β
其中 γ,β 是可学习参数。
6.2 作用
- 加速训练:允许更大的学习率
- 正则化效果:mini-batch 统计带来噪声
- 减少内部协变量偏移
7. PyTorch 实现
7.1 简单 CNN
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| import torch import torch.nn as nn import torch.nn.functional as F
class SimpleCNN(nn.Module): def __init__(self, num_classes=10): super().__init__() self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1) self.bn1 = nn.BatchNorm2d(32) self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1) self.bn2 = nn.BatchNorm2d(64) self.conv3 = nn.Conv2d(64, 128, kernel_size=3, padding=1) self.bn3 = nn.BatchNorm2d(128) self.pool = nn.MaxPool2d(2, 2) self.fc1 = nn.Linear(128 * 4 * 4, 256) self.fc2 = nn.Linear(256, num_classes) self.dropout = nn.Dropout(0.5) def forward(self, x): x = self.pool(F.relu(self.bn1(self.conv1(x)))) x = self.pool(F.relu(self.bn2(self.conv2(x)))) x = self.pool(F.relu(self.bn3(self.conv3(x)))) x = x.view(x.size(0), -1) x = self.dropout(F.relu(self.fc1(x))) x = self.fc2(x) return x
|
7.2 使用预训练模型
1 2 3 4 5 6 7 8 9 10 11 12 13
| import torchvision.models as models
model = models.resnet18(pretrained=True)
num_classes = 10 model.fc = nn.Linear(model.fc.in_features, num_classes)
for param in model.parameters(): param.requires_grad = False model.fc.requires_grad = True
|
7.3 训练循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| device = torch.device("cuda" if torch.cuda.is_available() else "cpu") model = SimpleCNN().to(device) criterion = nn.CrossEntropyLoss() optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
for epoch in range(num_epochs): model.train() for images, labels in train_loader: images, labels = images.to(device), labels.to(device) optimizer.zero_grad() outputs = model(images) loss = criterion(outputs, labels) loss.backward() optimizer.step() model.eval() correct = 0 total = 0 with torch.no_grad(): for images, labels in val_loader: images, labels = images.to(device), labels.to(device) outputs = model(images) _, predicted = torch.max(outputs, 1) total += labels.size(0) correct += (predicted == labels).sum().item() print(f"Epoch {epoch+1}, Accuracy: {100*correct/total:.2f}%")
|
8. CNN 的理论理解
8.1 感受野
第 L 层的感受野大小:
RFL=RFL−1+(KL−1)×i=1∏L−1Si
深层神经元"看到"的输入区域更大。
8.2 特征可视化
浅层学习:边缘、颜色、纹理
中层学习:角点、形状、纹理组合
深层学习:物体部件、语义概念
8.3 平移等变性
卷积具有平移等变性:
Tt(f∗g)=(Ttf)∗g
输入平移导致输出相同平移。
总结
CNN 的核心设计原则:
- 局部连接:减少参数,利用空间局部性
- 权值共享:同一特征检测器检测整张图
- 层次表示:从低级到高级特征逐层抽象
- 池化下采样:降低分辨率,增加感受野
- 残差连接:训练更深的网络
参考资料
- LeCun, Y. et al. Gradient-based learning applied to document recognition, 1998
- Krizhevsky, A. et al. ImageNet Classification with Deep Convolutional Neural Networks, 2012
- He, K. et al. Deep Residual Learning for Image Recognition, 2015
- CS231n: Convolutional Neural Networks