(4-2-2)开发卷积神经网络模型——PyTorch实现

本实例的功能是创建LeNet-5模型,对MNIST手写数字数据集进行训练和测试,并在训练过程中绘制损失曲线和准确率曲线。

实例4-2:创建并使用LeNet-5模型源码路径:daima\4\can.py

1. LeNet-5模型介绍

LeNet-5是一种经典的卷积神经网络(CNN)模型,由Yann LeCun等人于1998年提出,主要用于手写数字识别任务。它是第一个在实际任务中取得成功的卷积神经网络模型之一,为后来的深度学习发展奠定了基础。

LeNet-5模型的设计主要基于两个关键思想:稀疏连接和权值共享,它采用了一种层次化的结构,通过卷积、池化和全连接层来提取特征并进行分类。

下面是LeNet-5模型的详细结构:

1输入层

  1. 输入图像为灰度图像,大小为32x32。

(2)第一层:卷积层

  1. 输入大小:32x32x1
  2. 卷积核大小:5x5
  3. 卷积核数量:6
  4. 激活函数:ReLU(Rectified Linear Unit)
  5. 输出大小:28x28x6

(3)第二层:池化层

  1. 输入大小:28x28x6
  2. 池化窗口大小:2x2
  3. 池化方式:最大池化(Max Pooling)
  4. 输出大小:14x14x6

(4)第三层:卷积层

  1. 输入大小:14x14x6
  2. 卷积核大小:5x5
  3. 卷积核数量:16
  4. 激活函数:ReLU
  5. 输出大小:10x10x16

(5)第四层:池化层

  1. 输入大小:10x10x16
  2. 池化窗口大小:2x2
  3. 池化方式:最大池化
  4. 输出大小:5x5x16

(6)第五层:全连接层

  1. 输入大小:5x5x16=400
  2. 输出大小:120
  3. 激活函数:ReLU

(7)第六层:全连接层:

  1. 输入大小:120
  2. 输出大小:84
  3. 激活函数:ReLU

(8)第七层:全连接层(输出层)

  1. 输入大小:84
  2. 输出大小:10(对应10个类别,用于手写数字的分类)
  3. 激活函数:无(使用softmax激活函数进行多类别分类)

LeNet-5模型的整体结构是由多个卷积层、池化层和全连接层组成的,其中卷积层和池化层用于特征提取,全连接层用于分类。通过稀疏连接和权值共享的设计,LeNet-5模型在参数量和计算复杂度上较小,适用于处理小尺寸图像的任务。

2. 具体实现

实例文件can.py的具体实现流程如下所示。

(1)导入所需的库和模块,对应的实现代码如下所示:

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader
from torchvision.datasets import MNIST
from torchvision.transforms import transforms
import matplotlib.pyplot as plt

2定义LeNet-5模型,具体说明如下:

  1. LeNet5类继承自nn.Module,是LeNet-5模型的定义。
  2. 模型包括两个部分:特征提取层(features)和分类器层(classifier)。
  3. 特征提取层包括两个卷积层和池化层,用于提取图像的特征。
  4. 分类器层包括三个全连接层,用于对提取的特征进行分类。
  5. forward方法定义了前向传播的过程。

对应的实现代码如下所示:

# 定义LeNet-5模型
class LeNet5(nn.Module):
    def __init__(self, num_classes=10):
        super(LeNet5, self).__init__()
        self.features = nn.Sequential(
            nn.Conv2d(1, 6, kernel_size=5, stride=1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.Conv2d(6, 16, kernel_size=5, stride=1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2)
        )
        self.classifier = nn.Sequential(
            nn.Linear(16 * 4 * 4, 120),
            nn.ReLU(),
            nn.Linear(120, 84),
            nn.ReLU(),
            nn.Linear(84, num_classes)
        )

    def forward(self, x):
        x = self.features(x)
        x = torch.flatten(x, 1)
        x = self.classifier(x)
        return x

3数据预处理和加载,首先定义了数据的预处理操作,包括将图像转换为张量、归一化等;然后使用MNIST类加载训练集和测试集,并应用预处理操作。对应的实现代码如下所示。

# 数据预处理和加载
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.1307,), (0.3081,))
])

train_dataset = MNIST(root='./data', train=True, download=True, transform=transform)
test_dataset = MNIST(root='./data', train=False, download=True, transform=transform)

train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)

4创建模型和优化器,首先创建LeNet-5模型的实例,然后定义损失函数(交叉熵损失)和优化器(Adam优化器)。对应的实现代码如下所示。

# 创建模型和优化器
model = LeNet5()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

5)开始训练模型,具体实现流程如下:

  1. 使用循环迭代训练模型。
  2. 将模型设为训练模式,遍历训练集的批次,计算训练损失和训练准确率,并更新模型的参数。
  3. 将模型设为评估模式,遍历测试集的批次,计算测试损失和测试准确率。

对应的实现代码如下所示。

# 训练模型
num_epochs = 10
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)

train_losses = []
test_losses = []
train_accuracies = []
test_accuracies = []

for epoch in range(num_epochs):
    model.train()
    running_loss = 0.0
    correct_train = 0
    total_train = 0

    for images, labels in train_loader:
        images = images.to(device)
        labels = labels.to(device)

        optimizer.zero_grad()
        outputs = model(images)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        _, predicted_train = torch.max(outputs.data, 1)
        total_train += labels.size(0)
        correct_train += (predicted_train == labels).sum().item()

    train_loss = running_loss / len(train_loader)
    train_accuracy = 100 * correct_train / total_train
    train_losses.append(train_loss)
    train_accuracies.append(train_accuracy)

    # 在测试集上评估模型
    model.eval()
    running_loss = 0.0
    correct_test = 0
    total_test = 0

    with torch.no_grad():
        for images, labels in test_loader:
            images = images.to(device)
            labels = labels.to(device)

            outputs = model(images)
            loss = criterion(outputs, labels)

            running_loss += loss.item()
            _, predicted_test = torch.max(outputs.data, 1)
            total_test += labels.size(0)
            correct_test += (predicted_test == labels).sum().item()

    test_loss = running_loss / len(test_loader)
    test_accuracy = 100 * correct_test / total_test
    test_losses.append(test_loss)
    test_accuracies.append(test_accuracy)

    print(
        f"Epoch {epoch + 1}/{num_epochs} Train Loss: {train_loss:.4f} Train Accuracy: {train_accuracy:.2f}% Test Loss: {test_loss:.4f} Test Accuracy: {test_accuracy:.2f}%")

6绘制损失曲线和准确率曲线,使用Matplotlib库绘制训练过程中的损失曲线和准确率曲线。对应的实现代码如下所示。

# 绘制损失曲线和准确率曲线
plt.figure(figsize=(10, 4))
plt.subplot(1, 2, 1)
plt.plot(range(1, num_epochs + 1), train_losses, label='Train')
plt.plot(range(1, num_epochs + 1), test_losses, label='Test')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.subplot(1, 2, 2)
plt.plot(range(1, num_epochs + 1), train_accuracies, label='Train')
plt.plot(range(1, num_epochs + 1), test_accuracies, label='Test')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend()
plt.tight_layout()
plt.show()

7输出最终准确率,打印输出测试集上的最终准确率。对应的实现代码如下所示。

# 最终准确率

print(f"Final Accuracy on test set: {test_accuracies[-1]:.2f}%")

执行后会使用Matplotlib库绘制训练过程中的损失曲线和准确率曲线图,效果如图4-3所示

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农三叔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值