参考学习b站资源:
数学建模学习交流
bp神经网络预测matlab代码实现过程
神经网络简介
最早的神经网络模型, 单层感知器perceptron,结构如下:
这是一个两层的神经网络,第一层为输入层,第二层为输出层。因为只有在输出层需要进行计算,就是说只有一层计算层,所以称之为单层感知器。从形式上看,仅仅是将MP模型中的输入信号当作了独立的一层神经元,但是本质上却有很大差别。
感知器模型中权重和阈值不再是固定的了,而是计算机"学习"出来的结果。引入了损失函数的概念,通过迭代不断调整权重和阈值,使得损失函数最小,以此来寻找最佳的权重和阈值。
单层感知器只可以解决线性可分的问题,在单层感知器的基础上,再引入一层神经元,构成一个3层的神经网络,结构如下:
这样的一个神经网络模型,适用范围更广,涵盖了线性和非线性可分的场景。其中的每一层称之为layer, 除了输出层和输出层之外,还有中间的隐藏层。这样的神经网络模型,通过反向传播算法来求解。
增加一层的好处在于更好的数据表示和函数拟合的能力,在3层的基础上,再引入更多的隐藏层,就变成了深度神经网络,图示如下:
可以看到,每增加一层,模型的参数数量急剧增加,所以深度学习对计算资源的要求特别高,在实际使用中,模型训练时间非常的久。
虽然耗费计算资源,但是深度学习的优点也很突出,相比机器学习,模型自动完成特征提取,不需要人工的特征工程,这一点对于高维数据的处理特别重要
【改编】辛烷值是汽油最重要的品质指标,传统的实验室检测方法存在样品用量大,测试周期长和费用高等问题,不适用于生产控制,特别是在线测试。近年发展起来的近红外光谱分析方法(NIR),作为一种快速分析方法,已广泛应用于农业、制药、生物化工、石油产品等领域。其优越性是无损检测、低成本、无污染,能在线分析,更适合于生产和控制的需要。
实验采集得到50组汽油样品(辛烷值已通过其他方法测量),并利用傅里叶近红外变换光谱仪对其进行扫描,扫描范围900~1700nm,扫描间隔为2nm,即每个样品的光谱曲线共含401个波长点,每个波长点对应一个吸光度。
首先导入数据:
new_X:需要预测的输入层数据
X:样品的输入层数据
Y:样品的输出层数据
%% 此程序为matlab编程实现的BP神经网络
% 清空环境变量
% clear
close all %关闭所有图形窗口
clc
%%第一步 读取数据
input=X; %载入输入数据
output=Y; %载入输出数据
%% 第二步 设置训练数据和预测数据
% 注意要将指标变为列向量
input_train = input(1:40,:)';
output_train =output(1:40,:)';
input_test = input(41:50,:)';
output_test =output(41:50,:)';
%节点个数
inputnum=401; % 输入层节点数量
hiddennum=10; % 隐含层节点数量
outputnum=1; % 输出层节点数量
%% 第三本 训练样本数据归一化
[inputn,inputps]=mapminmax(input_train);%归一化到[-1,1]之间,inputps用来作下一次同样的归一化
[outputn,outputps]=mapminmax(output_train);
%% 第四步 构建BP神经网络
net=newff(inputn,outputn,hiddennum,{'tansig','purelin'},'trainlm');% 建立模型,传递函数使用purelin,采用梯度下降法训练
W1= net. iw{1, 1}; %输入层到中间层的权值
B1 = net.b{1}; %中间各层神经元阈值
W2 = net.lw{2,1}; %中间层到输出层的权值
B2 = net. b{2}; %输出层各神经元阈值
%% 第五步 网络参数配置( 训练次数,学习速率,训练目标最小误差等)
net.trainParam.epochs=1000; % 训练次数,这里设置为1000次
net.trainParam.lr=0.01; % 学习速率,这里设置为0.01
net.trainParam.goal=0.00001; % 训练目标最小误差,这里设置为0.00001
%% 第六步 BP神经网络训练
net=train(net,inputn,outputn);%开始训练,其中inputn,outputn分别为输入输出样本
%% 第七步 测试样本归一化
inputn_test=mapminmax('apply',input_test,inputps); % 对样本数据进行归一化
%% 第八步 BP神经网络预测
an=sim(net,inputn_test); %用训练好的模型进行仿真
%% 第九步 预测结果反归一化与误差计算
test_simu=mapminmax('reverse',an,outputps); %把仿真得到的数据还原为原始的数量级
error=test_simu-output_test; %预测值和真实值的误差
%%第十步 真实值与预测值误差比较
figure('units','normalized','position',[0.119 0.2 0.38 0.5])
plot(output_test,'bo-')
hold on
plot(test_simu,'r*-')
hold on
plot(error,'square','MarkerFaceColor','b')
legend('期望值','预测值','误差')
xlabel('数据组数')
ylabel('样本值')
title('BP神经网络测试集的预测值与实际值对比图')
[c,l]=size(output_test);
MAE1=sum(abs(error))/l;
MSE1=error*error'/l;
RMSE1=MSE1^(1/2);
disp(['-----------------------误差计算--------------------------'])
disp(['隐含层节点数为',num2str(hiddennum),'时的误差结果如下:'])
disp(['平均绝对误差MAE为:',num2str(MAE1)])
disp(['均方误差MSE为: ',num2str(MSE1)])
disp(['均方根误差RMSE为: ',num2str(RMSE1)])
关于隐含层数的确定(这里是10),需要注意的是:
训练结果:
-----------------------误差计算--------------------------
隐含层节点数为10时的误差结果如下:
平均绝对误差MAE为:0.30444
均方误差MSE为: 0.14714
均方根误差RMSE为: 0.38359
predict_y = zeros(10,1); % 初始化predict_y
pre_test=mapminmax('apply',new_X(:,:)',inputps);% 对预测数据进行归一化
for i = 1: 10
result = sim(net, pre_test(:,i));
predict_y(i) = result;
end
disp('预测值为:')
predict_y=mapminmax('reverse',predict_y,outputps); %把预测结果还原
disp(predict_y)
结果:
预测值为:
87.9633
87.8581
88.8067
85.4666
85.3155
83.1005
86.3266
86.7106
89.1940
87.0632
需要注意的是,不同的神经网络模型参数会对预测值有影响,比如隐含层的个数(默认为10),测试集比例,训练方法等,另一方面,样本数量的局限或是模型的质量也都有可能对结果有很大的影响
在Matlab的菜单栏点击APP,再点击Neural Fitting app(神经网络工具箱):
注意选择样本在行上面(Matrix rows),也就是说每一行对应一个样本的所有数据
之后出现:
解释:
训练集(Training set) —— 用于模型拟合的数据样本。
验证集(Validation set)—— 是模型训练过程中单独留出的样本集,它可以用于调整模型的超参数和用于对模型的能力进行初步评估。在神经网络中,我们用验证数据集去寻找最优的网络深度,或者决定反向传播算法的停止点或者在神经网络中选择隐藏层神经元的数量;
测试集(Testing set) —— 用来评估模最终模型的泛化能力。但不能作为调参、选择特征等算法相关的选择的依据。
之后默认选择隐含层的个数为10(就是说有10个神经元进行预测):
之后选择训练方法:
解释:
三种训练方法:
莱文贝格-马夸特方法(Levenberg–Marquardt algorithm)
贝叶斯正则化方法(Bayesian‐regularization)
量化共轭梯度法(Scaled Conjugate Gradient )
选择合适的进行训练即可
训练结果:
在时刻9(训练了9次)出现了最低的均方误差,选择时刻9的模型为最佳模型:
将拟合值对真实值回归,拟合优度越高,说明拟合的的效果越好:
对应的神经网络图:
最后保存训练出来的神经网络模型:
其中 net 即训练出来的神经网络模型
进行预测:
% 写一个循环,预测接下来的十个样本的辛烷值
% 注意要将指标变为列向量,然后再用sim函数预测
predict_y = zeros(10,1); % 初始化predict_y
for i = 1: 10
result = sim(net, new_X(i,:)');
predict_y(i) = result;
end
disp('预测值为:')
disp(predict_y)
结果:
预测值为:
87.3547
87.1239
88.1194
84.9958
84.5796
85.4275
87.8986
86.4921
89.0483
87.4444
因为数据太多,博客只放了一部分,完整Excel可以在百度网盘下载:
传送门:
神经网络:辛烷值和光谱分析
提取码:
cccc
因为有人进行了提问:bp神经网络预测的问题,讨论区也有类似的问题,所以对辛烷值的预测进行了深入的讨论
上一个是预测一个辛烷值,这次我们将上一次的辛烷值做一个运算,生成一个辛烷值区间(其实就是想生成个一个区间的两个端点),自定义公式:
[ α , β ] = [ x − ∣ x r a n d i ( [ 9 , 11 ] ) ∣ , x + ∣ x r a n d i ( [ 11 , 13 ] ) ∣ ] \left[ \alpha ,\beta \right] =\left[ x-\left| \dfrac{x}{randi([9,11])}\right| ,x+\left| \dfrac{x}{randi([11,13])}\right| \right] [α,β]=[x−∣∣∣∣randi([9,11])x∣∣∣∣,x+∣∣∣∣randi([11,13])x∣∣∣∣]
我们生成 [ α , β ] \left[ \alpha ,\beta \right] [α,β]:
%init(1)是初始辛烷值,init(2)是α,init(3)是β
for i = 1: 50
init(i,2) = init(1)-init(1)/randi([9,11]);
init(i,3) = init(1)+init(1)/randi([11,13]);
end
数据如下(均保存2位小数):
辛烷值 α β
85.3 76.77 92.41
85.25 77.55 92.41
88.45 76.77 91.86
83.4 77.55 92.41
87.9 76.77 92.41
85.5 75.82 93.05
88.9 76.77 93.05
88.3 77.55 93.05
88.7 75.82 93.05
88.45 75.82 92.41
88.75 75.82 91.86
88.25 76.77 93.05
87.3 77.55 91.86
88 76.77 93.05
88.7 75.82 92.41
85.5 76.77 93.05
88.65 76.77 91.86
88.75 75.82 93.05
85.4 75.82 93.05
88.6 76.77 92.41
87 75.82 93.05
87.15 77.55 93.05
87.05 77.55 91.86
87.25 76.77 92.41
86.85 75.82 92.41
88.65 77.55 92.41
86.6 76.77 93.05
86 76.77 92.41
86.1 77.55 92.41
86.5 76.77 91.86
86.3 75.82 91.86
84.4 77.55 91.86
84.7 75.82 93.05
84.6 76.77 91.86
84.5 75.82 91.86
88.1 75.82 92.41
85.25 76.77 91.86
88.4 77.55 91.86
88.2 77.55 92.41
88.4 77.55 93.05
88.55 75.82 91.86
88.35 76.77 92.41
88.2 77.55 92.41
85.3 76.77 91.86
88.5 77.55 92.41
88.25 75.82 93.05
88 77.55 93.05
88.85 76.77 93.05
88.45 77.55 91.86
88.7 76.77 92.41
现在我们开始愉快的预测:
首先导入数据:
new_X:需要预测的输入层数据
X:样品的输入层数据
Y:样品的输出层数据
%% 此程序为matlab编程实现的BP神经网络
% 清空环境变量
% clear
close all %关闭所有图形窗口
clc
%%第一步 读取数据
input=X; %载入输入数据
output=Y; %载入输出数据
%% 第二步 设置训练数据和预测数据
% 注意要将指标变为列向量
input_train = input(1:40,:)';
output_train =output(1:40,:)';
input_test = input(41:50,:)';
output_test =output(41:50,:)';
%节点个数
inputnum=401; % 输入层节点数量
hiddennum=10; % 隐含层节点数量
outputnum=2; % 输出层节点数量
%% 第三本 训练样本数据归一化
[inputn,inputps]=mapminmax(input_train);%归一化到[-1,1]之间,inputps用来作下一次同样的归一化
[outputn,outputps]=mapminmax(output_train);
%% 第四步 构建BP神经网络
net=newff(inputn,outputn,hiddennum,{'tansig','purelin'},'trainlm');% 建立模型,传递函数使用purelin,采用梯度下降法训练
W1= net. iw{1, 1}; %输入层到中间层的权值
B1 = net.b{1}; %中间各层神经元阈值
W2 = net.lw{2,1}; %中间层到输出层的权值
B2 = net. b{2}; %输出层各神经元阈值
%% 第五步 网络参数配置( 训练次数,学习速率,训练目标最小误差等)
net.trainParam.epochs=1000; % 训练次数,这里设置为1000次
net.trainParam.lr=0.01; % 学习速率,这里设置为0.01
net.trainParam.goal=0.00001; % 训练目标最小误差,这里设置为0.00001
%% 第六步 BP神经网络训练
net=train(net,inputn,outputn);%开始训练,其中inputn,outputn分别为输入输出样本
%% 第七步 测试样本归一化
inputn_test=mapminmax('apply',input_test,inputps); % 对样本数据进行归一化
%% 第八步 BP神经网络预测
an=sim(net,inputn_test); %用训练好的模型进行仿真
%% 第九步 预测结果反归一化与误差计算
test_simu=mapminmax('reverse',an,outputps); %把仿真得到的数据还原为原始的数量级
error=test_simu-output_test; %预测值和真实值的误差
%%第十步 真实值与预测值误差比较
figure('units','normalized','position',[0.119 0.2 0.38 0.5])
plot(output_test,'bo-')
hold on
plot(test_simu,'r*-')
hold on
plot(error,'square','MarkerFaceColor','b')
legend('期望值','预测值','误差')
xlabel('数据组数')
ylabel('样本值')
title('BP神经网络测试集的预测值与实际值对比图')
[c,l]=size(output_test);
MAE1=sum(abs(error))/l;
MSE1=error*error'/l;
RMSE1=MSE1^(1/2);
disp(['-----------------------误差计算--------------------------'])
disp(['隐含层节点数为',num2str(hiddennum),'时的误差结果如下:'])
disp(['平均绝对误差MAE为:',num2str(MAE1)])
disp(['α的均方误差MSE为: ',num2str(MSE1(1,:))])
disp(['β的均方误差MSE为: ',num2str(MSE1(2,:))])
disp(['α的均方根误差RMSE为: ',num2str(RMSE1(1,:))])
disp(['β的均方根误差RMSE为: ',num2str(RMSE1(2,:))])
输出结果(图像有些小问题,应该是多条曲线的对比,有空会将它优化的QAQ ,但是整体思路都没问题):
-----------------------误差计算--------------------------
隐含层节点数为10时的误差结果如下:
平均绝对误差MAE为:0.28223 0.28882 0.16351 0.17373 0.078239 0.15954 0.045716 0.11022 0.16083 0.16366
α的均方误差MSE为: 1.8212 -0.021202
β的均方误差MSE为: -0.021202 0.42378
α的均方根误差RMSE为: 1.3495 -0.010599
β的均方根误差RMSE为: -0.010599 0.6509
clc;
predict_y = zeros(10,2); % 初始化predict_y
pre_test=mapminmax('apply',new_X(:,:)',inputps);% 对预测数据进行归一化
for i = 1: 10
result = sim(net, pre_test(:,i));
predict_y(i,1) = result(1);
predict_y(i,2) = result(2);
end
disp('预测值为:')
predict_y=mapminmax('reverse',predict_y,outputps); %把预测结果还原
disp(predict_y)
我们查看predict_y,没问题:
那么就是mapminmax
函数的问题,修改如下:
clc;
predict_y = zeros(10,2); % 初始化predict_y
pre_test=mapminmax('apply',new_X(:,:)',inputps);% 对预测数据进行归一化
for i = 1: 10
result = sim(net, pre_test(:,i));
predict_y(i,1) = result(1);
predict_y(i,2) = result(2);
end
disp('预测值为:')
predict_y=predict_y';
predict_y=mapminmax('reverse',predict_y,outputps); %把预测结果还原
disp(predict_y)
结果:
预测值为:
77.9596 80.1580 78.4421 77.6802 79.4339 79.4779 77.8803 79.3454 78.7957 77.8469
92.1225 91.6629 93.0518 92.4459 92.6326 92.3652 93.6457 93.1900 93.0095 93.6050
看一下predict_y,也没问题:
我们再转置回来得到正确结果:
那么为啥要这么修改呢,我们细细品(#^.^#) ,这要回到神经网络构建的时候了:
这两部分要对应上哇,哈哈,完结撒花
类比之前实现的方法,其实是不难实现的,读者可以自行完成(有空待补,找个理由 )
目前大三下,课业压力极其繁忙,在这段时间,大概率会忽略博客评论,敬请谅解