在学习一段时间后,开始有些知识有些遗忘,所以整理一下,作为自己的学习笔记,以及帮助其他人学习。其中,大部分参考自《老饼讲解-BP神经网络》,
目录
一、什么是BP神经网络
1.1.BP神经网络原理
bp神经网络全称为Back Propagation Neural Network,简称为BPNN
BP神经网络的原理就像下面的图一样,模仿人的大脑的原理,把看到的东西作为输入,然后经过大脑,最后作为输出。
1.2.BP神经网络结构
BP神经网络在这个思想下,构造了下面的数学模型:
它的数学表达式如下:
这是一个只有一个隐层的BP神经网络(加上输入层、输出层,称为三层BP神经网络),
BP神经网络也可以有多个隐层,多层的BP神经网络结构图如下:
多个隐层的BP神经网络的数学表达式进行套娃就可以了,
学习时先用三层的进行理解,因为三层的使用得较多。
二、BP神经网络如何训练
2.1.BP神经网络的误差函数
BP使用均方差函数来评估网络的误差,它的公式如下:
m,k分别是样本个数与输出变量个数。误差越小,说明模型越好。
2.2.梯度下降算法训练BP神经网络
BP神经网络可以使用梯度下降算法进行训练,梯度下降算法就是先初始化BP神经网络的参数w,b,然后不断地往负梯度方向调整,使得模型的误差越来越小,最后求得最优解:
梯度下降算法需要使用参数在误差函数中的梯度,BP神经网络梯度公式如下:
MARK一下,后面我们会用到这条公式来实现代码。如果公式不太明白,可以看原文《BP神经网络的梯度公式推导(三层结构)》中的推导,了解了推导过程就比较清楚了。
三、如何用Matlab来实现BP神经网络
matlab提供了一个工具箱来实现BP神经网络,bp神经网络模型matlab工具箱还提供了非常多的训练算法,不过默认一般使用trainlm算法。BP神经网络matlab代码示例如下:
Matlab
x1 = [-3,-2.7,-2.4,-2.1,-1.8,-1.5,-1.2,-0.9,-0.6,-0.3,0,0.3,0.6,0.9,1.2,1.5,1.8]; % x1:x1 = -3:0.3:2;
x2 = [-2,-1.8,-1.6,-1.4,-1.2,-1,-0.8,-0.6,-0.4,-0.2,0,0.2,0.4,0.6,0.8,1,1.2]; % x2:x2 = -2:0.2:1.2;
y = [0.6589,0.2206,-0.1635,-0.4712,-0.6858,-0.7975,-0.8040,...
-0.7113,-0.5326,-0.2875 ,0,0.3035,0.5966,0.8553,1.0600,1.1975,1.2618]; % y: y = sin(x1)+0.2*x2.*x2;
inputData = [x1;x2]; % 将x1,x2作为输入数据
outputData = y; % 将y作为输出数据
setdemorandstream(88888); % 指定随机种子,这样每次训练出来的网络都一样。
%使用用输入输出数据(inputData、outputData)建立网络,
%隐节点个数设为3.其中隐层、输出层的传递函数分别为tansig和purelin,使用trainlm方法训练。
net = newff(inputData,outputData,3,{'tansig','purelin'},'trainlm');
%设置一些常用参数
net.trainparam.goal = 0.0001; % 训练目标:均方误差低于0.0001
net.trainparam.show = 400; % 每训练400次展示一次结果
net.trainparam.epochs = 15000; % 最大训练次数:15000.
[net,tr] = train(net,inputData,outputData); % 调用matlab神经网络工具箱自带的train函数训练网络
simout = sim(net,inputData); % 调用matlab神经网络工具箱自带的sim函数得到网络的预测值
figure; % 新建画图窗口窗口
t=1:length(simout);
plot(t,y,t,simout,'r') % 画图,对比原来的y和网络预测的y
运行后得到的结果如下:
在代码中我们用到newff函数,train函数,sim函数,具体的意义可以参考matlab-BP神经网络工具箱-newff、train、sim详解https://www.bbbdata.com/nn/text/40
四、如何自己写代码实现一个BP神经网络
如果不想借助matlab工具箱,还可以自己写代码实现BP神经网络,这就需要用到梯度下降法与上面的梯度公式,具体代码如下:
Matlab
close all;clear all;
%-----------数据----------------------
x1 = [-3,-2.7,-2.4,-2.1,-1.8,-1.5,-1.2,-0.9,-0.6,-0.3,0,0.3,0.6,0.9,1.2,1.5,1.8];% x1:x1 = -3:0.3:2;
x2 = [-2,-1.8,-1.6,-1.4,-1.2,-1,-0.8,-0.6,-0.4,-0.2,-2.2204,0.2,0.4,0.6,0.8,1,1.2]; % x2:x2 = -2:0.2:1.2;
X = [x1;x2]; % 将x1,x2作为输入数据
y = [0.6589,0.2206,-0.1635,-0.4712,-0.6858,-0.7975,-0.8040,...
-0.7113,-0.5326,-0.2875 ,0.9860,0.3035,0.5966,0.8553,1.0600,1.1975,1.2618]; % y: y = sin(x1)+0.2*x2.*x2;
%--------参数设置与常量计算-------------
setdemorandstream(88);
hide_num = 3;
lr = 0.05;
[in_num,sample_num] = size(X);
[out_num,~] = size(y);
%--------初始化w,b和预测结果-----------
w_ho = rand(out_num,hide_num); % 隐层到输出层的权重
b_o = rand(out_num,1); % 输出层阈值
w_ih = rand(hide_num,in_num); % 输入层到隐层权重
b_h = rand(hide_num,1); % 隐层阈值
simy = w_ho*tansig(w_ih*X+repmat(b_h,1,size(X,2)))+repmat(b_o,1,size(X,2)); % 预测结果
mse_record = [sum(sum((simy - y ).^2))/(sample_num*out_num)]; % 预测误差记录
% ---------用梯度下降训练------------------
for i = 1:5000
%计算梯度
hide_Ac = tansig(w_ih*X+repmat(b_h,1,sample_num)); % 隐节点激活值
dNo = 2*(simy - y )/(sample_num*out_num); % 输出层节点梯度
dw_ho = dNo*hide_Ac'; % 隐层-输出层权重梯度
db_o = sum(dNo,2); % 输出层阈值梯度
dNh = (w_ho'*dNo).*(1-hide_Ac.^2); % 隐层节点梯度
dw_ih = dNh*X'; % 输入层-隐层权重梯度
db_h = sum(dNh,2); % 隐层阈值梯度
%往负梯度更新w,b
w_ho = w_ho - lr*dw_ho; % 更新隐层-输出层权重
b_o = b_o - lr*db_o; % 更新输出层阈值
w_ih = w_ih - lr*dw_ih; % 更新输入层-隐层权重
b_h = b_h - lr*db_h; % 更新隐层阈值
% 计算网络预测结果与记录误差
simy = w_ho*tansig(w_ih*X+repmat(b_h,1,size(X,2)))+repmat(b_o,1,size(X,2));
mse_record =[mse_record, sum(sum((simy - y ).^2))/(sample_num*out_num)];
end
% -------------绘制训练结果与打印模型参数-----------------------------
h = figure;
subplot(1,2,1)
plot(mse_record)
subplot(1,2,2)
plot(1:sample_num,y);
hold on
plot(1:sample_num,simy,'-r');
set(h,'units','normalized','position',[0.1 0.1 0.8 0.5]);
%--模型参数--
w_ho % 隐层到输出层的权重
b_o % 输出层阈值
w_ih % 输入层到隐层权重
b_h % 隐层阈值
代码运行后的结果如下:
可以看到结果拟合得非常好。
理解完上面的代码,基本也就学会BP神经网络了。