BP神经网络的matlab实现
1 BP算法原理
BP算法是利用输出层的误差来估计输出层的直接前导层的误差,再用这个误差估计更前一层的误差。如此下去,就获得了所有其他各层的误差估计。这样就形成了将输出端表现出的误差沿着与输入信号传送相反的方向逐级向网络的输入端传递的过程。因此,人们就又将此算法称为向后传播算法,简称BP算法。
2 BPNN的学习过程
–输入样本---输入层---各隐层---输出层
判断是否转入反向传播阶段:
–若输出层的实际输出与期望的输出不符
误差反传
–误差以某种形式在各层表示----修正各层单元的权值
最终达到:
网络输出的误差减少到可接受的程度
进行到预先设定的学习次数为止
3 BPNN的标准学习算法
输入层与中间层的连接权值:$w_{ih}$
隐含层与输出层的连接权值:$w_{ho}$
隐含层各神经元的阈值:$b_h$
输出层各神经元的阈值:$b_o$
样本数据个数:$k=1,2,\cdots,m$
激活函数: $f(\cdot)$
误差函数:$e=\frac{1}{2}\sum^q_{o=1}(d_o(k)-yo_o(k))^2$
第一步,网络初始化
–给各连接权值分别赋一个区间(-1,1)内的随机数,设定误差函数$e$,给定计算精度值$\varepsilon$和最大学习次$M$。
第二步,随机选取第$k$个输入样本及对应期望输出
$$ x(k)=(x_1(k),x_2(k),\cdots,x_n(k))\\ d_o(k)=(d_1(k),d_2(k),\cdots,d_q(k))\\ $$
第三步,计算隐含层各神经元的输入和输出:
$$ hi_h(k)=\sum^n_{i=1}w_{ih}x_i(k)-b_h \quad h=1,2,\cdots,p\\ ho_h(k)=f(hi_h(k)) \quad h=1,2,\cdots,p\\ yi_o(k)=\sum^p_{h=1}w_{ho}ho_h(k)-b_o \quad o=1,2,\cdots,q\\ yo_o(k)=f(yi_o(k)) \quad o=1,2,\cdots,q\\ $$
第四步,利用网络期望输出和实际输出,计算误差函数对输出层的各神经元的偏导数$\delta_o(k)$。
$$ \frac{\partial e}{\partial w_{ho}}=\frac{\partial e}{\partial yi_o}\frac{\partial yi_o}{\partial w_{ho}}\\ \frac{\partial yi_o(k)}{\partial w_{ho}}=\frac{\partial(\sum^p_hw_{ho}ho_h(k)-b_o)}{\partial w_{ho}}=ho_h(k)\\ \frac{\partial e}{\partial yi_o}=\frac{\partial\frac{1}{2}\sum^q_{o=1}(d_o(k)-yo_o(k))^2}{\partial yi_o}=-(d_o(k)-yo_o(k))yo'_o(k)\\ =-(d_o(k)-yo_o(k))f'(yi_o(k)) \dot=-\delta_o(k) $$
第五步,利用隐含层到输出层的连接权值、输出层的 $\delta_o(k)$和隐含层的输出计算误差函数对隐含层各神经元的偏导数$\delta_h(k)$
$$ \frac{\partial e}{\partial w_{ho}}=\frac{\partial e}{\partial yi_o}\frac{\partial yi_o}{\partial w_{ho}}=-\delta_o(k)ho_h(k)\\ \frac{\partial e}{\partial w_{ih}}=\frac{\partial e}{\partial hi_h(k)}\frac{\partial hi_h(k)}{\partial w_{ih}}\\ \frac{\partial hi_h(k)}{\partial w_{ih}}=\frac{\partial(\sum^n_{i=1}w_{ih}x_i(k)-b_h)}{\partial w_{ih}}=x_i(k) $$
第六步,利用输出层各神经元的$ \delta_o(k)$和隐含层各神经元的输出来修正连接权值$w_{ho}(k)$
$$ \Delta w_{ho}(k)=-\mu\frac{\partial e}{\partial w_{ho}}=\mu\delta_o(k)ho_h(k)\\ w_{ho}^{N+1}=w_{ho}^N+\eta\delta_o(k)ho_h(k)\\ $$
第七步,利用隐含层各神经元的$ \delta_h(k)$和输入层各神经元的输入修正连接权。
$$ \Delta w_{ih}(k)=-\mu\frac{\partial e}{\partial w_{ih}}=-\mu\frac{\partial e}{\partial hi_h(k)}\frac{\partial hi_h(k)}{\partial w_{ih}}=\delta_h(k)x_i(k)\\ w_{ih}^{N+1}=w_{ih}^N+\eta\delta_h(k)x_i(k)\\ $$
第八步,计算全局误差
$$ E=\frac{1}{2m}\sum^m_{k=1}\sum^q_{o=1}(d_o(k)-y_o(k))^2\\ $$
第九步,判断网络误差是否满足要求。当误差达到预设精度或学习次数大于设定的最大次数,则结束算法。否则,选取下一个学习样本及对应的期望输出,返回到第三步,进入下一轮学习。
4 BPNN的matlab实现
函数newff之前讲过了:
net=newff(PR,[S1 S2...SN],{TF1 TF2... TFN},BTF,BLF,PF)
PR:一个R×2矩阵, 由R维输入向量的每维最小值和最大值组成
Si:第i层的神经元个数
TFi:第i层的传递函数,默认为tansig
BTF:训练函数,默认为trainlm
BLF:学习函数,默认为learngdm
PF:性能函数,默认为mse
net=newff([0,10;1,2],[5,1],{‘tansig’,’purelin’},’trainlm’);
%生成一个两层BP网络,隐层和输出层神经的个数为5和1,传递函数分别为tansig和purelin,训练函数为trainlm,其他默认
lBPNN的初始化:函数init
newff 函数在建立网络对象的同时, 自动调用初始化函数, 根据缺省的参数设置网络的连接权值和阈值.
使用函数init可以对网络进行自定义的初始化. 通过选择初始化函数, 可对各层连接权值和阈值分别进行不同的初始化.
lBPNN的训练:函数train
利用已知的“输入——目标”样本向量数据对网络进行训练,采用train函数完成。训练之前,对训练参数进行设置:
net = train(net,P,T)
训练参数 | 参数含义 | 默认值 |
---|---|---|
net.trainParam.epochs | 训练步数 | 100 |
net.trainParam.show | 显示训练结果的间隔步数 | 25 |
net.trainParam.goal | 训练目标误差 | 0 |
net.trainParam.time | 训练允许时间 | INF |
net.trainParam.lr | 学习率 | 0.01 |
BPNN的训练:学习算法的选择
matlab神经网络工具箱对常规的BP算法进行改进,提供了一系列快速算法,以满足不同问题的需要
学习算法 | 适用问题类型 | 收敛性能 | 占用存储空间 | 其他特点 |
---|---|---|---|---|
trainlm | 函数拟合 | 收敛快,误差小 | 大 | 性能随网络规模增大而变差 |
trainrp | 模式分类 | 收敛最快 | 较小 | 性能随着网络训练误差减小而变差 |
trainscg | 函数拟合与模式分类 | 收敛较快性能稳定 | 中等 | 尤其适用于网络国模较大的情况 |
trainbfg | 函数拟合 | 收敛较快 | 较大 | 计算量随着网络规模的增大呈几何增长 |
traingdx | 模式分类 | 收敛较慢 | 较小 | 适用于提前停止的方法 |
BPNN的仿真或者测试:函数sim或net
A=sim(net,p) %网络仿真
A=net(p) %网络仿真
4.1 一般步骤
数据归一化——mapminmax
创建BP网络——newff
初始化——init
训练算法——trainlm(速度快,需存储空间大)
学习规则——learngdm
网络训练——train
仿真——net,sim
BP神经网络实例
例:公路运量预测问题:公路运量主要包括公路的客运量和公路货运量两个方面。据研究,某地区的公路运量主要与该地区的人数、机动车数量和公路面积有关,表1给出了20年的公路运量相关数据,表中单位分别为万人/万量/万平方千米/万吨/万人。
根据有关部门数据,该地区2010年和2011年的人数分别为73.39和75.55万人,机动车数量分别为3.9635和4.0975万辆,公路面积将分别为0.9880和1.0268万平方米。
请利用BP神经网络预测该地区2010年2011年得公路客运量和公路货运量。
BP网络求解步骤:
1)原始数据的输入;
2)数据归一化;
3)网络建立以及训练;
4)对原始数据进行仿真;
5)将原始数据仿真的结果与已知样本进行对比;
6)对新数据进行仿真。
(1)原始数据的输入:
sqrts=[20.55 22.44 25.37 27.13 29.45 30.10 30.96 34.06 36.42 38.09 39.13 39.99 41.93 44.59 47.30 52.89 55.73 56.76 59.17 60.63];%人数(单位:万人)
sqjdcs=[0.6 0.75 0.85 0.91 1.05 1.35 1.45 1.6 1.7 1.85 2.15 2.2 2.25 2.35 2.5 2.6 2.7 2.85 2.95 3.1];%机动车数(单位:万辆)
sqglmj=[0.09 0.11 0.11 0.14 0.20 0.23 0.23 0.32 0.32 0.34 0.36 0.36 0.38 0.49 0.56 0.59 0.59 0.67 0.69 0.79];%公路面积
glkyl=[5126 6217 7730 9145 10460 11387 12353 15750 18304 19836 21024 19490 20433 22598 25107 33442 36836 40548 42927 43462]%公路客运量
glhyl=[1237 1379 1385 1399 1663 1714 1834 4322 8132 8936 11099 11203 10524 11115 13320 16762 18673 20724 20803 21804];%公路货运量
p=[sqrts;sqjdcs;sqglmj];%输入数据矩阵
t=[dlhyl;glhyl];%目标数据矩阵
(2)归一化:利用函数premnmx对数据做归一化处理:
[pn,minp,maxp,tn,mint,maxt]=premnmx(p,t);
dx=[-1,1;-1,1;-1,1];
(3)训练:利用处理好的数据对网络进行训练:
%BP网络训练
net=newff(dx,[3,2],{'tansig','tansig','purelin'},'traingdx');
net.trainParam.show=2000; %显示训练结果的间隔步数
net.trainParam.Lr=0.05; %学习率
net.trainParam.epochs=20000; %训练步数
net.trainParam.goal=0.65*10^(-3); %训练目标误差
net=train(net,pn,tn);
an=sim(net,pn);
a=postmnmx(an,mint,maxt);
pnew=[73.39 75.55
3.9635 4.0975
0.9880 1.0268];
pnewn=tramnmx(pnew,minp,maxp);
anewn=sim(net,pnewn);
anew=postmnmx(anewn,mint,maxt);
(4)用原始数据仿真的结果和已知数据进行对比:
x=1990:2009;
newk=a(1,:);
newh=a(2,:);
figure(2);
subplot(2,1,1);
plot(x,newk,'r-o',x,glkyl,'b--+');
legend('网络输出客运量','实际客运量');
xlabel('年份');ylabel('客运量/万人');
title('运用工具箱客运量学习和测试对比图');
hold on
plot([2010,2011],[anew(1,:)],'r-o');
subplot(2,1,2);plot(x,newh,'r-o',x,glhyl,'b--+');
legend('网络输出货运量','实际货运量');
xlabel('年份');
ylabel('货运量/万人');
title('运用工具箱货运量学习和测试对比图');
hold on
plot([2010,2011],[anew(2,:)],'r-o');
总程序如下:
sqrts=[20.55 22.44 25.37 27.13 29.45 30.10 30.96 34.06 36.42 38.09 39.13 39.99 41.93 44.59 47.30 52.89 55.73 56.76 59.17 60.63];%人数(单位:万人)
sqjdcs=[0.6 0.75 0.85 0.91 1.05 1.35 1.45 1.6 1.7 1.85 2.15 2.2 2.25 2.35 2.5 2.6 2.7 2.85 2.95 3.1];%机动车数(单位:万辆)
sqglmj=[0.09 0.11 0.11 0.14 0.20 0.23 0.23 0.32 0.32 0.34 0.36 0.36 0.38 0.49 0.56 0.59 0.59 0.67 0.69 0.79];%公路面积
glkyl=[5126 6217 7730 9145 10460 11387 12353 15750 18304 19836 21024 19490 20433 22598 25107 33442 36836 40548 42927 43462];%公路客运量
glhyl=[1237 1379 1385 1399 1663 1714 1834 4322 8132 8936 11099 11203 10524 11115 13320 16762 18673 20724 20803 21804];%公路货运量
p=[sqrts;sqjdcs;sqglmj];%输入数据矩阵
t=[glkyl;glhyl];%目标数据矩阵
[pn,minp,maxp,tn,mint,maxt]=premnmx(p,t);
dx=[-1,1;-1,1;-1,1];
net=newff(dx,[3,2],{'tansig','tansig','purelin'},'traingdx');
net.trainParam.show=2000;
net.trainParam.Lr=0.05;
net.trainParam.epochs=20000;
net.trainParam.goal=0.65*10^(-3);
net=train(net,pn,tn);
an=sim(net,pn);
a=postmnmx(an,mint,maxt);
pnew=[73.39 75.55
3.9635 4.0975
0.9880 1.0268];
pnewn=tramnmx(pnew,minp,maxp);
anewn=sim(net,pnewn);
anew=postmnmx(anewn,mint,maxt);
x=1990:2009;
newk=a(1,:);
newh=a(2,:);
figure(2);
subplot(2,1,1);
plot(x,newk,'r-o',x,glkyl,'b--+');
legend('网络输出客运量','实际客运量');
xlabel('年份');ylabel('客运量/万人');
title('运用工具箱客运量学习和测试对比图');
hold on
plot([2010,2011],[anew(1,:)],'r-o');
subplot(2,1,2);
plot(x,newh,'r-o',x,glhyl,'b--+');
legend('网络输出货运量','实际货运量');
xlabel('年份');
ylabel('货运量/万人');
title('运用工具箱货运量学习和测试对比图');
hold on
plot([2010,2011],[anew(2,:)],'r-o');
anew %输出2010和2011年的公路客运量和货运量
得到结果:
也就是说:
2010年和2011年的公路客运量分别为44451万人和22058万人,2010年和2011年的公路货运量分别为44496万吨和22059万吨。