数据集和完整的程序下载见更新版:神经网络用于字符识别更新版
二:BP神经网络应用于字符识别
字符包括汉字,字母,数字和一些符号。汉字有几千个,字母有几十个,数字的类最少只有10个,所以选择简单的手写数字字符来实现。结合三个相关的程序和论文,一个是语音特征的分类(不调用神经网络工具箱相关函数实现),另外两个是关于手写数字识别的。处理的数据集是放在10个文件夹里,文件夹的名称对应存放的手写数字图片的数字,每个数字500张,每张图片的像素统一为28*28,如下
这5000张随机选取4500张进行训练,剩下的500张用来测试。为了能对BP神经网络有更深入的了解,选择一步步详细实现。
BP神经网络的特点:信号前向传递,信号反向传播。若输出存在误差,根据误差调整权值和阈值,使网络的输出接近预期。
在用BP神经网络进行预测之前要训练网络
训练过程
1.网络初始化:各个参数的确定包括输入,输出,隐含层的节点数,输入和隐含,隐含和输出层之间的权值,隐含,输出层的阈值,学习速度和激励函数。
2.计算隐含层输出
3.计算输出层输出
4.误差计算
5.权值更新
6.阈值更新
7.判断迭代是否结束
模型建立:
BP神经网络构建-BP神经网络训练-BP神经网络分类
1.确定神经网络的输入,输出。
输入是BP神经网络很重要的方面,输入的数据是手写字符经过预处理和特征提取后的数据。预处理有二值化,裁剪掉空白的区域,然后再统一大小为70*50为特征提取做准备。特征提取采用的是粗网格特征提取,把图像分成35个区域,每个区域100像素,统计区域中1像素所占的比例。经过预处理特征提取后,28*28图像转成1*35的特征矢量。提取完5000张图片后,依次把所有的特征存于一个矩阵(5000*35)中,最后在加上第36行,用来存放原图片的真值。于是最后得到是包含特征向量和真值的矩阵(5000*36),特征向量是神经网络的输入,真值是其输出。
2.神经的网络的训练
用matlab的rands函数来实现网络权值的初始化,网络结构为输入层35,隐藏层34,输出层10,学习速率为0.1,隐藏层激励函数为sigmoid函数。随机抽取4500张图片提取特征后输入,按照公式计算隐含层和输出层输出,误差,更新网络权值。
3.神经网络的预测
训练好神经网络之后,用随机抽取的500个数字字符对网络进行预测,输入特征向量,计算隐含层和输出层输出,得到最后预测的数据。同时计算每个数字的正确率和全体的正确率。最后得到的总体正确率为0.8004。
程序:
clc;
clearall;
closeall;
Files= dir('E:/Matlabdip/word_recognition/testdatabase');
LengthFiles= length(Files);
%========读取存在testdatabase下0-10个文件的全部图片========%
%========存放在number中,number{1}是数字0有500张========%
fori = 3:LengthFiles;
if strcmp(Files(i).name,'.')||strcmp(Files(i).name,'..')
else
number{i-2}=BatchReadImg(strcat('E:/Matlabdip/word_recognition/testdatabase','/',Files(i).name),0);
end
end
charvec1=zeros(35,5000);
%========对读取的图片预处理(二值化-裁剪-特征提取)========%
for i=1:10
for j=1:500
I1=number{1,i}{1,j};
Ibw = im2bw(I1,graythresh(I1));
bw2 = edu_imgcrop(Ibw);%对图像进行裁剪,使边框完全贴紧字符
charvec = edu_imgresize(bw2);%提取特征统计每个小区域中图像象素所占百分比作为特征数据
charvec1(:,(i-1)*500+j)=charvec;
end
end
index=[zeros(1,500),zeros(1,500)+1,...
zeros(1,500)+2,zeros(1,500)+3,zeros(1,500)+4,zeros(1,500)+5,zeros(1,500)+6,zeros(1,500)+7,zeros(1,500)+8,zeros(1,500)+9];
charvec1(36,:)=index;
%=========BP神经网络创建,训练和测试========%
%从1到5000间随机排序(在[0,1]之间产生5000个随机数)==将数据顺序打乱
k=rand(1,5000);
[m,n]=sort(k);
%输入输出数据
input=charvec1(1:35,:);
output1=charvec1(36,:);
%把输出从1维变成10维
fori=1:5000
switch output1(i)
case 0
output(:,i)=[1 0 0 0 0 0 0 0 0 0]';
case 1
output(:,i)=[0 1 0 0 0 0 0 0 0 0]';
case 2
output(:,i)=[0 0 1 0 0 0 0 0 0 0]';
case 3
output(:,i)=[0 0 0 1 0 0 0 0 0 0]';
case 4
output(:,i)=[0 0 0 0 1 0 0 0 0 0]';
case 5
output(:,i)=[0 0 0 0 0 1 0 0 0 0]';
case 6
output(:,i)=[0 0 0 0 0 0 1 0 0 0]';
case 7
output(:,i)=[0 0 0 0 0 0 0 1 0 0]';
case 8
output(:,i)=[0 0 0 0 0 0 0 0 1 0]';
case 9
output(:,i)=[0 0 0 0 0 0 0 0 0 1]';
end
end
%随机提取4500个样本为训练样本,500个样本为预测样本
input_train=input(:,n(1:4500));
output_train=output(:,n(1:4500));
input_test=input(:,n(4501:5000));
output_test=output(:,n(4501:5000));
% %输入数据归一化
%[inputn,inputps]=mapminmax(input_train);
%% 网络结构初始化
innum=35;
midnum=34;
outnum=10;
%权值初始化
w1=rands(midnum,innum);%输入到隐藏
b1=rands(midnum,1);
w2=rands(midnum,outnum);%隐藏到输出
b2=rands(outnum,1);
w2_1=w2;w2_2=w2_1;
w1_1=w1;w1_2=w1_1;
b1_1=b1;b1_2=b1_1;
b2_1=b2;b2_2=b2_1;
%学习率
xite=0.1;
alfa=0.01;
%% 网络训练
%for ii=1:10
% E(ii)=0;
for i=1:1:4500
%% 网络预测输出
x=input_train(:,i);
% 隐含层输出
for j=1:1:midnum
I(j)=input_train(:,i)'*w1(j,:)'+b1(j);
Iout(j)=1/(1+exp(double(-I(j))));
end
% 输出层输出
yn=w2'*Iout'+b2;
%% 权值阀值修正
%计算误差
e=output_train(:,i)-yn;
% E(ii)=E(ii)+sum(abs(e));
%计算权值变化率
dw2=e*Iout;
db2=e';
%=======由于采用的是sigmoid单元,所以要对每个输出单元以及隐藏单元计算误差项======%
for j=1:1:midnum
S=1/(1+exp(double(-I(j))));
FI(j)=S*(1-S);
end
for k=1:1:innum
for j=1:1:midnum
dw1(k,j)=FI(j)*x(k)*(w2(j,:)*e);%
db1(j)=FI(j)*(w2(j,:)*e);
end
end
w1=w1_1+xite*dw1';
b1=b1_1+xite*db1';
w2=w2_1+xite*dw2';
b2=b2_1+xite*db2';
w1_2=w1_1;w1_1=w1;
w2_2=w2_1;w2_1=w2;
b1_2=b1_1;b1_1=b1;
b2_2=b2_1;b2_1=b2;
end
%end
%%% 语音特征信号分类
%inputn_test=mapminmax('apply',input_test,inputps);
for i=1:500%1500
%隐含层输出
for j=1:1:midnum
I(j)=input_test(:,i)'*w1(j,:)'+b1(j);
Iout(j)=1/(1+exp(double(-I(j))));
end
%输出层输出
fore(:,i)=w2'*Iout'+b2;
end
%% 结果分析
%根据网络输出找出数据属于哪类
fori=1:500
output_fore(i)=find(fore(:,i)==max(fore(:,i)))-1;
end
%BP网络预测误差
error=output_fore'-output1(n(4501:5000))';
%画出预测数字和实际数字的分类图
figure(1)
plot(output_fore,'r')
holdon
plot(output1(n(4501:5000))','b')
legend('预测数字','实际数字')
%画出误差图
figure(2)
plot(error)
title('BP网络分类误差','fontsize',12)
xlabel('输入数字','fontsize',12)
ylabel('分类误差','fontsize',12)
k=zeros(1,10);
%找出判断错误的分类属于哪一类
fori=1:500
if error(i)~=0
[b,c]=max(output_test(:,i));
switch c-1
case 1
k(1)=k(1)+1;
case 2
k(2)=k(2)+1;
case 3
k(3)=k(3)+1;
case 4
k(4)=k(4)+1;
case 5
k(5)=k(5)+1;
case 6
k(6)=k(6)+1;
case 7
k(7)=k(7)+1;
case 8
k(8)=k(8)+1;
case 9
k(9)=k(9)+1;
case 0
k(10)=k(10)+1;
end
end
end
%找出每类的个体和
kk=zeros(1,10);
fori=1:500
[b,c]=max(output_test(:,i));
switch c-1
case 1
kk(1)=kk(1)+1;
case 2
kk(2)=kk(2)+1;
case 3
kk(3)=kk(3)+1;
case 4
kk(4)=kk(4)+1;
case 5
kk(5)=kk(5)+1;
case 6
kk(6)=kk(6)+1;
case 7
kk(7)=kk(7)+1;
case 8
kk(8)=k(8)+1;
case 9
kk(9)=kk(9)+1;
case 0
kk(10)=kk(10)+1;
end
end
%正确率
rightridio=(kk-k)./kk
right=(sum(kk(:))-sum(k(:)))/sum(kk(:));
用到到函数:BatchImg
function [imglist]=BatchReadImg(rootpath,grayflag)
if nargin<2
disp('Not enough parameters!');
return;
end
filelist=dir(rootpath);
[filenum,temp]=size(filelist);
tempind=0;
imglist=cell(0);
for i=1:filenum
if strcmp(filelist(i).name,'.')|| strcmp(filelist(i).name,'..')||strcmp(filelist(i).name,'Desktop_1.ini')||strcmp(filelist(i).name,'Desktop_2.ini')
else
tempind=tempind+1;
imglist{tempind}=imread(strcat(rootpath,'/',filelist(i).name));
end
end
if grayflag==1
tempcount=size(imglist);
for j=1:tempcount(2)
imglist{j}=rgb2gray(imglist{j});
end
end
edu_imgcrop:
function bw2 = edu_imgcrop(bw)
%找到图像边界
[y2temp x2temp] = size(bw);
x1=1;
y1=1;
x2=x2temp;
y2=y2temp;
% 找左边空白
cntB=1;
while (sum(bw(:,cntB))==y2temp)
x1=x1+1;
cntB=cntB+1;
end
% 左边
cntB=1;
while (sum(bw(cntB,:))==x2temp)
y1=y1+1;
cntB=cntB+1;
end
% 上边
cntB=x2temp;
while (sum(bw(:,cntB))==y2temp)
x2=x2-1;
cntB=cntB-1;
end
% 下边
cntB=y2temp;
while (sum(bw(cntB,:))==x2temp)
y2=y2-1;
cntB=cntB-1;
end
bw2=imcrop(bw,[x1,y1,(x2-x1),(y2-y1)]);
edu_imgresize:
function lett = edu_imgresize(bw2)
% ======提取特征,转成5*7的特征矢量,把图像中每10*10的点进行划分相加,进行相加成一个点=====%
%======即统计每个小区域中图像象素所占百分比作为特征数据====%
bw_7050=imresize(bw2,[70,50]);
for cnt=1:7
for cnt2=1:5
Atemp=sum(bw_7050(((cnt*10-9):(cnt*10)),((cnt2*10-9):(cnt2*10))));%10*10box
lett((cnt-1)*5+cnt2)=sum(Atemp);
end
end
lett=((100-lett)/100);
lett=lett';
完整的数据集和可以运行的Matlab代码下载
邮箱联系:[email protected]