山大软院ai导论实验之采用BP神经网络分类MNIST数据集

发布于:2025-02-27 ⋅ 阅读:(17) ⋅ 点赞:(0)

 目录

实验代码

实验内容


实验代码

import matplotlib.pyplot as plt
from matplotlib import font_manager
import torch
from torch.utils.data import DataLoader
import torchvision
from torchvision import transforms

# 数据预处理
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.5,), (0.5,))
])


train_data_path = 'E:\\小刘的桌面\\人工智能导论实验\\expr2_trainset'
train_dataset = torchvision.datasets.MNIST(root=train_data_path, train=True, download=True, transform=transform)
test_dataset = torchvision.datasets.MNIST(root=train_data_path, train=False, download=True, transform=transform)

# 使用DataLoader加载数据集
train_loader = DataLoader(dataset=train_dataset, shuffle=True, batch_size=100)
test_loader = DataLoader(dataset=test_dataset, shuffle=False, batch_size=100)

# 定义BP神经网络结构
class BPNetwork(torch.nn.Module):
    def __init__(self):
        super(BPNetwork, self).__init__()

        # # 4层
        # self.fc1 = torch.nn.Linear(784, 256)
        # self.activation1 = torch.nn.ReLU()
        # self.fc2 = torch.nn.Linear(256, 128)
        # self.activation2 = torch.nn.ReLU()
        # self.fc3 = torch.nn.Linear(128, 64)
        # self.activation3 = torch.nn.ReLU()
        # self.fc4 = torch.nn.Linear(64, 32)
        # self.activation4 = torch.nn.ReLU()
        # self.fc5 = torch.nn.Linear(32, 10)


        # #2层
        # self.fc1 = torch.nn.Linear(784,64)
        # self.activation1 = torch.nn.ReLU()
        # self.fc2 = torch.nn.Linear(64, 32)
        # self.activation2 = torch.nn.ReLU()
        # self.fc3 = torch.nn.Linear(32, 10)




        # self.softmax = torch.nn.LogSoftmax(dim=1)

    # def forward(self, x):
    #     x = x.view(x.size(0), -1)
    #     x = self.activation1(self.fc1(x))
    #     x = self.activation2(self.fc2(x))
    #     # x = self.activation3(self.fc3(x))
    #     x = self.softmax(self.fc3(x))
    #     return x
    # def forward(self, x):
    #     x = x.view(x.size(0), -1)
    #     x = self.activation1(self.fc1(x))
    #     x = self.activation2(self.fc2(x))
    #     x = self.activation3(self.fc3(x))
    #     x = self.activation4(self.fc4(x))
    #     x = self.softmax(self.fc5(x))  # 修改为使用fc5
    #     return x
        # 3个隐藏层
        self.fc1 = torch.nn.Linear(784, 128)
        self.activation1 = torch.nn.ReLU()
        self.fc2 = torch.nn.Linear(128, 64)
        self.activation2 = torch.nn.ReLU()
        self.fc3 = torch.nn.Linear(64, 32)
        self.activation3 = torch.nn.ReLU()
        self.fc4 = torch.nn.Linear(32, 10)

        self.softmax = torch.nn.LogSoftmax(dim=1)


    def forward(self, x):
        x = x.view(x.size(0), -1)
        x = self.activation1(self.fc1(x))
        x = self.activation2(self.fc2(x))
        x = self.activation3(self.fc3(x))
        x = self.softmax(self.fc4(x))  # 使用fc4作为输出层
        return x

    #     # 5个隐藏层
    #     self.fc1 = torch.nn.Linear(784, 512)
    #     self.activation1 = torch.nn.ReLU()
    #     self.fc2 = torch.nn.Linear(512, 256)
    #     self.activation2 = torch.nn.ReLU()
    #     self.fc3 = torch.nn.Linear(256, 128)
    #     self.activation3 = torch.nn.ReLU()
    #     self.fc4 = torch.nn.Linear(128, 64)
    #     self.activation4 = torch.nn.ReLU()
    #     self.fc5 = torch.nn.Linear(64, 32)
    #     self.activation5 = torch.nn.ReLU()
    #     self.fc6 = torch.nn.Linear(32, 10)
    #
    #     self.softmax = torch.nn.LogSoftmax(dim=1)
    #
    #
    # def forward(self, x):
    #     x = x.view(x.size(0), -1)
    #     x = self.activation1(self.fc1(x))
    #     x = self.activation2(self.fc2(x))
    #     x = self.activation3(self.fc3(x))
    #     x = self.activation4(self.fc4(x))
    #     x = self.activation5(self.fc5(x))
    #     x = self.softmax(self.fc6(x))  # 使用fc6作为输出层
    #     return x


# 创建网络模型
model = BPNetwork()
# 定义损失函数与优化器
criterion = torch.nn.NLLLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.009, momentum=0.9)
num_epochs = 1
total_batches = 0

font = font_manager.FontProperties()


batch_steps = []
train_accuracies = []
test_accuracies = []

# 训练网络
for epoch in range(num_epochs):
    for images, labels in train_loader:
        total_batches += 1
        optimizer.zero_grad()  # 清空梯度
        outputs = model(images)  # 前向传播
        loss = criterion(outputs, labels)  # 计算损失
        loss.backward()  # 反向传播
        optimizer.step()  # 更新参数

        # 每50批次计算并记录准确率
        if total_batches % 50 == 0:
            # 计算训练集准确率
            train_correct = (outputs.argmax(dim=1) == labels).sum().item()
            train_accuracy = train_correct / len(images)

            # 计算测试集准确率
            test_correct = 0
            with torch.no_grad():
                for test_images, test_labels in test_loader:
                    test_outputs = model(test_images)
                    test_correct += (test_outputs.argmax(dim=1) == test_labels).sum().item()
            test_accuracy = test_correct / len(test_dataset)

            # 存储结果
            batch_steps.append(total_batches)
            train_accuracies.append(train_accuracy)
            test_accuracies.append(test_accuracy)

            print(f"Step {total_batches}, Training Accuracy: {train_accuracy:.2f}, Test Accuracy: {test_accuracy:.4f}")

# 绘制曲线
plt.figure(figsize=(10, 5))
plt.plot(batch_steps, train_accuracies, label='Training Accuracy', marker='o')
plt.plot(batch_steps, test_accuracies, label='Test Accuracy', marker='x')
plt.title('Training and Test Accuracy Over Time', fontproperties=font, fontsize=18)
plt.xlabel('Batch Steps', fontproperties=font, fontsize=12)
plt.ylabel('Accuracy', fontproperties=font, fontsize=12)
plt.legend()
plt.show()

实验内容

1.下载数据集:

MNIST数据集来自美国国家标准与技术研究所(NIST),包含手写数字图片及其标签。数据集分为训练集和测试集,详细信息如下:

训练集:包含60000张图片及其标签,每张图片是一个28 x 28的灰度图像。

测试集:包含10000张图片及其标签,图片格式与训练集相同。

每个样本代表一个手写数字(0-9),图片中像素值已归一化到[0, 1]范围。

进行数据集的下载:

2.数据预处理:使用torchvision加载MNIST数据集并进行标准化。将训练集和测试集的每个像素点归一化到[-1, 1]范围,以适应神经网络的输入。

  1. 定义BP神经网络结构:构建一个多层感知器网络,在本次实验分别采用了2、3、4、5层隐藏层,用以来观察各个的准确率。其中三层隐藏层中,每层隐藏层分别包含128、64、32个神经元,2层和34层分别递减或者递增即可,另外激活函数为ReLU,输出层采用LogSoftmax。

3个隐藏层:

  1. 训练:设置学习率为0.009,并采用交叉熵损失函数和SGD优化器进行训练。训练集中每批包含100个样本,总共训练1个epoch,每50个批次计算一次训练集和测试集的准确率。最终在训练完所有样本后,记录模型在测试集上的最终准确率。

  1. 为使训练和测试的准确率更为直观,使用matplotlib绘制训练和测试准确率随批次数变化的折线图,以便观察模型的训练过程。