共计 2429 个字符,预计需要花费 7 分钟才能阅读完成。
为什么需要 CNN?
传统全连接神经网络在处理图像时会遇到两个致命问题:
- 参数爆炸 :假设处理 100×100 像素的 RGB 图片,输入层就需要 100×100×3=30,000 个权重参数,第一个隐藏层若包含 1000 个神经元,仅这一层就有 3000 万个参数!计算量公式为:
$$\text{参数量} = \text{输入维度} \times \text{输出维度} + \text{输出维度}$$
- 无视局部关联 :全连接网络把图像拆解为独立像素点处理,完全忽略了相邻像素之间的空间关系。
CNN 核心原理图解
卷积操作本质
想象用一个手电筒(卷积核)在图像上滑动扫描,每次照亮一个小区域做计算。数学表达为:
$$S(i,j) = (I * K)(i,j) = \sum_m \sum_n I(i+m,j+n)K(m,n)$$
其中 $I$ 是输入图像,$K$ 是卷积核,$S$ 是输出特征图。

为什么需要 ReLU?
使用激活函数 $\text{ReLU}(x)=\max(0,x)$ 有两个关键好处:
- 解决梯度消失问题(相比 sigmoid)
- 增加网络非线性表达能力
PyTorch 实战 MNIST 分类
模型定义
import torch
import torch.nn as nn
model = nn.Sequential(
# 卷积层 1: 输入 1 通道,输出 32 通道,3x3 卷积核
nn.Conv2d(1, 32, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2), # 2x2 最大池化
# 卷积层 2: 32→64 通道
nn.Conv2d(32, 64, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2),
# 展平后接全连接层
nn.Flatten(),
nn.Linear(64*7*7, 128), # MNIST 经两次池化后尺寸计算
nn.ReLU(),
nn.Linear(128, 10)
)
训练循环关键代码
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
criterion = nn.CrossEntropyLoss()
for epoch in range(10):
for images, labels in train_loader:
# 数据归一化到 [0,1]
images = images / 255.0
optimizer.zero_grad()
outputs = model(images)
loss = criterion(outputs, labels)
# 核心三步曲
loss.backward() # 反向传播
optimizer.step() # 更新权重
# 打印训练进度
if (i+1) % 100 == 0:
print(f'Epoch [{epoch+1}/10], Loss: {loss.item():.4f}')
调参实战技巧
学习率与 batch size 的协同
- 大 batch size 需要更大的学习率
- 推荐初始设置:
- batch_size=64 → lr=0.001
- batch_size=256 → lr=0.004
使用 torchsummary 诊断模型
from torchsummary import summary
summary(model, input_size=(1, 28, 28)) # MNIST 输入尺寸
输出示例:
----------------------------------------------------------------
Layer (type) Output Shape Param #
================================================================
Conv2d-1 [-1, 32, 28, 28] 320
ReLU-2 [-1, 32, 28, 28] 0
MaxPool2d-3 [-1, 32, 14, 14] 0
Conv2d-4 [-1, 64, 14, 14] 18,496
ReLU-5 [-1, 64, 14, 14] 0
MaxPool2d-6 [-1, 64, 7, 7] 0
Flatten-7 [-1, 3136] 0
Linear-8 [-1, 128] 401,536
ReLU-9 [-1, 128] 0
Linear-10 [-1, 10] 1,290
================================================================
Total params: 421,642
常见避坑指南
维度错误急救包
# 经典错误:忘记 unsqueeze 增加通道维度
tensor = torch.randn(28, 28) # 错误!应该是 1×28×28
correct_tensor = tensor.unsqueeze(0) # 变为 1×28×28
# 处理 NHWC 格式数据 (如 OpenCV 读取的图片)
image = cv2.imread('cat.jpg') # H×W×C 格式
pytorch_tensor = torch.from_numpy(image).permute(2,0,1) # 转为 C×H×W
显存不足解决方案
- 减小 batch size(如从 256 降到 64)
- 使用混合精度训练:
scaler = torch.cuda.amp.GradScaler() with torch.cuda.amp.autocast(): outputs = model(inputs) loss = criterion(outputs, labels) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update()
延伸思考
当处理 4 通道 DICOM 医学影像时,只需修改第一层卷积的 in_channels 参数:
# 原版:适用于灰度图像
nn.Conv2d(1, 32, kernel_size=3)
# 修改版:适配 4 通道输入
nn.Conv2d(4, 32, kernel_size=3)
关键是要保证卷积核的输入通道数与实际数据通道数一致。其他网络结构无需改动,这就是 CNN 参数共享优势的体现!
正文完
