BP神经网络
(一)定义
误差反向传播的BP算法简称BP算法,其基本思想是梯度下降法。它采用梯度搜索技术,以期使网络的实际输出值与期望输出值的误差均方值为最小。
(二)BP网络特点
1)是一种多层网络,包括输入层、隐含层和输出层;
2)层与层之间采用全互连方式,同一层神经元之间不连接;
3)权值通过δ学习算法进行调节;
4)神经元激发函数为S函数;
5)学习算法由正向传播和反向传播组成;
6)层与层的连接是单向的,信息的传播是双向的。
(三)BP主要应用
回归预测(可以进行拟合,数据处理分析,事物预测,控制等)、分类识别(进行类型划分,模式识别等),但无论那种网络,什么方法,解决问题的精确度都无法打到100%的,但并不影响其使用,因为现实中很多复杂的问题,精确的解释是毫无意义的,有意义的解析必定会损失精度。
(四)BP网络各种算法的应用范围
1)Traingd:批梯度下降训练函数,沿网络性能参数的负梯度方向调整网络的权值和阈值;
2)Traingdm:动量批梯度下降函数,也是一种批处理的前馈神经网络训练方法,不但具有更快的收敛速度,而且引入了一个动量项,有效避免了局部最小问题在网络训练中出现;
3)Trainrp:有弹回的BP算法,用于消除梯度模值对网络训练带来的影响,提高训练的速度(主要通过delt_inc和delt_dec来实现权值的改变);
4)Trainlm:Levenberg-Marquardt算法,对于中等规模的BP神经网络有最快的收敛速度,是系统默认的算法.由于其避免了直接计算赫赛矩阵,从而减少了训练中的计算量,但需要较大内存量.;
5)traincgb:Plwell-Beale算法:通过判断前后梯度的正交性来决定权值和阈值的调整方向是否回到负梯度方向上来;
6)trainscg:比例共轭梯度算法:将模值信赖域算法与共轭梯度算法结合起来,减少用于调整方向时搜索网络的时间。
一般来说,traingd和traingdm是普通训练函数,而traingda,traingdx,traingd,trainrp,traincgf,traincgb,trainsc g,trainbgf等等都是快速训练函数.总体感觉就是训练时间的差别比较大,还带有精度的差异。
(五)实例及其仿真分析(BP网络底层代码的实现)
1)程序
%% 读入数据
xlsfile='student.xls';
[data,label]=getdata(xlsfile);
%% 划分数据
[traind,trainl,testd,testl]=divide(data,label);
%% 设置参数
rng('default')
rng(0)
nTrainNum = 60; % 60个训练样本
nSampDim = 2; % 样本是2维的
%% 构造网络
net.nIn=2;
net.nHidden = 3; % 3个隐含层节点
net.nOut = 1; % 一个输出层节点
w = 2*(rand(net.nHidden,net.nIn)-1/2); % nHidden * 3 一行代表一个隐含层节点
b = 2*(rand(net.nHidden,1)-1/2);
net.w1 = [w,b];
W = 2*(rand(net.nOut,net.nHidden)-1/2);
B = 2*(rand(net.nOut,1)-1/2);
net.w2 = [W,B];
%% 训练数据归一化
mm=mean(traind);
% 均值平移
for i=1:2
traind_s(:,i)=traind(:,i)-mm(i);
end
% 方差标准化
ml(1) = std(traind_s(:,1));
ml(2) = std(traind_s(:,2));
for i=1:2
traind_s(:,i)=traind_s(:,i)/ml(i);
end
%% 训练
SampInEx = [traind_s';ones(1,nTrainNum)]; expectedOut=trainl;
eb = 0.01; % 误差容限
eta = 0.6; % 学习率
mc = 0.8; % 动量因子maxiter = 2000; % 最大迭代次数iteration = 0; % 第一代
errRec = zeros(1,maxiter);
outRec = zeros(nTrainNum, maxiter);
NET=[]; % 记录
% 开始迭代
for i = 1 : maxiter
hid_input = net.w1 * SampInEx; % 隐含层的输入
hid_out = logsig(hid_input); % 隐含层的输出
ou_input1 = [hid_out;ones(1,nTrainNum)]; % 输出层的输入
ou_input2 = net.w2 * ou_input1;
out_out = logsig(ou_input2); % 输出层的输出
outRec(:,i) = out_out'; % 记录每次迭代的输出
err = expectedOut - out_out; % 误差
sse = sumsqr(err);
errRec(i) = sse; % 保存误差值
fprintf('第%d 次迭代误差: %f\n', i, sse);
iteration = iteration + 1;
% 判断是否收敛
if sse<=eb
break;
end
% 误差反向传播
% 隐含层与输出层之间的局部梯度
DELTA = err.*dlogsig(ou_input2,out_out);
% 输入层与隐含层之间的局部梯度
delta = net.w2(:,1:end-1)' * DELTA.*dlogsig(hid_input,hid_out);
% 权值修改量
dWEX = DELTA*ou_input1';
dwex = delta*SampInEx';
% 修改权值,如果不是第一次修改,则使用动量因子
if i == 1
net.w2 = net.w2 + eta * dWEX;
net.w1 = net.w1 + eta * dwex;
else
net.w2 = net.w2 + (1 - mc)*eta*dWEX + mc * dWEXOld;
net.w1 = net.w1 + (1 - mc)*eta*dwex + mc * dwexOld; end
% 记录上一次的权值修改量
dWEXOld = dWEX;
dwexOld = dwex;
end
%% 测试
% 测试数据归一化
for i=1:2
testd_s(:,i)=testd(:,i)-mm(i);
end
for i=1:2
testd_s(:,i)=testd_s(:,i)/ml(i);
end
% 计算测试输出
InEx=[testd_s';ones(1,260-nTrainNum)];
hid_input = net.w1 * InEx;
hid_out = logsig(hid_input); % output of the hidden layer nodes ou_input1 = [hid_out;ones(1,260-nTrainNum)];
ou_input2 = net.w2 * ou_input1;
out_out = logsig(ou_input2);
out_out1=out_out;
% 取整
out_out(out_out<0.5)=0;
out_out(out_out>=0.5)=1;
% 正确率
rate = sum(out_out == testl)/length(out_out);
%% 显示
% 显示训练样本
train_m = traind(trainl==1,:);
train_m=train_m';
train_f = traind(trainl==0,:);
train_f=train_f';
figure(1)
plot(train_m(1,:),train_m(2,:),'bo');
hold on;
plot(train_f(1,:),train_f(2,:),'r*');
xlabel('身高')
ylabel('体重')
title('训练样本分布')
legend('男生','女生')
figure(2)
axis on
hold on
grid
[nRow,nCol] = size(errRec);
plot(1:nCol,errRec,'LineWidth',1.5);
legend('误差平方和');
xlabel('迭代次数','FontName','Times','FontSize',10);
ylabel('误差');
% 正确率:87%
%将样本逐个输入,由于样本输入的随机性,可以在一定程度上避免出现局部最优。
%% 清理
clear all
clc
%% 读入数据
xlsfile='student.xls';
[data,label]=getdata(xlsfile);
%% 划分数据
[traind,trainl,testd,testl]=divide(data,label);
%% 设置参数
rng('default')
rng(0)
nTrainNum = 60; % 60个训练样本nSampDim = 2; % 样本是2维的
M=2000; % 迭代次数
ita=0.1; % 学习率
alpha=0.2;
%% 构造网络
HN=3; % 隐含层层数
net.w1=rand(3,HN);
net.w2=rand(HN+1,1);
%% 归一化数据
mm=mean(traind);
for i=1:2
traind_s(:,i)=traind(:,i)-mm(i);
end
ml(1) = std(traind_s(:,1));
ml(2) = std(traind_s(:,2));
for i=1:2
traind_s(:,i)=traind_s(:,i)/ml(i);
end
%% 训练
for x=1:M % 迭代
ind=randi(60); % 从1-60中选一个随机数
in=[traind_s(ind,:),1]; % 输入层输出
net1_in=in*net.w1; % 隐含层输入
net1_out=logsig(net1_in); % 隐含层输出
net2_int = [net1_out,1]; % 下一次输入
net2_in = net2_int*net.w2; % 输出层输入
net2_out = logsig(net2_in); % 输出层输出
err=trainl(ind)-net2_out; % 误差
errt(x)=1/2*sqrt(sum(err.^2)); % 误差平方
fprintf('第%d 次循环,第%d个学生,误差%f\n',x,ind, errt(x));
% 调整权值
for i=1:length(net1_out)+1
for j=1:1
ipu1(j)=err(j); % 局部梯度
% 输出层与隐含层之间的调整量
delta1(i,j) = ita.*ipu1(j).*net2_int(i);
end
end
for m=1:3
for i=1:length(net1_out)
% 局部梯度
ipu2(i)=net1_out(i).*(1-net1_out(i)).*sum(ipu1.*net.w2);
% 输入层和隐含层之间的调整量
delta2(m,i)= ita.*in(m).*ipu2(i);
end
end
% 调整权值
if x==1
net.w1 = net.w1+delta2;
net.w2 = net.w2+delta1;
else
net.w1 = net.w1+delta2*(1-alpha) + alpha*old_delta2;
net.w2 = net.w2+delta1*(1-alpha) + alpha*old_delta1;
end
old_delta1=delta1;
old_delta2=delta2;
end
%% 测试
% 测试数据归一化
for i=1:2
testd_s(:,i)=testd(:,i)-mm(i);
end
for i=1:2
testd_s(:,i)=testd_s(:,i)/ml(i);
end
testd_s = [testd_s,ones(length(testd_s),1)];
net1_in=testd_s*net.w1;
net1_out=logsig(net1_in);
net1_out=[net1_out,ones(length(net1_out),1)]; net2_int = net1_out;
net2_in = net2_int*net.w2;
net2_out=net2_in;
% 取整
net2_out(net2_out<0.5)=0;
net2_out(net2_out>=0.5)=1;
rate=sum(net2_out==testl')/length(net2_out); %% 显示
figure(1);
plot(1:M,errt,'b-','LineWidth',1.5);
xlabel('迭代次数')
ylabel('误差')
title('BP网络串行训练的误差')
%正确率:88.5%
2)仿真结果