西瓜书5.5:试编程实现BP算法与累积BP算法,在西瓜数据集3.0上分别用这两个算法训练一个单隐层网络,并进行比较。
BP算法matlab实现
clear
x = xlsread('watermelon3.0.xlsx', 'Sheet1', 'A1:Q8');
y = xlsread('watermelon3.0.xlsx', 'Sheet1', 'A9:Q9');
x=x';
y=y';
%将y设为0,1两类
y=y-1;
%获取输入参数的样本数与参数数
[m,n]=size(x);
t=1; %输出层神经元
rand('seed',0);
v=rand(n,n+1); %输入层与隐层的权值
w=rand(n+1,t); %隐层与输出层的权值
thy=rand(n+1); %隐层阀值
thj=rand(t); %输出层阀值
ty=zeros(m,t); %输出层输出
b=zeros(n+1); %隐层输出
gj=zeros(t); %累计误差对w,thj求导的参数
eh=zeros(n+1); %累计误差对v,thy求导的参数
xk=1; %学习率
kn=0; %迭代次数
sn=0; %同样的累计误差值累积次数
old_ey=0; %前一次迭代的累计误差
EY_BP = zeros(2175); #随机种子为0的时候,BP算法迭代2175次终止
while(1)
kn=kn+1;
ey=0; %当前迭代的累计误差
for i=1:m
%计算隐层输出
for j=1:n+1
ca=0;
for k=1:n
ca=ca+v(k,j)*x(i,k);
end
b(j)=1/(1+exp(-ca+thy(j)));
end
%计算输出层输出
for j=1:t
cb=0;
for k=1:n+1
cb=cb+w(k,j)*b(k);
end
ty(i,j)=1/(1+exp(-cb+thj(j)));
end
%计算当前迭代累计误差
for j=1:t
ey=ey+((y(i)-ty(i,j))^2)/2;
end
%计算w,thj导数参数
for j=1:t
gj(j)=ty(i,j)*(1-ty(i,j))*(y(i)-ty(i,j));
end
%计算v,thy导数参数
for j=1:n+1
teh=0;
for k=1:t
teh=teh+w(j,k)*gj(k);
end
eh(j)=teh*b(j)*(1-b(j));
end
%更新v,thy
for j=1:n+1
thy(j)=thy(j)+(-xk)*eh(j);
for k=1:n
v(k,j)=v(k,j)+k*eh(j)*x(i,k);
end
end
%更新thj,w
for j=1:t
thj(j)=thj(j)+(-xk)*gj(j);
for k=1:n+1
w(k,j)=w(k,j)+xk*gj(j)*b(k);
end
end
end
EY_BP(kn) = ey;
%迭代终止判断
if(abs(old_ey-ey)<0.0001)
sn=sn+1;
if(sn==100)
break;
end
else
old_ey=ey;
sn=0;
end
end
save('EY_BP.mat','EY_BP')
ABP算法matlab实现
clear
x = xlsread('watermelon3.0.xlsx', 'Sheet1', 'A1:Q8');
y = xlsread('watermelon3.0.xlsx', 'Sheet1', 'A9:Q9');
x=x';
y=y';
y=y-1;
[m,n]=size(x);
t=1; %输出层神经元
rand('seed',0);
v=rand(n,n+1); %输入层与隐层的权值
w=rand(n+1,t); %隐层与输出层的权值
thy=rand(n+1); %隐层阀值
thj=rand(t); %输出层阀值
ty=zeros(m,t); %输出层输出
b=zeros(n+1); %隐层输出
gj=zeros(t); %累计误差对w,thj求导的参数
eh=zeros(n+1); %累计误差对v,thy求导的参数
tk=1; %学习率
kn=0; %迭代次数
sn=0; %同样的累计误差值累积次数
old_ey=0; %前一次迭代的累计误差
EY_ABP = zeros(1305); %在随机种子为0的情况下,ABP达到终止条件,迭代了1305次
while(1)
kn=kn+1;
ey=0;%当前迭代的累计误差
%计算全部样本输出层输出
for i=1:m
%计算隐层输出
for j=1:n+1
ca=0;
for k=1:n
ca=ca+v(k,j)*x(i,k);
end
b(i,j)=1/(1+exp(-ca+thy(j)));
end
%计算输出层输出
for j=1:t
cb=0;
for k=1:n+1
cb=cb+w(k,j)*b(i,k);
end
ty(i,j)=1/(1+exp(-cb+thj(j)));
end
end
%用来存累计误差对四个变量的下降方向
tv=zeros(n,n+1);
tw=zeros(n+1,t);
tthy=zeros(n+1);
tthj=zeros(t);
%计算累计误差
for i=1:m
for j=1:t
ey=ey+((y(i)-ty(i,j))^2)/2;
end
%计算w,thj导数参数
for j=1:t
gj(j)=ty(i,j)*(1-ty(i,j))*(y(i)-ty(i,j));
end
%计算v,thy导数参数
for j=1:n+1
teh=0;
for k=1:t
teh=teh+w(j,k)*gj(k);
end
eh(j)=teh*b(i,j)*(1-b(i,j));
end
%计算w,thj导数
for j=1:n+1
tthy(j)=tthy(j)+(-1)*eh(j);
for k=1:n
tv(k,j)=tv(k,j)+k*eh(j)*x(i,k);
end
end
%计算v,thy导数
for j=1:t
tthj(j)=tthj(j)+(-1)*gj(j);
for k=1:n+1
tw(k,j)=tw(k,j)+gj(j)*b(i,k);
end
end
end
%更新参数
v=v+tk*tv;
w=w+tk*tw;
thy=thy+tk*tthy;
tthj=thj+tk*tthj;
%迭代终止条件
EY_ABP(kn) = ey;
if(abs(old_ey-ey)<0.0001)
sn=sn+1;
if(sn==50)
break;
end
else
old_ey=ey;
sn=0;
end
end
save('EY_ABP.mat','EY_ABP');
西瓜书:一般来说,标准BP算法每次更新只针对单个样本,参数更新地非常频繁,而且对不同地样例进行更新的效果可能出现抵消的现象,因此,达到同样的累积误差极小值点,标准BP算法往往需要更多的迭代次数。累积BP算法直接对累积误差最小化,它在读取整个训练集D一遍后才对参数进行更新,其参数的更新频率低很多,在很多任务中,累积误差下降到一定程度之后,进一步下降会非常缓慢,这时候,标准BP往往会获得较好的解,尤其在训练集D非常大的时候更加明显。
标准BP算法与累积BP算法之间的区别,类似于随机梯度下降(SGD)与标准梯度下降之间的区别。
相关python实现可参考: