解决Matlab 调用训练好的BP网络的权值和阀值算出来的预测值和调用sim得到的值不一样的办法

解决方法

解决方法很简单:自己通过训练好的权值和阈值计算时,归一化和反归一化的范围应该设为(-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。

以下将以经典的BP神经网络——基于近红外光谱的汽油辛烷值预测为例

原始的程序和数据集大家可以自行百度、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神经网络程序
以上

  • 8
    点赞
  • 85
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值