醋醋百科网

Good Luck To You!

PyTorch 深度学习实战(4):卷积神经网络(CNN)与图像分类


在上一篇文章中,我们使用全连接神经网络(Fully Connected Neural Network)实现了手写数字识别,并取得了不错的效果。然而,全连接神经网络在处理图像数据时存在一些局限性,例如参数过多、难以捕捉局部特征等。为了解决这些问题,本文将介绍 卷积神经网络(Convolutional Neural Network, CNN),并使用 CNN 进一步提升手写数字识别的性能。


一、卷积神经网络基础

卷积神经网络是专门为处理图像数据而设计的神经网络,它的核心思想是通过 卷积操作 提取图像的局部特征,并通过 池化操作 降低数据的维度。

1. 卷积层(Convolutional Layer)

卷积层是 CNN 的核心组件,它通过卷积核(Kernel)在图像上滑动,提取局部特征。卷积操作的主要参数包括:

  • 卷积核大小:例如 3x3 或 5x5。
  • 步长(Stride):卷积核滑动的步长。
  • 填充(Padding):在图像边缘填充像素,以控制输出特征图的大小。

2. 池化层(Pooling Layer)

池化层用于降低特征图的空间维度,同时保留重要信息。常用的池化操作包括:

  • 最大池化(Max Pooling):取局部区域的最大值。
  • 平均池化(Average Pooling):取局部区域的平均值。

3. 全连接层(Fully Connected Layer)

在 CNN 的最后几层,通常会使用全连接层将提取的特征映射到最终的输出类别。

4. 经典 CNN 模型

  • LeNet:最早的 CNN 模型之一,用于手写数字识别。
  • AlexNet:在 ImageNet 竞赛中取得突破性成绩。
  • VGG:通过堆叠多个小卷积核构建深层网络。
  • ResNet:引入残差连接,解决了深层网络的梯度消失问题。

二、使用 CNN 实现手写数字识别

我们将使用 PyTorch 构建一个简单的 CNN 模型,并在 MNIST 数据集上进行训练和测试。

1. 实现步骤

  1. 加载和预处理数据。
  2. 定义 CNN 模型。
  3. 定义损失函数和优化器。
  4. 训练模型。
  5. 测试模型并评估性能。

2. 代码实现

import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
import matplotlib.pyplot as plt

# 设置 Matplotlib 支持中文显示
plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置字体为 SimHei(黑体)
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题

# 1. 加载和预处理数据
transform = transforms.Compose([
    transforms.ToTensor(),  # 将图像转换为张量
    transforms.Normalize((0.1307,), (0.3081,))  # 标准化
])

# 下载并加载训练集和测试集
train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
test_dataset = datasets.MNIST(root='./data', train=False, download=True, transform=transform)

train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=64, shuffle=False)

# 2. 定义 CNN 模型
class SimpleCNN(nn.Module):
    def __init__(self):
        super(SimpleCNN, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1)  # 卷积层
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2)  # 池化层
        self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)  # 卷积层
        self.fc1 = nn.Linear(64 * 7 * 7, 128)  # 全连接层
        self.fc2 = nn.Linear(128, 10)  # 输出层

    def forward(self, x):
        x = self.pool(torch.relu(self.conv1(x)))  # 第一层卷积 + ReLU + 池化
        x = self.pool(torch.relu(self.conv2(x)))  # 第二层卷积 + ReLU + 池化
        x = x.view(-1, 64 * 7 * 7)  # 展平
        x = torch.relu(self.fc1(x))  # 全连接层 + ReLU
        x = self.fc2(x)  # 输出层
        return x

model = SimpleCNN()

# 3. 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()  # 交叉熵损失
optimizer = optim.Adam(model.parameters(), lr=0.001)  # Adam 优化器

# 4. 训练模型
num_epochs = 5
loss_history = []

for epoch in range(num_epochs):
    for i, (images, labels) in enumerate(train_loader):
        # 前向传播
        outputs = model(images)
        loss = criterion(outputs, labels)
        
        # 反向传播
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        # 记录损失
        if (i + 1) % 100 == 0:
            loss_history.append(loss.item())
            print(f"Epoch [{epoch + 1}/{num_epochs}], Step [{i + 1}/{len(train_loader)}], Loss: {loss.item():.4f}")

# 5. 测试模型
model.eval()  # 设置模型为评估模式
correct = 0
total = 0

with torch.no_grad():
    for images, labels in test_loader:
        outputs = model(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

print(f"测试集准确率: {100 * correct / total:.2f}%")

# 6. 可视化损失曲线
plt.plot(loss_history)
plt.xlabel("训练步数")
plt.ylabel("损失值")
plt.title("训练损失曲线")
plt.show()

三、代码解析

  1. 数据加载与预处理:

使用
torchvision.datasets.MNIST
加载 MNIST 数据集。

使用 transforms.ToTensor() 将图像转换为张量,并进行标准化。

  1. CNN 模型:

定义了一个简单的 CNN 模型 SimpleCNN,包含两个卷积层、两个池化层和两个全连接层。

使用 ReLU 作为激活函数。

  1. 训练过程:

使用交叉熵损失函数和 Adam 优化器。

训练 5 个 epoch,并记录损失值。

  1. 测试过程:

在测试集上评估模型性能,计算准确率。

  1. 可视化:

绘制训练损失曲线。


四、运行结果

运行上述代码后,你将看到以下输出:

  1. 训练过程中每 100 步打印一次损失值。
  2. 测试集准确率(通常在 98% 以上,比全连接神经网络更高)。
  3. 训练损失曲线图。

五、总结

本文介绍了卷积神经网络的基本概念,并使用 PyTorch 实现了一个简单的 CNN 模型来提升手写数字识别的性能。通过卷积操作和池化操作,CNN 能够有效地提取图像的局部特征,从而在图像分类任务中取得更好的效果。

在下一篇文章中,我们将学习如何使用更复杂的 CNN 模型(如 ResNet)来解决更复杂的图像分类问题。敬请期待!


代码实例说明:

  • 本文代码可以直接在 Jupyter Notebook 或 Python 脚本中运行。
  • 如果你有 GPU,可以将模型和数据移动到 GPU 上运行,例如:model = model.to('cuda')images = images.to('cuda')

希望这篇文章能帮助你更好地理解卷积神经网络的基础知识!如果有任何问题,欢迎在评论区留言讨论。

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言