标签:
Pytorch、CNN、卷积神经网络、Conv2d、池化
简介:全连接网络把图片摊平会丢失空间信息,CNN利用卷积核提取图像局部特征(边缘、纹理、轮廓)。本文吃透卷积核心参数、池化作用,从零搭建CNN完成MNIST手写数字分类。
一、前言
上一篇我们用全连接层完成MNIST分类。全连接网络有明显短板:
- 把28×28二维图像直接Flatten成一维向量,丢失像素之间空间位置关系
- 参数数量巨大,容易过拟合
CNN(卷积神经网络)三大核心组件:卷积层Conv、池化层Pool、激活函数
卷积:滑动卷积核提取局部特征;池化:降采样、压缩特征图,减少计算量。
二、Conv2d 卷积层核心参数
nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0)
| 参数 | 含义 |
|---|---|
| in_channels | 输入通道数:灰度图=1,RGB彩色图=3 |
| out_channels | 输出通道数,等价于卷积核数量,想要多少组特征图 |
| kernel_size | 卷积核大小,常用 3 等价 (3,3) |
| stride | 步长,卷积核每次滑动几格,默认1 |
| padding | 边缘填充0,填充大小,控制输出特征图尺寸 |
输出特征图尺寸公式:
Hout=Hin+2×padding−kernel_sizestride+1H_{out} = \frac{H_{in}+2\times padding - kernel\_size}{stride}+1Hout=strideHin+2×padding−kernel_size+1
示例:输入28×28,kernel=3,padding=1,stride=1
(28+2×1−3)/1+1=28(28 + 2\times1 -3)/1 +1 = 28(28+2×1−3)/1+1=28
padding=1时3×3卷积不改变宽高(same padding)
三、池化层 MaxPool2d
最常用最大池化 nn.MaxPool2d(kernel_size, stride)
作用:
- 下采样,特征图宽高减半,减少参数量与计算量
- 保留显著特征,增加特征鲁棒性
- 没有可学习权重,只是取区域最大值
示例:MaxPool2d(2,2),宽高变为原来1/2
平均池化 AvgPool2d:取区域平均值,现在CV场景用得比较少
四、CNN网络结构设计思路
经典堆叠顺序:
Conv2d → ReLU → MaxPool2d → Conv2d → ReLU → MaxPool2d → Flatten → Linear
浅层卷积:提取边缘、线条;深层卷积:提取组合特征(数字轮廓)
五、完整CNN代码(MNIST)
import torch
import torch.nn as nn
from torch.utils.data import DataLoader, random_split
from torchvision import datasets, transforms
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"运行设备:{device}")
# 数据预处理
trans = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])
# 数据集划分
full_data = datasets.MNIST(root="./data", train=True, transform=trans, download=True)
train_ds, val_ds = random_split(full_data, [int(0.8*len(full_data)), len(full_data)-int(0.8*len(full_data))])
train_loader = DataLoader(train_ds, batch_size=64, shuffle=True)
val_loader = DataLoader(val_ds, batch_size=64, shuffle=False)
# 搭建CNN
class MnistCNN(nn.Module):
def __init__(self):
super().__init__()
self.conv_layers = nn.Sequential(
# 输入 [batch,1,28,28]
nn.Conv2d(in_channels=1, out_channels=16, kernel_size=3, stride=1, padding=1),
nn.ReLU(),
nn.MaxPool2d(2,2), # 输出 [batch,16,14,14]
nn.Conv2d(in_channels=16, out_channels=32, kernel_size=3, stride=1, padding=1),
nn.ReLU(),
nn.MaxPool2d(2,2), # 输出 [batch,32,7,7]
)
self.fc_layers = nn.Sequential(
nn.Flatten(),
nn.Linear(32 * 7 * 7, 128),
nn.ReLU(),
nn.Linear(128, 10)
)
def forward(self, x):
x = self.conv_layers(x)
x = self.fc_layers(x)
return x
model = MnistCNN().to(device)
loss_fn = nn.CrossEntropyLoss()
opt = torch.optim.Adam(model.parameters(), lr=1e-3)
epoch_num = 10
best_val_acc = 0.0
for epoch in range(epoch_num):
# 训练
model.train()
train_loss_sum = 0.0
for imgs, labels in train_loader:
imgs, labels = imgs.to(device), labels.to(device)
outputs = model(imgs)
loss = loss_fn(outputs, labels)
opt.zero_grad()
loss.backward()
opt.step()
train_loss_sum += loss.item()
train_loss_avg = train_loss_sum / len(train_loader)
# 验证
model.eval()
val_loss_sum = 0.0
correct_sum = 0
total_num = 0
with torch.no_grad():
for imgs, labels in val_loader:
imgs, labels = imgs.to(device), labels.to(device)
outputs = model(imgs)
loss = loss_fn(outputs, labels)
val_loss_sum += loss.item()
preds = torch.max(outputs, dim=1)[1]
correct_sum += torch.sum(preds == labels)
total_num += labels.size(0)
val_loss_avg = val_loss_sum / len(val_loader)
val_acc = correct_sum.item() / total_num
print(f"【Epoch {epoch+1}/{epoch_num}】")
print(f"train_loss:{train_loss_avg:.4f} | val_loss:{val_loss_avg:.4f} | val_acc:{val_acc:.4f}\n")
if val_acc > best_val_acc:
best_val_acc = val_acc
torch.save(model.state_dict(), "mnist_cnn_best.pth")
print(f"✅ 保存最优CNN模型,最佳acc:{best_val_acc:.4f}")
六、CNN对比全连接网络优势总结
- 局部感受野:卷积核只看一小块区域,符合图像特征局部相关性
- 权值共享:一张图共用同一套卷积核,大幅减少参数量
- 平移不变性:同一个特征,在图里左右移动依然可以被识别
七、高频踩坑点
- Conv2d输入维度必须是
[batch, C, H, W],通道在前!PIL图片默认HWC,ToTensor自动转CHW - 算错Flatten之后Linear输入维度:改卷积、池化参数之后一定要重新算特征尺寸
- 通道数顺序:in_channels要和上一层输出通道对齐
- 池化没有参数,不需要训练
- 卷积后忘记激活函数,网络退化成线性组合,拟合能力暴跌
八、拓展小知识
- 1×1卷积:用来升降通道数,不改变宽高,压缩通道、融合跨通道信息
- 空洞卷积dilation:扩大感受野,不增加卷积核尺寸
- groups分组卷积:深度可分离卷积的基础,轻量化模型常用
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/Beforthing/article/details/170366158



