基于BP神经网络的图像分类
1 数据集
本次BP神经网络分类实验所用数据集为MNIST手写数据集。
MNIST 数据集来自美国国家标准与技术研究所, National Institute of Standards and Technology (NIST)。训练集 (training set) 由来自 250 个不同人的手写的数字构成, 其中 50% 是高中学生, 50% 来自人口普查局 (the Census Bureau) 的工作人员。测试集(test set) 也是同样比例的手写数字数据。
训练数据集包含60000个样本, 测试数据集包含10000样本。在 MNIST 数据集中,每张图片由28×28个像素点构成, 每个像素点用一个灰度值表示。使用时,将28×28的像素展开成一个维度为784的一维的向量, 向量中的值对应图片中的像素值。此外,还有一个标签数组,对应每张图片所属的手写数字类别(整数0-9)。
本次实验基于Pytorch框架,使用Pytorch自带工具包可完成MNIST数据集的下载及预处理。下图所示代码分别完成了训练数据和测试数据的下载,预处理及加载。
#1.Load the train datasets and test datasets
train_transformations = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))
])
train_set = MNIST(root="./data", train=True, transform=train_transformations, download=True)
train_loader = DataLoader(train_set,batch_size=128,shuffle=True,num_workers=4)
test_transformations = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))
])
test_set = MNIST(root="./data", train=False, transform=test_transformations, download=True)
test_loader = DataLoader(test_set,batch_size=128,shuffle=False,num_workers=0)
观察MNIST单个样本数据时,发现其中的像素值范围在(0,1)之间,说明已经被整除256,后续无需再重复这一操作。先将28×28的二维数据转换成张量Tensor的形式,再进行标准化处理,将数据映射到(-1,1)之间,最后将数据进行批处理,每批包含128(2的倍数,方便GPU处理)个样本,完成数据的加载。加载时设置打乱训练样本的顺序,不打乱测试样本的顺序。
2 分类网络设计
本次分类BP神经网络共有5层,包括1个输入层,3个隐藏层和一个输出层。层与层之间均采用全连接的形式。输入层有784个节点,对应MNIST单个样本的像素值总数;隐藏层的节点数分别为1024,1024,2048;输出层共有10个节点,用于分类,输出结果为(0-9)的预测概率。详细网络结构图如下所示。
3 训练过程
训练过程主要分为以下四个步骤,分别为:
加载训练数据集和测试数据集;
初始化模型;
定义优化器和损失函数;
训练模型及保存权重参数;
下面对每个步骤详细展开介绍。
3.1 加载训练数据集和测试数据集
数据集的加载包括训练数据集和测试数据集的加载,训练数据集用于训练模型,测试数据集用于训练过程中对模型的性能进行实时监测。本次所用数据集为MNIST书写数字数据集,包括60000个训练样本和10000个测试样本,具体加载方式在第一章已详细介绍。
3.2 初始化模型
本次分类BP神经网络共有5层,包括1个输入层,3个隐藏层和一个输出层。层与层之间均采用全连接的形式。代码实现时,只需要实现3个隐藏层和1个输出层的设计即可。
每个隐藏层都由一个线性全连接层和一个激活函数构成,为了方便起见,自定义一个隐藏层模块,主要是定义线性全连接层的输入和输出节点数,激活函数的选取,实现过程如下所示。
# Build the neural network
class Unit(nn.Module): def __init__(self, in_features, out_features): super(Unit, self).__init__()self.fc=nn.Linear(in_features, out_features, True) self.relu = nn.ReLU()def forward(self, input): output = self.fc(input) output = self.relu(output) return output
接着,调用上面定义好的隐藏层模块实现整个网络的设计。将3个隐藏层根据其输入和输出节点数一一定义出来,再将这3个隐藏层组合成一个小网络。然后根据分类的类别数定义出输出层,也就是最后一个全连接层。最后在前向传播函数中,将这些层的输入输出拼接起来,实现整个网络的结构设计。代码实现如下所示。
class SimpleNet(nn.Module): def __init__(self, num_classes=10): super(SimpleNet, self).__init__()self.unit1 = Unit(in_features=784,out_features=1024) self.unit2 = Unit(in_features=1024, out_features=1024) self.unit3 = Unit(in_features=1024, out_features=2048) self.net = nn.Sequential(self.unit1, self.unit2, self.unit3) self.fc = nn.Linear(in_features=2048,out_features=num_classes)def forward(self, input): output = self.net(input) output = self.fc(output) return output
完成网络结构设计后,通过实例化这个类来初始化训练模型。为了加速训练过程,选择在GPU上进行模型的训练和测试,具体过程如下所示。
#2.Initialize model
cuda_avail = torch.cuda.is_available()
model = SimpleNet(num_classes=10)
cuda_avail = torch.cuda.is_available()
if cuda_avail: model.cuda()
3.3 定义优化器和损失函数
本次实验选用Adam优化器,它结合AdaGrad和RMSProp两种优化算法的优点。对梯度的一阶矩估计(First Moment Estimation,即梯度的均值)和二阶矩估计(Second Moment Estimation,即梯度的未中心化的方差)进行综合考虑,计算出更新步长。设置初始学习率为0.001,权重衰减值为0.0001。
损失函数选用交叉熵损失函数,它是一种专门用于处理分类问题的损失函数。
#3. Define the optimizer and loss function
optimizer = Adam(model.parameters(), lr=0.001, weight_decay=0.0001)
loss_fn = nn.CrossEntropyLoss()
3.4 训练模型及保存权重参数
定义训练过程,遍历整个训练集100轮。每遍历一轮训练集,根据训练轮次,不断调整学习率的大小,并计算模型在测试集上的准确率,若本轮训练后的测试准确率高于之前轮次,则保存本轮训练得到的权重参数。具体实现如下所示。
#4.Training
num_epochs = 100
best_acc = 0.0
for epoch in range(num_epochs): train_acc = 0.0 train_loss = 0.0 train_acc,train_loss = train(model,train_acc,train_loss,train_loader,optimizer,loss_fn,cuda_avail) adjust_learning_rate(optimizer, epoch) test_acc = test(model,test_loader,cuda_avail) if test_acc > best_acc: save_models(model,epoch) best_acc = test_acc print("Epoch {}, Train Accuracy: {} , TrainLoss: {} , Test Accuracy: {}".format( epoch, train_acc, train_loss, test_acc))
训练过程如下所示。每一轮次训练结束均会打印训练精度,训练损失值和测试精度。
4 完整代码
import torch
import torch.nn as nn
import os
from torch.autograd import Variable
from torchvision.datasets import MNIST
from torchvision.transforms import transforms
from torch.utils.data import DataLoader
from torch.optim import Adamimport numpy
#Set GPU id
os.environ["CUDA_VISIBLE_DEVICES"] = "1"
# Build the neural network
class Unit(nn.Module): def __init__(self, in_features, out_features): super(Unit, self).__init__()self.fc=nn.Linear(in_features, out_features, True) self.relu = nn.ReLU()def forward(self, input): output = self.fc(input) output = self.relu(output) return outputclass SimpleNet(nn.Module): def __init__(self, num_classes=10): super(SimpleNet, self).__init__()self.unit1 = Unit(in_features=784,out_features=1024) self.unit2 = Unit(in_features=1024, out_features=1024) self.unit3 = Unit(in_features=1024, out_features=2048) self.net = nn.Sequential(self.unit1, self.unit2, self.unit3) self.fc = nn.Linear(in_features=2048,out_features=num_classes)def forward(self, input): output = self.net(input) output = self.fc(output) return output# Create a learning rate adjustment function that divides the learning rate by 10 every 30 epochs
def adjust_learning_rate(optimizer, epoch): lr = 0.001 if epoch > 180: lr = lr / 1000000 elif epoch > 150: lr = lr / 100000 elif epoch > 120: lr = lr / 10000 elif epoch > 90: lr = lr / 1000 elif epoch > 60: lr = lr / 100 elif epoch > 30: lr = lr / 10 for param_group in optimizer.param_groups: param_group["lr"] = lr# Training process
def train(model,train_acc,train_loss,train_loader,optimizer,loss_fn,cuda_avail=True): model.train() for i, (images, labels) in enumerate(train_loader): if cuda_avail: images = Variable(images.cuda()) images = images.reshape(-1,784) labels = Variable(labels.cuda()) optimizer.zero_grad() outputs = model(images) loss = loss_fn(outputs, labels) loss.backward() optimizer.step() train_loss += loss.cpu().data.numpy() * images.size(0) _, prediction = torch.max(outputs.data, 1) train_acc += torch.sum(prediction == labels.data)train_acc = train_acc / 60000 train_loss = train_loss / 60000 return train_acc, train_loss# Test the model while training
def test(model,test_loader,cuda_avail=True): model.eval() test_acc = 0.0 for i, (images, labels) in enumerate(test_loader): if cuda_avail: images = Variable(images.cuda()) images = images.reshape(-1,784) labels = Variable(labels.cuda())# Predict classes using images from the test set outputs = model(images) _, prediction = torch.max(outputs.data, 1) test_acc += torch.sum(prediction == labels.data)# Compute the average acc and loss over all 10000 test images test_acc = test_acc / 10000return test_acc# Save the weights
def save_models(model,epoch): torch.save(model.state_dict(), "MNIST_model_{}.model".format(epoch)) print("Chekcpoint saved")def main():
#1.Load the train datasets and test datasets train_transformations = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,)) ]) train_set = MNIST(root="./data", train=True, transform=train_transformations, download=True) train_loader = DataLoader(train_set,batch_size=128,shuffle=True,num_workers=4) test_transformations = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,)) ]) test_set = MNIST(root="./data", train=False, transform=test_transformations, download=True) test_loader = DataLoader(test_set,batch_size=128,shuffle=False,num_workers=0)#2.Initialize model cuda_avail = torch.cuda.is_available() model = SimpleNet(num_classes=10) cuda_avail = torch.cuda.is_available() if cuda_avail: model.cuda()#3. Define the optimizer and loss function optimizer = Adam(model.parameters(), lr=0.001, weight_decay=0.0001) loss_fn = nn.CrossEntropyLoss()#4.Training num_epochs = 100 best_acc = 0.0 for epoch in range(num_epochs): train_acc = 0.0 train_loss = 0.0 train_acc,train_loss = train(model,train_acc,train_loss,train_loader, optimizer,loss_fn,cuda_avail) adjust_learning_rate(optimizer, epoch) test_acc = test(model,test_loader,cuda_avail) if test_acc > best_acc: save_models(model,epoch) best_acc = test_acc print("Epoch {}, Train Accuracy: {} , TrainLoss: {} , Test Accuracy: {}".format( epoch, train_acc, train_loss, test_acc))if __name__ == "__main__": main()
基于BP神经网络的图像分类相关推荐
- 《MATLAB 神经网络43个案例分析》:第25章 基于MIV的神经网络变量筛选----基于BP神经网络的变量筛选
<MATLAB 神经网络43个案例分析>:第25章 基于MIV的神经网络变量筛选----基于BP神经网络的变量筛选 1. 前言 2. MATLAB 仿真示例 3. 小结 1. 前言 < ...
- 基于BP神经网络算法的性别识别
目录 基于 BP 神经网络算法的性别识别 1 目录 1 1.背景介绍 2 2. OpenCV 的介绍 3 3.安装 OpenCV 4 4. BP 神经网络算法介绍和实践 4 4.1 BP 神经网络结构 ...
- 【交通标志识别】基于BP神经网络实现交通标志识别matlab代码
1 简介 近年来,交通标志识别在车辆视觉导航系统中是一个热门研究课题.为了安全驾驶和高效运输,交通部门在公路道路上设置了各类重要的交通标志,以提醒司机和行人有关道路交通信息,如指示标志.警告标志.禁止 ...
- MATLAB实现基于BP神经网络的手写数字识别+GUI界面+mnist数据集测试
文章目录 MATLAB实现基于BP神经网络的手写数字识别+GUI界面+mnist数据集测试 一.题目要求 二.完整的目录结构说明 三.Mnist数据集及数据格式转换 四.BP神经网络相关知识 4.1 ...
- 基于BP神经网络的PID控制,神经网络算法pid控制
基于BP神经网络的PID控制器设计 参考一下刘金琨的<先进PID控制>这本书. 例子:被控对象yout(k)=a(k)yout(k-1)/(1+yout(k-1)^2)+u(k_1)其中a ...
- 基于bp神经网络的pid算法,神经网络pid控制器设计
基于BP神经网络的PID控制器设计 参考一下刘金琨的<先进PID控制>这本书. 例子:被控对象yout(k)=a(k)yout(k-1)/(1+yout(k-1)^2)+u(k_1)其中a ...
- 基于BP神经网络的车牌识别系统的设计
一.基本原理概述 基于BP神经网络的的汽车牌照识别系统的处理过程分为预处理.边缘提取.车牌定位.字符分割.字符识别五大模块.具体涉及以下几个过程: ① 原始车牌图像:由数码相机或其他扫描装置拍摄到的车 ...
- 基于bp神经网络的pid控制,pid神经网络什么原理
关于基于神经网络的PID液位控制用MATLAB怎么编程啊?求高手指点!!!! . 其实只需要PID参数能够顺利确定就行了,这里有个程序,你试试看closeallclearallclctic%初始化x= ...
- 基于bp神经网络的pid算法,基于单神经元的pid控制
基于BP神经网络的PID控制器设计 参考一下刘金琨的<先进PID控制>这本书. 例子:被控对象yout(k)=a(k)yout(k-1)/(1+yout(k-1)^2)+u(k_1)其中a ...
最新文章
- ef mysql 插件_EF Core 插件 —— ToSql
- HashMap和LinkedHashMap的区别
- iOS网络开发之:NSURLConnection
- Nginx-05:Nginx配置实例之反向代理2
- webpack 的基本使用—— 创建列表隔行变色项目||在项目中安装和配置 webpack
- Spring Security 玩出花!两种方式 DIY 登录
- 5.单行函数,多行函数,字符函数,数字函数,日期函数,数据类型转换,数字和字符串转换,通用函数(case和decode)
- Finacial professional
- 基于RBF简单的matlab手写识别
- jsx怎么往js里传参数_在vue中使用jsx语法的使用方法
- [转]项目管理有感之一 沟通
- 入门 | egg.js 入门之egg-jwt
- 圆环和环形是一样的吗_Excel不知道还可以这样做圆环图
- STM32 J-LINK、ST-Link、CMSIS-DAP
- Eclipse alt+/语法不提示的解决方法
- ADO.Net之SqlConnection、 Sqlcommand的应用
- 软件需求工程 高校教学平台 项目总体计划
- php gd2扩展_PHP如何打开gd2扩展库
- 5.android系统裁剪
- php自动化营销推广引流源码,PHP自动化售货发卡网源码