CNN卷积神经网络入门实战:从零搭建图像分类模型(附CSDN代码)

1次阅读
没有评论

共计 2363 个字符,预计需要花费 6 分钟才能阅读完成。

image.webp

为什么选择 CNN 处理图像?

卷积神经网络(Convolutional Neural Network, CNN)在图像处理领域有两大先天优势:

CNN 卷积神经网络入门实战:从零搭建图像分类模型(附 CSDN 代码)

  • 局部感知机制 :传统全连接网络需要每个神经元连接所有输入像素(比如 224×224 图像会产生 50176 个权重),而 CNN 通过卷积核(Kernel)在局部滑动窗口计算(通常 3 ×3 或 5 ×5),大幅减少参数量。例如 $S(i,j)=(I*K)(i,j)$ 表示在位置(i,j) 的卷积运算

  • 参数共享特性:同一个卷积核会扫描整张图像,这意味着不同位置检测相同特征(如边缘、纹理)时共享同一组权重,既增强了平移不变性,又降低了模型复杂度

LeNet- 5 架构拆解

以经典的 LeNet- 5 为例(结构如下图),我们逐层分析其设计思想:

[INPUT] -> [CONV1] -> [POOL1] -> [CONV2] -> [POOL2] -> [FC1] -> [FC2] -> [OUTPUT]
  1. 卷积层(Convolutional Layer)
  2. CONV1 使用 5 ×5 卷积核提取空间特征,输出 6 个特征图(Feature Map)
  3. 每个神经元只连接输入区域的 5 ×5 邻域,实现局部连接

  4. 池化层(Pooling Layer)

  5. POOL1 采用 2 ×2 最大池化(Max Pooling),保留窗口内最大值
  6. 作用:降低维度同时保持特征不变性(平移 / 旋转鲁棒性)

  7. 全连接层(Fully Connected Layer)

  8. 将最后的特征图展平后送入传统神经网络
  9. FC2 层神经元数量对应分类类别数(如 MNIST 是 10 类)

Python 实战代码(PyTorch 版)

数据准备

import torch
import torchvision

transform = torchvision.transforms.Compose([torchvision.transforms.ToTensor(),
    torchvision.transforms.Normalize((0.5,), (0.5,)) # 像素值归一化到[-1,1]
])

trainset = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True)

网络定义

import torch.nn as nn
import torch.nn.functional as F

class LeNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, 6, 5)  # 输入通道 1,输出通道 6,卷积核 5x5
        self.pool = nn.MaxPool2d(2, 2)   # 2x2 最大池化
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16*4*4, 120) # 展平后维度计算
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x))) # CONV -> ReLU -> POOL
        x = self.pool(F.relu(self.conv2(x)))
        x = torch.flatten(x, 1) # 保留 batch 维度
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

训练循环

model = LeNet()
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9)

for epoch in range(10):
    running_loss = 0.0
    for i, data in enumerate(trainloader):
        inputs, labels = data
        optimizer.zero_grad()
        outputs = model(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
        running_loss += loss.item()
    print(f'Epoch {epoch+1} loss: {running_loss/len(trainloader):.3f}')

新手避坑指南

学习率设置

  • 初始值尝试:常见范围在 0.1~0.0001 之间,简单任务可从 0.01 开始
  • 动态调整 :使用torch.optim.lr_scheduler.ReduceLROnPlateau 当验证损失停滞时自动降低

应对过拟合

  • Dropout 层:在全连接层间随机失活部分神经元(如nn.Dropout(0.5)
  • L2 正则化:优化器添加权重衰减参数(如optim.Adam(model.parameters(), weight_decay=1e-4)

梯度消失解决方案

  • 激活函数选择:用 ReLU 替代 Sigmoid/Tanh(梯度为 1 或 0)
  • 残差连接:在深层网络中加入跳跃连接(ResNet 设计思想)

延伸思考与资源

完整代码已上传 CSDN:项目链接

进阶思考题:
1. 如何修改网络结构以适应 CIFAR-10 的 RGB 三通道输入?
2. 如果训练集准确率高但验证集差,可能是什么原因?如何诊断?
3. 尝试添加 Batch Normalization 层观察训练速度变化

测试环境说明:
– 显卡:NVIDIA GTX 1060 6GB
– 数据集:MNIST(60,000 训练样本)
– 训练时间:约 3 分钟 /epoch

正文完
 0
评论(没有评论)