想自己用matlab写bp神经网络,看了好多网上bp算法的视频,自己写的思路和视频里基本一致,在这里叙述一下我自己写的过程。先说下我理解的bp算法,不知道是不是对的。
比如是2维输入,一层隐含层,6个隐含层单元,3个输出。
前向传播:输入单元接收输入,输入和权值相乘并加上对应隐含层的阈值,再经过激活函数,激活函数的输出再乘以权值并加上对应输出单元的阈值,再经过激活函数,这就是输出了。
bp反馈:用输出值和期望值做方差,得到误差函数,用每一个权值和阈值分别对误差函数求偏导,导数是正的就减小权值或阈值,导数是负的就增大权值或阈值。一直迭代,直到误差函数小于一定的值。
我想的bp算法应该在我输入第一组数据后,3个输出单元会输出1 0 0;第二组数据则会输出 0 1 0
第三组数据则输出 0 0 1;
一共写了两种方式。
第一种:总体结构是2个输入单元,一层隐含层,隐含层有6个单元,3个输出单元。先训练一组数据,直到误差函数的值很小后再换另一组数据训练,如此下去。
第一步,
随机设置参数,0~1内。参数包括了,输入层到隐含层的权值v,隐含层的阈值r,隐含层到输出层的权值w,输出层的阈值h。学习率k=0.1,误差函数E。
第二步,前向传播,并反馈修改权值,每组数据迭代100次再换数据
第三步,直接查看输出的值y_hat
代码:
clear;clc
x=[17,17,17];
C=[41,42,43];
[r,h,v,w,E,y_hat]=standard_BP(x,C,1e-6);
function [r,h,v,w,E,y_hat]=standard_BP(x,C,eps) %q为隐层单元数目,eps均方误差限
q=6; %隐含层单元数目
L=3; %输出单元数目
n=2; %获取数据的维度
v=rand(n,q); %初始化输入层到隐含层的权值
r=rand(1,q); %初始化隐含层的阀值
w=rand(q,L); %初始化隐含层到输出层的权值
h=rand(1,L); %初始化输出层的阀值
k=0.1; %学习率
E=0;
for t=1:3 %每组数据训练多次,并多次修改权值,降低误差,一共三组数据
Y=[1 0 0];
Y1=[0 1 0];
Y2=[0 0 1];
Y3=[Y(t) Y1(t) Y2(t)]; %期望值
N=100; %迭代100次
while N>1
a=[x(t) C(t) ];
A=a*v;
b=fc_sigmod(A-r); %经过隐含层的激活函数的输出
B=b*w; %隐含层->输出层,各个输出层单元具有的权值
y_hat=fc_sigmod(B-h); %经过输出层的激活函数的输出
E=0.5*sum((y_hat-Y3).^2); %求均方误差
%yn=y_hat.*y(t);
g=y_hat.*(Y3-y_hat).*(1-y_hat);
e=b.*(1-b).*(w*g')';
v=v+k*a'*e; %输入层->隐含层的权值更新
r=r-k*e; %隐含层的阀值更新
w=w+(k*g'*b)'; %隐含层->输出层的权值更新
h=h-k*g; %隐含层的阀值更新
N=N-1;
end
end
for t=1:3 %依次输入三组数据,检测输出
Y3=[Y(t) Y1(t) Y2(t)];
a=[x(t) C(t) ];
A=a*v;
b=fc_sigmod(A-r);
B=b*w;
y_hat=fc_sigmod(B-h);
E=0.5*sum((y_hat-Y3).^2);
y_hat
E
end
function y=fc_sigmod(x)
y=1./(1+exp(-x));
end
end
程序结束。
如果训练成功,结果应该是输入第一组数据,输出则会输出y_hat=[1 0 0],但是实际情况是三组数据训练之后,无论怎么输入都会输出y_hat=[0 0 1],也就是只有最后一组的数据训练有效了,前面两组数据没有作用。
第二种,总体结构是2个输入单元,两层隐含层,每层隐含层有6个单元,3个输出单元。每组数据只训练一次,连续训练三组数据后再循环三次,如此下去。
第一步,初始化
第二步,前向传播,并反馈,每组数据训练一次,并修改一次权值,三组全训练后再重新进行一轮
第三步 看训练结果
clear;clc
x=[17,17,17];
C=[44,45,46];
y=[0.1,0.2,0.3];
[r,h,v,w,E]=standard_BP(x,C,1e-6);
function [r,h,v,w,E]=standard_BP(x,C,eps)
q=6; %隐层单元数目
L=3;%length(y); %输出单元数目
n=2;%length(x); %获取数据的维度
v=rand(n,q); %初始化输入层到隐层的权值
r=rand(1,q); %初始化隐层1的阀值
s=rand(q,q); %隐层到隐层的权值
d=rand(1,q); %隐层2的阈值
w=rand(q,L); %初始化隐层2到输出层的权值
h=rand(1,L); %初始化输出层的阀值
k=0.1; %学习率
E=0;
M=1000;
while M>1
for t=1:3 %每组数据训练一次,并修改一次权值,三组数据全训练后多次循环降低误差
Y = [1 0 0];
Y1= [0 1 0];
Y2= [0 0 1];
Y3=[Y(t) Y1(t) Y2(t)]; %期望值
N=2;
while N>1
a=[x(t) C(t)];
A=a*v+r;
b=fc_sigmod(A);
F=b*s+d;
u=fc_sigmod(F);
B=u*w+h;
y_hat=fc_sigmod(B);
E=0.5*sum((y_hat-Y3).^2); %误差函数
g=y_hat.*(Y3-y_hat).*(1-y_hat);
eb=b.*(1-b).*(w*g')';
eu=u.*(1-u).*(w*g')';
v=v+k*a'*eb*s.*u.*(1-u); %更新权值和阈值
r=r+k*eb*s.*u.*(1-u) ;
s=s+k*b'*eu;
d=d+k*eu;
w=w+(k*g'*u)';
h=h+k*g;
N=N-1;
end
end
M=M-1;
end
for t=1:3 %依次输入三组数据,检测输出
Y3=[Y(t) Y1(t) Y2(t)];
a=[x(t) C(t)];
A=a*v;
b=fc_sigmod(A+r);
F=b*s;
u=fc_sigmod(F+d);
B=u*w;
y_hat=fc_sigmod(B+h);
E=0.5*sum((y_hat-Y3).^2);
y_hat
E
end
end
如果训练成功,则在输入第一组数据时,输出应该为 y_hat=[1 0 0],但是实际输出的却是 y_hat=[0.33 0.33 0.33],而且三组数据的输出都是如此。好像是三组数据被求了均值一样。
过程公式都是自己写的,对照网上公式推导,觉得自己应该没有推错。
也不知道是自己对bp算法的理解不对还是什么?
不知道是哪里不对,bp算法到底是怎么训练的?
这里有matlab traingd简化后的重写代码,
《重写traingd代码(梯度下降法)》https://bp.bbbdata.com/site/text/8,
里面有验证,跟matlab的traingd函数结果一样。