赞
踩
解决方法很简单:自己通过训练好的权值和阈值计算时,归一化和反归一化的范围应该设为(-1,1),而不是(0,1)。
也就是从原来的:
[p_train, ps_input] = mapminmax(Id',0,1);
[t_train, ps_output] = mapminmax(train_y',0,1);
改为:
[p_train, ps_input] = mapminmax(Id',-1,1);
[t_train, ps_output] = mapminmax(train_y',-1,1);
本文在这篇论坛上得到提示:Matlab训练好BP神经网络后,怎么根据权值和阈值来计算呢?
此方法仅供参考,可能大家的情况有所不同,希望对大家有帮助。
以上为原回答
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
以下为10月10日更新
之前在评论区答应了过几天就补全回答,没想到一下子耽搁了3个月,实在是抱歉!
之前的答案这一句话“自己通过训练好的权值和阈值计算时”有误,应该是在一开始训练BP神经网络的时候就把归一化和反归一化的范围设为(-1,1),而不是采用(0,1),对了,我用的matlab版本为2019b。
原始的程序和数据集大家可以自行百度、google或者在github上寻找,我在文中也会给出程序,找不到数据集的人可以说自己邮箱,我看到的话会回,不过我后面也挺忙的,不保证及时性。
原始的BP神经网络程序如下:
%% I. 清空环境变量 clear all close all clc %% II. 训练集/测试集产生 %% % 1. 导入数据 load spectra_data.mat %% % 2. 随机产生训练集和测试集 temp = randperm(size(NIR,1)); % 训练集——50个样本 P_train = NIR(temp(1:50),:)'; T_train = octane(temp(1:50),:)'; % 测试集——10个样本 P_test = NIR(temp(51:end),:)'; T_test = octane(temp(51:end),:)'; N = size(P_test,2); %% III. 数据归一化 [p_train, ps_input] = mapminmax(P_train,0,1); p_test = mapminmax('apply',P_test,ps_input); [t_train, ps_output] = mapminmax(T_train,0,1); %% IV. BP神经网络创建、训练及仿真测试 %% % 1. 创建网络 net = newff(p_train,t_train,8); %% % 2. 设置训练参数 net.trainParam.epochs = 1000;%最大训练次数设置 net.trainParam.goal = 1e-3;%训练目标设置,及要求精度 net.trainParam.lr = 0.01;%学习率设置,应设置为较小值 %% % 3. 训练网络 net = train(net,p_train,t_train); %% % 4. 仿真测试 t_sim = sim(net,p_test); %% % 5. 数据反归一化 T_sim = mapminmax('reverse',t_sim,ps_output); %% V. 性能评价 %% % 1. 相对误差error error = abs(T_sim - T_test)./T_test; %% % 2. 决定系数R^2 R2 = (N * sum(T_sim .* T_test) - sum(T_sim) * sum(T_test))^2 / ((N * sum((T_sim).^2) - (sum(T_sim))^2) * (N * sum((T_test).^2) - (sum(T_test))^2)); %% % 3. 结果对比 result = [T_test' T_sim' error'] %% VI. 绘图 figure plot(1:N,T_test,'b:*',1:N,T_sim,'r-o') legend('真实值','预测值') xlabel('预测样本') ylabel('辛烷值') string = {'测试集辛烷值含量预测结果对比';['R^2=' num2str(R2)]}; title(string)
从上述程序中我们可以发现,在数据归一化的位置是将范围设定在(0,1)之间,但是我在实际操作中发现,在照搬根据(0,1)归一化的mapminmax函数的参数后,计算出来的神经网络输出值和原神经网络的不同,那么怎么解决这个问题呢,就像我前面说的,我们只需要将上面的原始BP神经网络的归一化范围改为(-1,1)。具体的原因我也没想明白,我猜也许matlab内部的调用函数不太一样,如果有大佬知道的请多多指教。
现在让我们将上述程序中的这部分:
%% III. 数据归一化
[p_train, ps_input] = mapminmax(P_train,0,1);
p_test = mapminmax('apply',P_test,ps_input);
[t_train, ps_output] = mapminmax(T_train,0,1);
改为
%% III. 数据归一化
[p_train, ps_input] = mapminmax(P_train,-1,1);
p_test = mapminmax('apply',P_test,ps_input);
[t_train, ps_output] = mapminmax(T_train,-1,1);
这样改变归一化范围并不会对神经网络预测精确度产生什么影响。
运行更改后的BP神经网络主程序之后,我们就可以得到如下的预测结果图:
同时我们在工作区中会得到大量的计算变量,如下图:
其中我们在后续需要用到的数据是红框中的三个,分别是训练好的神经网络和归一化反归一化的函数参数,其中需要我们自行提取的只有训练好的net变量中的网络权值和阈值参数。
这里有两种方法,参看如下程序:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%方法一:
genFunction(net); %提取函数net
%或者如下
%方法二:
IW1_1 = net.iw{1,1};
b1 = net.b{1};
LW2_1 = net.lw{2,1};
b2 = net.b{2};
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
方法二就不细说了,其他文章中已经有提到过,想弄明白的同学可以参看help中“network”的文档。
方法一则是运行genFunction函数,然后点击命令行窗口的“edit neural_function”:
然后会跳出“neural_function”函数,其中就有已经训练好的权值和阈值,也就是其中的b和IW,LW,我们只需要将其复制过来:
IW为输出层到隐含层的权值,b1为输入层到隐含层的阈值;LW即为隐含层到输出层的权值,b2为隐含层到输出层的阈值。
同时,我们还能在“neural_function”函数中找到程序内部运行神经网络的循环计算代码:
for ts=1:TS
% Input 1
Xp1 = mapminmax_apply(X{1,ts},x1_step1);
% Layer 1
a1 = tansig_apply(repmat(b1,1,Q) + IW1_1*Xp1);
% Layer 2
a2 = repmat(b2,1,Q) + LW2_1*a1;
% Output 1
Y{1,ts} = mapminmax_reverse(a2,y1_step1);
end
和sigmoid的传递函数:
% Sigmoid Symmetric Transfer Function
function a = tansig_apply(n,~)
a = 2 ./ (1 + exp(-2*n)) - 1;
end
我在后续自行建立训练好的神经网络时既是参考的上图的循环算式。具体程序如下:
% clear all % close all % clc %% 创建神经网络参数 % Layer 1;b1:隐含层偏移量;IW1_1:隐含层权值 b1 = [1.3748057355138554314;-1.0270389076505417325]; IW1_1 = [-0.033329920682804686782 -0.046980249869347533165]; % Layer 2;b2:输出层偏移量;LW2_1:输出层权值 b2 = -0.70620702517192035508; LW2_1 = [-0.50069237473355243662 -0.31059943234833836678]; %% 计算 p_test1 = mapminmax('apply',P_test,ps_input); a1 = tansig(b1+IW1_1*p_test1); a2 =b2+LW2_1*a1; T_sim_t = mapminmax('reverse',a2,ps_output); %% 作图 figure(1) plot(1:N,T_sim,'r-o'); hold on plot(1:N,T_sim_t,'b-*');
上述代码中,前三行加引号是因为还需要使用之前得到的变量“ps_input”和“ps_output”,避免直接点运行按钮就把之前的变量都删除掉了,另外,这里的b1、b2、IW、LW这么短是因为本来的变量参数有401列,全部放出来太长了,在这里我就略去了,大家自己弄的时候注意。
以下是运行结果图,其中红色是原始神经网络的计算结果,蓝色是我们提取出训练好的net参数的计算结果:
可以看到和原始训练好的神经网络结果完全一致,但是假如我们还是采用(0,1)的归一化范围的话,得到的对比图则如下:
我也不明白为什么会出现这样的情况,希望有懂的大佬可以告知。
欢迎在评论区留言讨论,也欢迎指正错误。
有兴趣的同学也可以参看这一篇博客:MATLAB编写自己的BP神经网络程序
以上
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。