基于matlab BP神经网络的手写数字识别

摘要 本文实现了基于MATLAB关于神经网络的手写数字识别算法的设计过程,采用神经网络中反向传播神经网络(即BP神经网络)对手写数字的识别,由MATLAB对图片进行读入、灰度化以及二值化等处理,通过神经网络进行训练和测试。实验证明:该神经网络对手写数字的识别可以达到95.65%。

关键词 手写数字识别;BP神经网络;MATLAB语言

1 绪论

1.1 图像识别的提出

图像识别在信息技术发达的今天已经占据了很重要的地位,在我们实际生活中也有很多应用。所谓的图像识别,就是指通过计算机对图像进行相应的处理、分析,来达到识别不同模型的目标和任务的一种技术。对于它的提出,简单的来说,它的发展经历了三个阶段:第一个是文字识别 、第二个是数字图像处理与识别、第三个是物体识别。第一种相对来说比较简单,它的研究是从1950年开始的,一般情况是识别字母、符号和数字,无论是印刷体识别还是手写体识别,它的应用都非常广泛,但是也伴随着,这个识别的过程会更加的耗时、费力,无论是人力还是物力,都会有很大的损失;第二种就是我们所说的数字图像处理与识别,在图片的识别过程中,图片识别会有一定的误差,也会带来小小的麻烦;第三就是物体识别,而物体的识别主要指的是:在三维世界中,对于个体、环境的感知和认识进行识别,这不同于二维世界的认知,相对来说是更高级的计算机图像识别,它是以二维世界中对数字图像和模拟图像处理的办法为依据,进行更高一级的,并且结合了现代人工智能技术等学科的研究目标,研究成果已经被广泛的应用在各种工业探测机器人上,为人们的安全提供了很大的帮助。

1.2 图像识别的现状与发展趋势

随着网络的发达、电子的信息化,图像识别的应用已经非常广泛,而主要的研究工作也包括各行各业,整理以下几点对其应用的广泛度进行说明:

⒈在生物学中,对生物的原型进行研究。从生物的脑细胞结构、物体解剖等其他科学研究的方向对生物的体系结构、神经结构、神经细胞组织等生物的原型结构及其功能机理进行研究,增强对生物学更加全面的理解。

⒉在实际应用中,建立我们需要的理论模型。根据需要应用的信息在生物学中的应用,建立需要的生物原型,也可以建立类似神经元、神经网络这样不可见的理论模型,以便可以让其更加有效的应用在生活中。建立我们生活中不能直观表现的事物模型,以便我们可以更方便的、更直观的理解事物的本质。

⒊在信息时代中,建立网络模型以及算法研究。就是通过上面所说的,建立相应的理论模型,在这个基础上加以理解,建立我们所需要的网络模型,实现计算机应用,主要应用在网络学习算法的研究,这方面的研究工作也被人们称为技术模型研究。

⒋信息时代的发展,让我们在生活中有很多的应用,例如:完成某种函数图像的绘制以及对其变化的形式进行分析、对图片信号的处理、模式识别等功能,建立需要的应用系统、制造机器人等等。

通过上面的说明,也就是说从开始根据生物学原理的应用,直到建立需要的神经网络模型,最后应用到图像识别当中,可以看出其模型的建立是在生活中实例的基础上,其可靠性和准确性是显而易见的,这样就大大的增加了可信度,与此同时,也减少了工作中不必要的麻烦与困扰。而在网络信息发达的今天,人类在基本粒子、宇宙空间、生命起源等科学领域方面都已经显现出很高的兴趣度,而这其中难免会有图像提取后的处理工作,所以图像识别的应用就会越来越广泛。

2 BP神经网络的概述

反向传播(Back-Propagation,BP)学习算法简称BP算法,采用BP算法的前馈型神经网络简称BP网络。BP网络是多层感知器的一种,它具备多层感知器的特点,同时也有自己的特点。多层感知器包括输入层、隐藏层、输出层,其中隐藏层可以有多个,而我们BP网络中隐藏层只有一个,其简单构造如图所示:



e507fa2571f3c371d3ac14f4e7f121cd.png
图1 多层感知器结构图



而我们用到的BP网络中的具体信号流如图所示,它有一个反向传播的过程,这也是对传播进行调整,使精确度更高的一种办法。如图所示,其中有两种信号流通:


3cee902069d17b4b0e26ede80794d36a.png
图2 多层感知器的信号流



第一:函数信号

简单来说就是信号进入输入层,然后通过隐藏层到达输入层,通过输出层输出所得值,就可以完成一个函数信号。

第二:误差信号

误差信号就是在逆向的传播的过程中传输的信号。其中,有两个重要参数。一个是函数信号即sigmoid函数,还有一个就是权值的梯度运算即梯度向量。(注:sigmoid函数、权重的修正函数,如图所示。)

1551bf0d6bf7c0b37ed5bef42ed977ef.png
(1)

cc2dd65439ccd8cf1b0e626b54c0654e.png
(2)

通过对两个参数的调整,完成整个算法的应用。

3 手写体数字识别的实现过程

3.1 整体线路图

整体流程图如图3所示


7cefc08f0b0302ffb46e91b5c35491b9.png
图3 整体流程图



部分文件调用流程图如图4所示:

8ce17b84423980566458c4f7150823a0.png
图4 整体流程图


3.2 算法流程

图片识别要经过训练好的模型来提取我们要得到的手写数字,而模型是经过多次的训练得到的,为了提高程序的准确度、增加可信度的一种数据集,所以,程序的开始,我们设计了多个可用的数据,来训练我们的神经网络。如图3所示,一开始可视化我们的手写体测试数据,每个数字都保存在20*20的像素里,其中设置25个隐藏单位,0到9共10个数字标签。将我们需要的参数保存到需要的函数中,也就是我们用到的θ1和θ2中。也就是保存在我们用的.mat文件中的数据,如图5所示。


ffc7e877767bc03f6ff07ca13a38305e.png



1f23f7619ff9254117f45dddeb62d7a7.png



注:其中,.mat文件中保存的是二位数组,用来保存我们测试需要的数据。

其次,使用前馈神经网络,当参数λ=0时,运行nnCostFunction.m文件,而文件再调用sigmoidGradient.m、sigmoid.m两个参数文件(其中,sigmoid-

GradiEnt.m文件,就是对sigmoid函数的求导,为得就是得到sigmoid函数的梯度值,以便更好的了解数值变化的程度。而sigmoid.m文件中保存的就是sigmoid函数)。运行结果是损失函数J=0.287629。其中也会实现损失函数的正规化和梯度。而为了检测它的正确性,又使λ=1进行测试,调式,看结果是否符合要求,来检测正确性,得到的结果如图8所示,也是通过两组数据的对比,让我们更加清晰的体会它的不同之处。


29089398f30621e678266664360535f1.png


图7 实验数据对比图

68989e89e49d9ecf1b5b701f3629a5de.png

第三,sigmoid函数的运行。运行文件ex4.m文件中,提到函数g = sig-

moidGradient(),是指调用sigmoidGradient.m文件,文件中写了sigmoid函数的梯度表达式,而其中的g(z)函数,是sigmoid函数的方程式,

3c3f1750f6e005c16aff9c073759b286.png

通过对文件的调用,输入测试值1、-0.5、0、0.5、1,可以得到输出的梯度数,而当z=0时,可以得到导数值为0.25。越接近于0,它的变化越明显。sigmoid函数梯度指的是标量场中变化的方向,而梯度值的大小就是用来表示变化的大小,简单来说就是我们数学中的斜率,而这么说也只是为了让人们更好的接受。

对于sigmoid函数的测试,我们用一组数据对它进行测试,得到的结果如图 8所示:


e5cd46bc6a39dbead52640b1b0f2a2bd.png


图8 梯度函数测试值

初始化参数(权重W文件的调用说明),文件中使用randInitializeWei-

ghts.m文件,来初始化θ1,θ2,产生随机变量,为下边的调用起到很重要的作用。上文BP神经网络中也曾提到过,权重值是整个过程中很重要的一个参数。而我们的randInitializeWeights.m文件中,也对其进行了新的定义,给定一个较小的ε值,计算出新的W值。这个文件的作用是为了让我们打破对称而训练神经网络。其中初始化W的一部分代码如图所示:


c0a038b63012ba6412a5f247e208f7f1.png
图9 初始化权重值


其中,L_out,L_in是ex4.m文件中传输的数据。

最后,就是这个程序最重要的部分,神经网络的应用。而神经网络的形成与训练又被分为以下几个部分来实现:初始化神经网络、实现反向传播、实现正则化、训练NN。而具体的函数调用部分可以从图3代码调用流程图看见,初始化神经网络用randInitializeWeights.m文件进行数据初始化。而我们的显示界面并没有显示初始化以后的数据,这部分是不可见的。通过文件调用图可见,实现反向传播和正规化都是运用了同一个文件,也就是说,内部调用的文件也是相同的,只是λ值不同,实现反向传播时λ=0,写在函数内部,进行数据判断,正则化则定义好了λ值,即λ=3,可以看到,因为λ值得不同,运行结果的输出情况也有所不同。在checkNNGradients.m文件中,还引用了三个.m文件。运行后得到两列相似的数列,如图10所示。


0e5ea891d3daad36f9c58f7e2c3ed312.png
图10 检查神经网络



这就是用于检测神经网络正确性的测试数据,通过测试数据得到相对偏差,即数字输出是产生的偏差值。这个数值小于1e-9,则可以使用于数字识别的过程中,得到的结果如图11所示,可以看出,相对偏差小于要求值,则可以进行接下来的运行。


bea84f5afebe926c68996766410bf72a.png



79f6c6152511be0c493eed4387e009c6.png
图11相对偏差



文件中通过对nnCostFunction.m文件的调用,可得到相应的测试数据,如图12所示:


efca1265a85ebc8abe241af8ae44ddd0.png
图12 成本函数的调试参数



训练神经网络,给出训练循环次数,本次循环次数为50,调用fmincg.m文件。得到下列一组训练次数为50的数字,得到如图13所示。



7185c4abf178851f7806f5a445db7156.png


图13 神经网络的训练

通过这整个的实验,我们就可以得到自己想要的数据训练集。

3.3 图像预处理

我们都知道,手写体的图片底色可以有很多种,而我们要做的就是将图片处理成我们需要的大小样子,放到训练集里运行,以便得到我们需要的图片信息。这整个过程又会被分为很多小的地方。过程可以大致分为以下几个步骤:


0047047a93acfcc5257fe54fd40175ff.png


其中,所需要的程序代码部分为:

1、引入图片:imread函数,可以引用多种类型的图片。不会因为图片的格式不同而影响程序的运行。

2、用matlab中使用rgb2gray函数将彩色图片转化为灰度图像。

3、Graythresh函数是将图片阈值法,将灰度图片转化为索引图。

4、im2bw函数将索引图片二值化

5、用边缘切割算法,对图片进行切割细化。

最后得到的图片矩阵就是我们用到的样式,如果整个过程你还想区别不同样式的图片有什么变化,还可以用图片显示函数imshow进行显示,可以更加详细、明确地观察图片的变化。

3.4 结果分析

结果由图片引入到程序中,经过神经网络的训练识别,成为数字显示在MATLAB的command Window工作区中。显示准确度以及数字结果。如图所示:


88e0720f8fd93fc4e69a1d73ac56c23f.png


图14 准确度显示

  • 1
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
以下是一个示例的matlabbp神经网络手写数字识别程序: 首先,需要准备数据。这里使用MNIST数据集,包含60000个手写数字训练样本和10000个测试样本。可以从网上下载并解压缩到本地路径下,例如: train_images_path = './mnist/train-images-idx3-ubyte'; train_labels_path = './mnist/train-labels-idx1-ubyte'; test_images_path = './mnist/t10k-images-idx3-ubyte'; test_labels_path = './mnist/t10k-labels-idx1-ubyte'; 然后,读取数据到matlab中: train_images = loadMNISTImages(train_images_path)'; train_labels = loadMNISTLabels(train_labels_path); test_images = loadMNISTImages(test_images_path)'; test_labels = loadMNISTLabels(test_labels_path); 接下来,先定义神经网络的结构。这里使用3层全连接神经网络,输入层有784个神经元(即28x28的图片展开成一维向量),隐藏层有50个神经元,输出层有10个神经元(分别表示0-9这10个数字): input_layer_size = 784; hidden_layer_size = 50; output_layer_size = 10; 然后,初始化神经网络的权重和偏置: W1 = randn(input_layer_size, hidden_layer_size) / sqrt(input_layer_size); b1 = zeros(1, hidden_layer_size); W2 = randn(hidden_layer_size, output_layer_size) / sqrt(hidden_layer_size); b2 = zeros(1, output_layer_size); 接着,定义损失函数。这里使用交叉熵损失函数: loss_fn = @(y_hat, y) -mean(sum(y .* log(y_hat), 2)); 然后,定义优化器。这里使用随机梯度下降(SGD)算法: learning_rate = 0.1; batch_size = 32; num_epochs = 10; num_batches = ceil(size(train_images, 1) / batch_size); for epoch = 1:num_epochs shuffle_idx = randperm(size(train_images, 1)); train_images = train_images(shuffle_idx, :); train_labels = train_labels(shuffle_idx); for batch = 1:num_batches start_idx = (batch - 1) * batch_size + 1; end_idx = min(batch * batch_size, size(train_images, 1)); batch_images = train_images(start_idx:end_idx, :); batch_labels = train_labels(start_idx:end_idx, :); [y_hat, z] = forward_propagation(batch_images, W1, b1, W2, b2); loss = loss_fn(y_hat, batch_labels); [dW1, db1, dW2, db2] = backward_propagation(batch_images, batch_labels, y_hat, z, W2); W1 = W1 - learning_rate * dW1; b1 = b1 - learning_rate * db1; W2 = W2 - learning_rate * dW2; b2 = b2 - learning_rate * db2; end [y_hat, ~] = forward_propagation(test_images, W1, b1, W2, b2); [~, predicted_labels] = max(y_hat, [], 2); accuracy = sum(predicted_labels == test_labels) / length(test_labels); fprintf('Epoch %d, loss = %f, accuracy = %f\n', epoch, loss, accuracy); end 最后,定义前向传播和反向传播函数: function [y_hat, z] = forward_propagation(X, W1, b1, W2, b2) z = X * W1 + b1; a = relu(z); y_hat = softmax(a * W2 + b2); end function [dW1, db1, dW2, db2] = backward_propagation(X, y, y_hat, z, W2) delta2 = y_hat - y; dW2 = z' * delta2; db2 = mean(delta2, 1); delta1 = delta2 * W2' .* relu_gradient(z); dW1 = X' * delta1; db1 = mean(delta1, 1); end 其中,relu和softmax分别是激活函数,relu_gradient是relu函数的导数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

你的matlab大师

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

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

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

打赏作者

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

抵扣说明:

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

余额充值