本文参考链接https://blog.csdn.net/huang_miao_xin/article/details/51364152。修改了其中部分代码,可以完美运行。
代码主要包括以下五个部分。
V=double(rand(256,64));
W=double(rand(64,10));
delta_V=double(rand(256,64));
delta_W=double(rand(64,10));
% lf=0;用来看错误在哪一步的参考数据
yita=0.2;%缩放系数,有的文章称学习率
yita1=0.05;%我自己加的参数,缩放激活函数的自变量防止输入过大进入函数的饱和区,可以去掉体会一下变化
train_number=10;%训练样本中,有多少个数字,一共9个,没有0
train_num=400;%训练样本中,每种数字多少张图,一共100张
x=double(zeros(1,256));%输入层
y=double(zeros(1,64));%中间层,也是隐藏层
output=double(zeros(1,10));%输出层
tar_output=double(zeros(1,10));%目标输出,即理想输出
delta=double(zeros(1,10));%一个中间变量,可以不管
%记录总的均方差便于画图
s_record=1:400;
tic %计时
for train_control_num=1:400 %训练次数控制,在调参的最后发现1000次其实有多了,大概400次完全够了
s=0;
%读图,输入网络
for number=1:train_number %train_number=10
ReadDir=['D:\contrl\BP\BP\training\',num2str(number-1)];%读取样本的路径
for num=1:train_num %控制多少张 train_num=30
photo_name=['\a (',num2str(num),').png'];%图片名
photo_index=[ReadDir,photo_name];%路径加图片名得到总的图片索引
photo_matrix=imread(photo_index);%使用imread得到图像矩阵
photo_matrix=imresize(photo_matrix,[16,16]);
photo_matrix=uint8(photo_matrix>=30);%二值化,黑色是1
tmp=photo_matrix';
tmp=tmp(:);%以上两步完成了图像二维矩阵转变为列向量,256维,作为输入 就是把矩阵的元素按列的顺序变为一列,矩阵转化为向量
%计算输入层输入
x=double(tmp');%转化为行向量因为输入层X是行向量,并且化为浮点数
%得到隐层输入
y0=x*V;
%激活
y=1./(1+exp(-y0*yita1));
%得到输出层输入
output0=y*W;
% lf=lf+1;之前用来看错误在哪一步的参考数据
output=1./(1+exp(-output0*yita1));
%计算预期输出
tar_output=double(zeros(1,10));
tar_output(number)=1.0;
%计算误差
%按照公式计算W和V的调整,为了避免使用for循环比较耗费时间,下面采用了直接矩阵乘法,更高效
delta=(tar_output-output).*output.*(1-output);%1*10
delta_W=yita*repmat(y',1,10).*repmat(delta,64,1);%64*10
tmp=sum((W.*repmat(delta,64,1))');
tmp=tmp.*y.*(1-y);
delta_V=yita*repmat(x',1,64).*repmat(tmp,256,1);
%计算均方差
s=s+sum((tar_output-output).*(tar_output-output))/10;
%更新权值
W=W+delta_W;
V=V+delta_V;
end
end
s=s/train_number/train_num %不加分号,随时输出误差观看收敛情况
train_control_num %不加分号,随时输出迭代次数观看运行状态
s_record(train_control_num)=s;%记录
end
toc %计时结束
plot(1:400,s_record);
correct_num=0;%记录正确的数量
incorrect_num=0;%记录错误数量
test_number=10;%测试集中,一共多少数字,9个,没有0
test_num=800;%测试集中,每个数字多少个,最大100个
% load W;%%之前训练得到的W保存了,可以直接加载进来
% load V;
% load yita1;
%记录时间
tic %计时开始
for number=1:test_number
number
ReadDir=['D:\contrl\BP\BP\training\',num2str(number-1)];
for num=1:test_num %控制多少张
photo_name=['\a (',num2str(num),').png'];
photo_index=[ReadDir, photo_name];
photo_matrix=imread(photo_index);
%大小改变
photo_matrix=imresize(photo_matrix,[16 16]);
%二值化
photo_matrix=uint8(photo_matrix>=30);%黑色是1
%行向量
tmp=photo_matrix';
tmp=tmp(:);
%计算输入层输入
x=double(tmp');
%得到隐层输入
y0=x*V;
%激活
y=1./(1+exp(-y0*yita1));
%得到输出层输入
o0=y*W;
tar_output=double(zeros(1,10));
tar_output(number)=1.0;
o=1./(1+exp(-o0*yita1));
%最大的输出即是识别到的数字
output=double(zeros(1,10));
[o,index]=sort(o);
p=index(10);
output(p)=1.0;
if p==number
correct_num=correct_num+1;
else
incorrect_num=incorrect_num+1;
%显示不成功的数字,显示会比较花时间
% figure(incorrect_num)
% imshow((1-photo_matrix)*255);
% title(num2str(number));
end
end
end
plotconfusion(tar_output,output);
correct_rate=correct_num/test_number/test_num;
toc %计时结束
手写数字图片资源已上传至csdn,码字不易,希望能给些积分,谢大佬们!!!
https://download.csdn.net/download/qu_learner/12527007