资源下载地址:https://download.csdn.net/download/sheziqiong/86790047
资源下载地址:https://download.csdn.net/download/sheziqiong/86790047
目录
基于Python的BP网络实现手写数字识别 1
一、实验目的 1
二、实验过程与结果 1
- 获取MNIST数据 1
- 构建BP神经网络 2
- 训练构建的BP神经网络 3
- 测试BP网络 4
三、结果分析与实验结论 6
四、收获、体会及建议 6
由测试结果可以发现,模型基本上可以准确识别大部分的手写数字,只有个别的数字由于特征不是非常明显甚至兼有其他数字的特征,因此被错误识别。总的来说,模型的训练效果还是不错的。
三、结果分析与实验结论
通过实验可以发现,使用BP网络进行训练识别手写数字在一开始基本是随机识别,但是在对整个数据集进行多次训练之后,在训练集和测试集上的准确率都能达到较高的水准并且可以看到,在前几次迭代训练的结果中,损失函数下降的非常快,准确率也快速上升。
此外,两种模型测试集上的损失函数总体上一直在下降,没有出现上升而准确率总体上一直在上升没有出现下降。因此模型并没有出现过拟合的现象,还可以继续迭代进行训练。
对比两种模型可以看到,基于CNN的BP网络的准确率均高于全连接层的BP神经网络,有较好的训练效果。但是CNN训练的时间相较于全连接层较长,在数据较多时可能略显吃力。
四、收获、体会及建议
通过手写数字识别的实验,我对BP神经网络的原理和结果有了更加深刻的了解和认识;学习了如何使用深度学习框架加载数据集并进行处理和训练;对搭建神经网络的方法和神经网络相关的保存、评估等方法也有所认识。此外,还对比了两种不同的BP神经网络,本文转载自http://www.biyezuopin.vip/onews.asp?id=15396,总的收获还是非常大的。
from read_and_plot_func import *
import torch
import torch.nn as nn
import torchvision
import torch.utils.data.dataloader as dataloader
import numpy as np
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)
def data_tf(image):
"""
数据归一化并将维度展开:[28,28]->[1,784]
:param image:
:return:
"""
img = np.array(image, dtype='float32') / 255
# img = (img - 0.5) / 0.5
img = img.reshape((-1,))
img = torch.from_numpy(img)
return img
def data_reader(path, train_size, test_size):
"""
加载MNIST数据集,分训练集和测试集返回标签、数据
:param path:
:return:
"""
train_set = torchvision.datasets.MNIST(
root=path, train=True,
transform=data_tf, download=True
)
train_loader = dataloader.DataLoader(
dataset=train_set, shuffle=True, batch_size=train_size
)
"""
dataloader返回(images,labels)
其中,
images维度:[batch_size,1,28,28]->[batch_size, 28*28]
labels:[batch_size],即和图片对应
shuffle: 打乱数据
"""
# print(train_set)
test_set = torchvision.datasets.MNIST(
root=path, train=False,
transform=data_tf, download=True
)
test_loader = dataloader.DataLoader(
dataset=test_set, shuffle=False, batch_size=test_size
)
# print(test_set)
# firstImg, firstImg_label = train_set[0]
# print(firstImg.shape)
# print(firstImg_label)
# batch_images, batch_label = next(iter(train_loader))
# print(batch_images.shape)
# print(batch_label.shape)
return train_loader, test_loader
class BPNNMdel(torch.nn.Module):
def __init__(self):
super(BPNNMdel, self).__init__()
self.layer1 = nn.Sequential(nn.Linear(784, 400), nn.ReLU())
self.layer2 = nn.Sequential(nn.Linear(400, 200), nn.ReLU())
self.layer3 = nn.Sequential(nn.Linear(200, 100), nn.ReLU())
self.layer4 = nn.Sequential(nn.Linear(100, 10)) # 输出维度必须大于标签的维度,即最好大于分类数,否则报错
def forward(self, img):
img = self.layer1(img)
img = self.layer2(img)
img = self.layer3(img)
img = self.layer4(img)
return img
def train_model(train_data, test_data, iterations, model, model_criterion, model_optimizer):
"""
模型训练和评估函数,完成模型训练的整个过程
:param train_data: 训练用数据集
:param test_data: 测试用数据集
:param iterations: 训练迭代的次数
:param model: 神经网络模型
:param model_criterion: 损失函数
:param model_optimizer: 反向传播优化函数
:return:
"""
model_train_losses = []
model_train_acces = []
model_eval_losses = []
model_eval_acces = []
for epoch in range(iterations):
# 网络训练
train_loss = 0
train_acc = 0
model.train()
for i, data in enumerate(train_data):
img, label = data
img = img.to(device)
label = label.to(device)
out = model(img)
loss = model_criterion(out, label)
model_optimizer.zero_grad()
loss.backward()
model_optimizer.step()
train_loss += loss.item()
_, pred = out.max(1)
num_correct = (pred == label).sum().item()
acc = num_correct / img.shape[0]
train_acc += acc
model_train_losses.append(train_loss / len(train_data))
model_train_acces.append(train_acc / len(train_data))
# 网络评估
eval_loss = 0
eval_acc = 0
model.eval()
with torch.no_grad():
for i, data in enumerate(test_data):
img, label = data
img = img.to(device)
label = label.to(device)
out = model(img)
loss = model_criterion(out, label)
eval_loss += loss.item()
_, pred = out.max(1)
num_correct = (pred == label).sum().item()
acc = num_correct / img.shape[0]
eval_acc += acc
model_eval_losses.append(eval_loss / len(test_data))
model_eval_acces.append(eval_acc / len(test_data))
print('epoch: {}, Train Loss: {:.6f}, Train Acc: {:.6f}, Eval Loss: {:.6f}, Eval Acc: {:.6f}'
.format(epoch+1, train_loss / len(train_data), train_acc / len(train_data),
eval_loss / len(test_data), eval_acc / len(test_data)))
return model_train_losses, model_train_acces, model_eval_losses, model_eval_acces
if __name__ == "__main__":
# 获取数据
train_load, test_load = data_reader('./data', train_size=64, test_size=64) # 使用torchvision库函数读取数据
train, test = load_data('./data/self') # 从本地读取数据,暂时没有使用
# for i, data in enumerate(train_load):
# images, labels = data
# print(images)
# print(labels)
# print(i)
# x_train, y_train = train
# print(y_train[5])
# 构建网络、损失函数
epochs = 25 # 迭代次数
learning_rate = 0.01 # 学习率
Model = BPNNMdel()
Model = Model.to(device)
print(Model)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(Model.parameters(), lr=learning_rate)
# 训练
train_ID = 're'
train_losses, train_acces, eval_losses, eval_acces = train_model(
train_data=train_load, test_data=test_load, iterations=epochs,
model=Model, model_criterion=criterion, model_optimizer=optimizer
)
state = {
'model': Model.state_dict(),
'optimizer': optimizer.state_dict()
}
torch.save(state, './save_model/BP_%s.pth' % train_ID)
# 绘图
plot_all(train_losses, train_acces, eval_losses, eval_acces, 'BP')
资源下载地址:https://download.csdn.net/download/sheziqiong/86790047
资源下载地址:https://download.csdn.net/download/sheziqiong/86790047