BP神经网络实验详解(MATLAB实现)

前言

分享一份之前上神经网络课上布置的练习题Demo。参数什么的可能在不同电脑上需要有所调整,还望用餐愉快。

题目

设计实现模糊控制规则为T = int((e+ec)/2)的模糊神经网络控制器,其中输入变量e和ec的变化范围分别是:e = int[-2, 2],ec = int[-2, 2]。网络设计的目标误差为0.001。

解答

1.网络结构

输入输出数据根据题意列出:
P=[-2 -2 -2 -2 -2 -1 -1 -1 -1 -1 0 0 0 0 0 1 1 1 1 1 2 2 2 2 2; -2 -1 0 1 2 -2 -1 0 1 2 -2 -1 0 1 2 -2 -1 0 1 2 -2 -1 0 1 2 ];

T=[-2 -2 -1 -1 0 -2 -1 -1 0 0 -1 -1 0 0 1 -1 0 0 1 1 0 0 1 1 2];

因此输入为25组样本,需要输入节点数为2输出节点数仅需1即可。

由于输入输出节点数很少,因此优先考虑单层隐含层神经网络。即网络结构初步定为2-S1-1,隐含层采用S型正切激活函数,输出层采用线性激活函数,隐含层节点数待定。

2. 隐含层节点数S1的确定

确定隐含层节点数需要通过对S1取不同值的训练情况来分析,得出较好的S1作为确定的节点数。在此之前,需要大致初始化一个学习速率 lr。取最大训练次数epochs=10000 ;目标误差goal=0.001。

网络初始化及训练的MATLAB代码:

clear;
ec=[-2 -1 0 1 2];
%输入矢量,输入节点为2
P=[-2 -2 -2 -2 -2 -1 -1 -1 -1 -1 ...
 	0 0 0 0 0 1 1 1 1 1 2 2 2 2 2;
    -2 -1 0 1 2 -2 -1 0 1 2 -2 -1 ...
    0 1 2 -2 -1 0 1 2 -2 -1 0 1 2];	   
%输出矢量    
T=[-2 -2 -1 -1 0  -2 -1 -1 0 0  -1 ...
  -1 0 0 1 -1  0  0 1 1 0 0 1 1 2]; 
[R, Q]=size(P);
[S2, Q]=size(T);
 
%初始化网络结构和参数
%隐含层节点数,需要修改调整的参数
%输出层采用线性激活函数,隐含层采用S型正切函数
S1=10; 
W1=rands(S1,R);
B1=rands(S1,1);
W2=rands(S2,S1);
B2=rands(S2,1);  
%创建两层前向回馈网络,梯度下降法
net=newff(minmax(P),[S1,1],{
     'tansig','purelin'},...
    'traingd'); 
%初始化训练次数
net.trainParam.epochs=10000; 
net.trainParam.goal=0.001;  
%调整学习速率   
net.trainParam.lr=0.03;
%训练网络,tr是训练参数
[net,tr]= train(net,P,T); 
Y = sim(net,P); 
 %查看训练时间
t=tr.time(end)
%计算均方差
SSE = perform(net,T,Y)  

得到的训练数据如下表所示:

表 1 取 lr = 0.030 时的网络训练记录

S1 误差平方和 训练次数 时间(秒) 误差过程记录
8 0.0328 10000 22.136 有收敛趋势
9 0.0436 10000 23.076 有收敛趋势
10 0.0334 10000 25.421 曲线平滑,有收敛趋势
11 0.0211 10000 23.254 曲线有波动,有收敛趋势
12 0.0039 10000 21.759 前期下降快,后期收敛很慢
13 0.0093 10000 24.266 梯度变化部分不均匀

即使隐含层节点已经相对较多的情况下效果依然不够理想,但并未出现振荡及发散现象。推测lr取值较小导致,因而收敛速度较慢,因此适当增大lr的取值,新得到的训练结果如表2所示:

表 2 取 lr = 0.060 时的网络训练记录

S1 误差平方和 训练次数 时间(秒) 误差过程记录
6 0.0257 10000 27.169 曲线较平滑,有收敛趋势
7 0.0211 10000 29.476 曲线较平滑,有收敛趋势
8 0.0036 10000 28.869 有下降收敛趋势
9 0.0147 10000 26.687 曲线有点波动,有收敛趋势
10 0.0031 10000 26.638 下降较快,曲线非常平滑
11 0.0010 7425 20.199 下降很快,曲线平滑
12 0.0027 10000 27.884 有下降收敛趋势,曲线平滑
13 0.0010 8996 25.801 曲线光滑但后期收敛慢
15 0.0010 4976 14.838 下降很快,梯度变化部分不均匀
18 0.0010 869 5.766 下降很快,梯度变化均匀

由表2可看出,随着S1的增加,误差梯度下降加快;但同时每次迭代的计算量增加,整体训练时间可能会增加。当S1=8,10~18几乎都能达到目标误差同时误差下降很快。但是,当S1取值过大会造成网络的泛化性能变差。根据误差过程记录、误差平方和以及时间综合考虑,选取S1=11

3. 学习速率的影响

在确定较好的S1后,针对不同的lr取值,分别对网络进行重新训练,得到表3的记录。

表 3 不同lr 取值的网络训练记录

lr 误差平方和 训练次数 时间(秒) 误差过程记录
0.03 0.0019 10000 19.592 曲线轻微波动下降
0.05 0.0031 10000 20.167 曲线下降平滑
0.055 0.0184 10000 21.780 曲线下降平滑
0.06 0.001 7424 15.520 曲线快速下降且平滑
0.062 0.001 7080 20.119 曲线快速下降,有些波动
0.065 0.0043 10000 23.912 误差直线下降且快速
0.08 0.0011 10000 20.851 曲线快速下降且平滑
0.1 0.001 8744 18.965 曲线快速下降,有一定幅度波动
0.2 0.001 5824 17.865 出现高尖刺和振荡现象
0.3 —— —— —— 直接发散

由表3可以看出,学习速率的增加可以使梯度下降步长变大,能够更快到达误差目标;但当学习速率过大时,会出现在极小值周围来回跳跃,即产生振荡现象,甚至发散,难以满足期望目标。综合误差、时间和记录因素考虑,取lr=0.06

4. 自适应与固定学习速率的比较

使用自适应学习速率仅需将newff.m中参数换为’traingd’换为’traingda’即可。此时,可以设置初始学习速率为lr=0.03。得到结果为:
t = 8.0160;
SSE = 9.9666e-04;
Epochs = 3564;

与上表中最好结果相比,自适应学习速率训练时间更短,同时也省去了为确定合适的学习速率而进行大量调参训练的时间。但是误差曲线呈锯齿状下降,属于算法本身的缘故。

5. 改进算法之间的比较

保持之前所有参数不变,通过不断变换newff的参数使用不同算法进行训练,并与标准梯度下降法进行分析比较,本次进行对比的算法有:附加动量法,自适应学习速率法,BFGS拟牛顿法和Levenberg-Marquardt法,训练结果如下表:

表 4 不同改进算法的网络训练记录

函数 算法 误差平方和 训练次数 时间(秒)
traingd 标准梯度下降法 0.0276 10000 21.8730
traingda 自适应学习速率法 0.00099666 3564 8.0160
traingdm 附加动量法 0.0139 10000 19.442
trainbfg BFGS拟牛顿法 0.00097212 92 0.599
trainlm Levenberg-Marquardt法 0.00024548 7 0.258

从表中的记录可以看出,尽管自适应学习速率法已经在原有算法基础上减少了一定的训练时间,但BFGS拟牛顿法和Levenberg-Marquardt法的表现惊人,在本人电脑上几乎眨眼之间便完成了训练,同时误差精度也是几个算法中最高的,尤其是后者,如此的优化实在令人佩服。附加动量法相比于标准的梯度下降法在误差精度和训练时间上也有一定的改善,但跟其他算法相比实在逊色不少。

6. 插值验证

根据上面的分析确定了神经网络的结构为2-11-1的单层前向神经网络,隐含层采用S型正切激活函数,输出层采用线性激活函数。训练得到的神经网络使用插值法作为测试集输入验证其性能。

训练点数组的取值范围为int[-2, 2],因此,测试点采用每间隔0.5取一个点的方式进行插值,输出规则与之前一致向下取整。

测试集输入为一个2×81的矩阵,期望输出为1×81的行向量(太长了就不写了)。代码如下:

%样本插值进行测试
P1 = zeros();
T1 = zeros();
e1 = -2:0.5:2;
ec1 = -2:0.5:2;
for i=1:9
    for j=1:9
        r = (i-1)*9+j;
        P1(1,r)=e1(i);
        P1(2,r)=ec1(j);
        T1(r)=floor((e1(i)+ec1(j))/2);
    end
end
P1  %查看输入
T1  %查看输出
A = sim(net,P1)
error = perform(net,T1,A)  %计算误差

最后计算出的误差为:error = 0.0520。通过观察比对期望和实际输出,发现在计算某些插值点时,实际输出会围绕在x.5周围,导致整体误差偏大。

你可能感兴趣的:(人工智能,神经网络,算法,人工智能,机器学习)