一、实验目的

学习BP神经网络、卷积神经网络的工作原理、构建流程、实现方法。使用两者神经网络处理数据集多分类问题。

二、实验内容

使用BP网络、卷积神经网络CNN实现对MNIST数据集的分类问题。

三、 实验要求

1、第一部分使用简单结构的BP网络,可以调用手写包,包括不限于pytorch、tensorflow深度学习框架;BP网络应包含至少三层网络,输入层、隐藏层、输出层,并使用激活函数。
2、第二部分使用卷积神经网络,同样应包含多层网络,
3、实验应体现出两种神经网络的结构(比如,不能使用mlp等API)。

四、实验报告要求

1.代码中体现网络的结构。
(1)Bp神经网络

import numpy as np
import torch
from torchvision import datasets, transforms

# 数据预处理和加载
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))])
train_data = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
test_data = datasets.MNIST(root='./data', train=False, download=True, transform=transform)

# 只保留几千张图片以加快训练(可选)
train_data.data = train_data.data[:5000]
train_data.targets = train_data.targets[:5000]

# 将数据转换为numpy格式
train_images = train_data.data.numpy().reshape(-1, 28 * 28) / 255.0
train_labels = np.eye(10)[train_data.targets.numpy()]  # One-hot编码
test_images = test_data.data.numpy().reshape(-1, 28 * 28) / 255.0
test_labels = np.eye(10)[test_data.targets.numpy()]  # One-hot编码

class BPNeuralNetwork:
    def __init__(self, input_size, hidden_size, output_size, lr=0.01):
        # 初始化网络参数
        self.lr = lr
        self.weights_input_hidden = np.random.randn(input_size, hidden_size) * 0.01
        self.weights_hidden_output = np.random.randn(hidden_size, output_size) * 0.01
        self.bias_hidden = np.zeros((1, hidden_size))
        self.bias_output = np.zeros((1, output_size))

    def sigmoid(self, x):
        return 1 / (1 + np.exp(-x))

    def sigmoid_derivative(self, x):
        return x * (1 - x)

    def forward(self, x):
        # 前向传播
        self.input = x
        self.hidden = self.sigmoid(np.dot(self.input, self.weights_input_hidden) + self.bias_hidden)
        self.output = self.sigmoid(np.dot(self.hidden, self.weights_hidden_output) + self.bias_output)
        return self.output

    def backward(self, target):
        # 计算误差
        output_error = target - self.output
        output_delta = output_error * self.sigmoid_derivative(self.output)

        hidden_error = np.dot(output_delta, self.weights_hidden_output.T)
        hidden_delta = hidden_error * self.sigmoid_derivative(self.hidden)

        # 更新权重和偏置
        self.weights_hidden_output += self.lr * np.dot(self.hidden.T, output_delta)
        self.bias_output += self.lr * np.sum(output_delta, axis=0, keepdims=True)
        self.weights_input_hidden += self.lr * np.dot(self.input.T, hidden_delta)
        self.bias_hidden += self.lr * np.sum(hidden_delta, axis=0, keepdims=True)

    def train(self, train_images, train_labels, epochs):
        # 将输入数据和标签转为二维数组以支持批处理
        train_images = train_images.reshape(-1, 784)
        train_labels = train_labels.reshape(-1, 10)

        for epoch in range(epochs):
            for x, y in zip(train_images, train_labels):
                x = x.reshape(1, -1)  # 将x变为1x784的二维数组
                y = y.reshape(1, -1)  # 将y变为1x10的二维数组
                self.forward(x)
                self.backward(y)
            if epoch % 10 == 0:
                loss = np.mean((self.forward(train_images) - train_labels) ** 2)
                print(f'Epoch {epoch}, Loss: {loss:.4f}')

    def predict(self, x):
        x = x.reshape(1, -1)  # 转为二维以支持单样本预测
        return np.argmax(self.forward(x), axis=1)

    def accuracy(self, images, labels):
        predictions = [self.predict(x) for x in images]
        targets = np.argmax(labels, axis=1)
        return np.mean(np.array(predictions).flatten() == targets)

# 初始化和训练网络
input_size = 784
hidden_size = 128
output_size = 10
learning_rate = 0.01
epochs = 100

bp_network = BPNeuralNetwork(input_size, hidden_size, output_size, lr=learning_rate)
bp_network.train(train_images, train_labels, epochs=epochs)

# 测试准确率
accuracy = bp_network.accuracy(test_images, test_labels)
print(f"Test Accuracy: {accuracy * 100:.2f}%")


(2)卷积神经网络

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
# 数据预处理和加载
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))])
train_data = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
test_data = datasets.MNIST(root='./data', train=False, download=True, transform=transform)
# 数据加载器
train_loader = DataLoader(train_data, batch_size=64, shuffle=True)
test_loader = DataLoader(test_data, batch_size=64, shuffle=False)
# 定义CNN网络结构
class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.conv1 = nn.Conv2d(in_channels=1, out_channels=32, kernel_size=3, padding=1)
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
        self.conv2 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, padding=1)
        self.fc1 = nn.Linear(64 * 7 * 7, 128)
        self.fc2 = nn.Linear(128, 10)
        self.relu = nn.ReLU()
        self.dropout = nn.Dropout(0.25)

    def forward(self, x):
        x = self.relu(self.conv1(x))
        x = self.pool(x)
        x = self.relu(self.conv2(x))
        x = self.pool(x)
        x = x.view(-1, 64 * 7 * 7)  # 展平
        x = self.dropout(self.relu(self.fc1(x)))
        x = self.fc2(x)
        return x


# 实例化CNN模型、损失函数和优化器
model = CNN()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 训练模型
def train(model, train_loader, criterion, optimizer, epochs=5):
    model.train()
    for epoch in range(epochs):
        running_loss = 0.0
        for images, labels in train_loader:
            optimizer.zero_grad()
            outputs = model(images)
            loss = criterion(outputs, labels)
            loss.backward()
            optimizer.step()
            running_loss += loss.item()

        print(f"Epoch {epoch + 1}/{epochs}, Loss: {running_loss / len(train_loader):.4f}")

# 测试模型
def test(model, test_loader):
    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()
    accuracy = 100 * correct / total
    print(f'Test Accuracy: {accuracy:.2f}%')

# 训练和测试CNN模型
train(model, train_loader, criterion, optimizer, epochs=5)
test(model, test_loader)

2.网络的分类结果

(1)Bp神经网络
在这里插入图片描述
(2)卷积神经网络
在这里插入图片描述

3.总结实验心得体会。

在本次实验中,我们使用了BP神经网络(反向传播网络)和卷积神经网络(CNN)分别对MNIST手写数字数据集进行了分类任务。BP网络在浅层结构下分类效果一般,容易出现过拟合,需要较长训练时间才能达到较好效果。而CNN在处理图像数据方面具有明显优势,通过卷积层提取局部特征、池化层缩小特征尺寸,模型学习到更多图像的空间信息,提高了分类准确度。实验结果显示,CNN在MNIST分类任务中明显优于BP网络,体现了卷积网络在图像识别中的高效性和优越性。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐