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

BP神经网络手写数字识别的matlab实现

BP神经网络原理

BP神经网络是一种按误差逆传播算法训练的多层前馈网络。标准的前馈神经网络一般包括三层神经,即输入层,隐含层,输出层,每层神经包含的神经元个数不一。它的学习规则是使用最速下降法,通过反向传播来不断调整网络的权值和阈值,使网络的误差平方和最小。网络上有许多BP神经网络的原理,比较通俗易懂,读者可以自行搜索。这里推荐一篇BP神经网络权值迭代过程的博文和手写BP神经网络权值迭代公式的推导博文
链接1: BP神经网络权值迭代的直观过程.
链接2: BP神经网络权值迭代公式.

数据集选择

本次实验采用mmist数据集对搭建的网络进行训练和测试,下载网站如下:
链接3: MNIST数据集.
该数字集包含60000张手写数字的照片的训练集和包含10000张手写数字照片的测试集。每张图片为28*28像素,带有标签,满足训练网络所需要求。

实验代码

由于代码之中注释比较全面,所以直接上代码。

读取image数据

function y=loadmnistdata()
    fp = fopen('文件保存路径', 'r');%打开文件句柄,路径之中不可以有汉字,否则打不开
    assert(fp ~= -1, ['Could not open ',文件保存路径', '']);
    magic = fread(fp, 1, 'int32', 0, 'ieee-be');
    assert(magic == 2051, ['Bad magic number in ','文件保存路径', '']);
    numImages = fread(fp, 1, 'int32', 0, 'ieee-be');%读取图片数
    numRows = fread(fp, 1, 'int32', 0, 'ieee-be');%读取图片行数
    numCols = fread(fp, 1, 'int32', 0, 'ieee-be');%读取图片列数
    images = fread(fp, inf, 'unsigned char');%读取数据
    images = reshape(images, numCols, numRows, numImages);%转化成28X28X6000
    images = permute(images,[2 1 3]);%旋转
    images = images/255;%让图片更加清晰
    y=images;
    fclose(fp);%关闭文件
end

读取label数据

function lables = loadmnistlabels()
	fp = fopen('文件保存路径', 'r');
	assert(fp ~= -1, ['Could not open ', '文件保存路径', '']);
	magic = fread(fp, 1, 'int32', 0, 'ieee-be');
	assert(magic == 2049, ['Bad magic number in ', '文件保存路径', '']);
	numLabels = fread(fp, 1, 'int32', 0, 'ieee-be');
	lables = fread(fp, inf, 'unsigned char');%
	assert(size(lables,1) == numLabels, 'Mismatch in label count');
	fclose(fp);
end

特征提取

虽然数据集中,每一张相片只有28x28像素,但是若是将每个像素的数值作为神经网络的输入,会导致神经元的数量过大,神经元特别是输入到输入层神经元的连接变得非常复杂,导致网络训练的速度变慢,推广能力变差。而且图片中并不是每一个像素都包含了识别该图片所必备的信息。因此要对照片进行特征提取,减少不必要信息输入,简化网络结构,增加训练速度和网络的推广性。特征提取的思路如下:在以4x4个像素为一个单位,原来的28x28像素图片分成49个4x4的单位,将里面的16个像素的数值相加,用这个数表示这个单位的特征。这样就把原本28x28=784个像素的照片变成了7x7=49的特征矩阵。

function y=takefeatures(images)
	a=size(images);
	b=a(3);
	images=mat2cell(images,4*ones(1,7),4*ones(1,7),ones(1,b));%转为元胞数组,4X4X7x60000
	images=cellfun(@(x) sum(x(:)),images);%4X4元胞求和,转换成 矩阵
	images=reshape(images,[49,1,b]);%再转换成49X1X60000
	y=0.1*images;%相当于归一化
end

BP神经网络代码

function [y1,y2,y3,y4]=bpnet_handwritednum(images,lables,innum,hdnum,otnum,learn_rate,traic)
	
	in_w=double(rand(49,innum));%隐含层1权重
	hd_w=double(rand(innum,hdnum));%隐含层2权重
	ot_w=double(rand(hdnum,otnum));%输出层权重
	in_incell(1,49)=(0);%保存隐含层1各个节点的输入值
	in_outcell(1,innum)=(0);%保存隐含层1各个节点的输出值
	hd_incell(1,hdnum)=(0);%保存隐含层2各个节点的输入值
	hd_outcell(1,hdnum)=(0);%保存隐含层2各个节点的输出值
	ot_incell(1,otnum)=(0);%保存输出层各个节点的输入值
	ot_outcell(1,otnum)=(0);%保存输出层各个节点的输出值
	ot_error(1,otnum)=(0);%保存输出各节点的偏差
	hd_error(1,hdnum)=(0);%保存反向传后递隐含层各节点的误差
	in_error(1,innum)=(0);%保存反向传播后隐含层1各节点的误差
	bi=size(images);
	count=0;
	canout=0;
	derror(traic)=0;%
	tic
	while(1)
	
	  count=count+1;
	    derror(count)=canout/bi(3);%误差计算,实际上没有用到
	     if count>=traic
	       break;
	     end
	    canout=0;
	for i=1:1:bi(3)
	     in_incell=images(:,1,i)'*in_w;
	     if min(in_incell)<=-500
	         in_incell=mapminmax(in_incell,-400,20);
	     end
	    % in_incell=mapminmax(in_incell,-2,2);   原本用来归一化,但是导致训练过程变长,所以不用
	%隐含层1各个节点的输出
	    in_outcell=1./(1+exp(-in_incell));
	%隐含层2各个节点的输入
	     hd_incell=in_outcell*hd_w;
	    % hd_incell=mapminmax(hd_incell,0,1);   原本用来归一化,但是训练过程变长,所以不用
	%隐含层2各个节点的输出
	    hd_outcell=1./(1+exp(-hd_incell));
	%输出层各个节点的输入
	    ot_incell=hd_outcell*ot_w;
	   % ot_incell=mapminmax(ot_incell,0,1);    原本用来归一化,但是训练过程变长,所以不用
	%输出层的输出
	    ot_outcell=1./(1+exp(-ot_incell));
	    % ot_outcell=mapminmax( ot_outcell,0,1);
	 
	switch lables(i)%判断图片对应的输出
	    case 0
	        ideal_out=[1,0,0,0,0,0,0,0,0,0];
	    case 1
	        ideal_out=[0,1,0,0,0,0,0,0,0,0];
	    case 2
	        ideal_out=[0,0,1,0,0,0,0,0,0,0];
	    case 3
	        ideal_out=[0,0,0,1,0,0,0,0,0,0];
	    case 4
	        ideal_out=[0,0,0,0,1,0,0,0,0,0];
	    case 5
	        ideal_out=[0,0,0,0,0,1,0,0,0,0];
	    case 6
	        ideal_out=[0,0,0,0,0,0,1,0,0,0];
	    case 7
	        ideal_out=[0,0,0,0,0,0,0,1,0,0];
	    case 8
	        ideal_out=[0,0,0,0,0,0,0,0,1,0];
	    case 9
	        ideal_out=[0,0,0,0,0,0,0,0,0,1];
	end
	%计算实际输出和理想输出之间的偏差
	   ot_error=ideal_out-ot_outcell;    
	       %ot_error=0.5*(ot_error.*ot_error);  
	       %原本是按照推导用欧氏几何距离作为误差计算,但是后来发现直接用差值效果更好
	   canout=canout+ot_error*ot_error';
	%反向传播隐含层各个节点的误差
	  hd_error=ot_error*ot_w';
	       % hd_error= (exp(-ot_incell)./(exp(-ot_incell) + 1).^2).*ot_error*ot_w';
	        %原本是按照推导用应该用上述公式计算误差,但是后来发现直接用权值乘效果跟更好
	%反向传播输入层各个节点的误差
	in_error=hd_error*hd_w';
	% %输入层权值更新
	      %in_w= in_w+learn_rate*images(:,1,i).*(exp(-images(:,1,i)')./(exp(-images(:,1,i)') + 1).^2)'.*in_error';
	        in_w= in_w+learn_rate*images(:,1,i)*(exp(-in_incell)./(exp(-in_incell) + 1).^2).*in_error;
	%隐含层2权值更新      
	        hd_w= hd_w+learn_rate*in_outcell'*(exp(-hd_incell)./(exp(-hd_incell) + 1).^2).*hd_error;
	%隐含层1权值更新
	        ot_w=ot_w+learn_rate*hd_outcell'*(exp(-ot_incell)./(exp(-ot_incell) + 1).^2).*ot_error;
	
	end
	end
	toc
	y1=in_w;
	y2=hd_w;
	y3=ot_w;
	y4=derror;
end

测试正确率代码

function y=bpnet_test(data,lables,in_w,hd_w,ot_w)
    isright=0;
    error(10)=0;
    yes(10)=0;
    a=1;
    b=size(lables);
    en=b(1);
    for i=1:1:en
    %隐含层1各个节点的输入
         in_incell=data(:,1,i)'*in_w;
    %隐含层1各个节点的输出
        in_outcell=1./(1+exp(-in_incell));
    %隐含层2各个节点的输入
         hd_incell=in_outcell*hd_w;
    %隐含层2各个节点的输出
        hd_outcell=1./(1+exp(-hd_incell));
    %输出层各个节点的输入
        ot_incell=hd_outcell*ot_w;
    %输出层的输出
        ot_outcell=1./(1+exp(-ot_incell));
          switch lables(i)%判断图片对应的输出
        case 0
            ideal_out=[1,0,0,0,0,0,0,0,0,0];
        case 1
            ideal_out=[0,1,0,0,0,0,0,0,0,0];
        case 2
            ideal_out=[0,0,1,0,0,0,0,0,0,0];
        case 3
            ideal_out=[0,0,0,1,0,0,0,0,0,0];
        case 4
            ideal_out=[0,0,0,0,1,0,0,0,0,0];
        case 5
            ideal_out=[0,0,0,0,0,1,0,0,0,0];
        case 6
            ideal_out=[0,0,0,0,0,0,1,0,0,0];
        case 7
            ideal_out=[0,0,0,0,0,0,0,1,0,0];
        case 8
            ideal_out=[0,0,0,0,0,0,0,0,1,0];
        case 9
            ideal_out=[0,0,0,0,0,0,0,0,0,1];
        end
        a=lables(i)+1;
        if find(ideal_out==max(ideal_out))==find(ot_outcell==max(ot_outcell))
            isright=isright+1;
            yes(a)=yes(a)+1;
        else
            error(a)=error(a)+1;
        end
    end
       error./yes
        y=isright/en;
end

实验测试:
在这里插入图片描述

在这里插入图片描述

结论:可以看到,用训练集,训练400次以后,用测试集测试,得到的正确率为0.9404.正确率较高,符合预期。各个数据的错误率如图所示。可以看到5和8的错误率最高,但是正确率都在百分之九十左右。结果较为满意。

有兴趣的同学可以利用自己手写的数字进行测试。实际上本实验之中训练出来的 网络泛化性较差,用不在数据集之中的手写数字进行测试得出的正确率没有这么高,有待改进。

代码较多,阅读可能有点困难,见谅。若有错误,欢迎指正交流。

  • 10
    点赞
  • 71
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
bp神经网络是一种常用的人工神经网络模型,可以用于手写数字识别Matlab是一个强大的科学计算软件,也提供了丰富的神经网络工具包。 首先,需要创建一个BP神经网络模型。可以使用Matlab中的"newff"函数来创建一个具有指定输入、输出和隐藏层节点数量的BP网络。网络的输入层节点数量应与手写数字的特征数量相匹配,输出层节点数量应为10,对应于0-9这10个可能的数字。 然后,可以使用手写数字的训练数据来训练BP神经网络。这些训练数据应该包含已知的手写数字图像及其对应的数字标签。可以使用Matlab中的"train"函数来对网络进行训练,指定训练数据和训练参数。网络会通过不断调整权重和偏置来逼近正确的输出。 训练完成后,可以使用训练好的神经网络来识别手写数字。对于待识别的手写数字图像,可以使用Matlab的"sim"函数将其输入到网络中,得到网络的输出结果。输出结果为一个包含10个值的向量,表示输入图像是每个数字的概率。可以通过比较这些概率,并选取最大的值对应的数字作为识别结果。 需要注意的是,BP神经网络对于手写数字识别是一种简单但有效的方法。然而,准确率可能会受到训练数据的质量和数量的影响。同时,还可以使用其他改进的神经网络模型或者结合其他图像处理技术来提高手写数字识别的准确性。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值