BP 神经网络算法及MATLAB实现
2018年7月11日这源自实验课上的一个小作业。做的一个PPT,在文章底部附件中。
人工神经网络
是一种模仿生物神经网络(动物的中枢神经系统,特别是大脑)的结构和功能的数学模型或计算模型,用于对函数进行估计或近似。神经网络由大量的人工神经元联结进行计算。大多数情况下人工神经网络能在外界信息的基础上改变内部结构,是一种自适应系统,通俗的讲就是具备学习功能。
BP神经网络算法
反向传播(英语:Backpropagation,缩写为BP)是“误差反向传播”的简称,是用来训练人工神经网络的常见方法。该方法对网络中所有权重计算损失函数的梯度。这个梯度会反馈给最优化方法,用来更新权值以最小化损失函数。
BP 算法主要阶段:
第1阶段:激励传播
1.(前向传播阶段)将训练输入送入网络以获得激励响应;
2.(反向传播阶段)将激励响应同训练输入对应的目标输出求差,从而获得隐层和输出层的响应误差。
第2阶段:权重更新
1.将输入激励和响应误差相乘,从而获得权重的梯度;
2.将这个梯度乘上一个比例并取反后加到权重上。
这个比例(百分比)将会影响到训练过程的速度和效果,因此成为“训练因子”。梯度的方向指明了误差扩大的方向,因此在更新权重的时候需要对其取反,从而减小权重引起的误差。
第 1 和第 2 阶段可以反复循环迭代,直到网络对输入的响应达到满意的预定的目标范围为止。
流程图
相关公式
- 激活函数: g(x)=\frac{1}{1+e^{-x}}
隐含层输出: H_j = g(\sum_{i=1}^{n}{\omega_{ij} * x_i + a_j})
输出层输出: O_k = \sum_{j=1}^{l}{H_j*\omega_{jk}+b_k}
误差计算:E=\frac{1}{2}\sum_{k=1}^{m}e_k^2
权值更新:\begin{cases}
\omega_{ij}=\omega_{ij}+\eta H_j(1-H_j)x_i\sum_{k=1}^m\omega_{jk}e_{k} \\
\omega_{jk}=\omega_{jk}+\eta H_j e_k
\end{cases}偏置更新:\begin{cases}
a_{j}=a_{j}+\eta H_j(1-H_j)\sum_{k=1}^m\omega_{jk}e_{k} \\
b_{k}=b_{k}+\eta H_j e_k
\end{cases}
源码实现
这里根据上面的流程及公式实现了源码,并用它来处理 Iris 数据集分类的问题。Iris数据集可以在 http://en.wikipedia.org/wiki/Iris_flower_data_set 找到。
第一个文件,实现BP算法
classdef bpnn < handle
properties
input; %训练输入
output; %训练输出
inputps; %归一化变量
testInput; %测试输入
testOutput; %测试输出
n; %训练次数
inputNum; %输入层的节点数
hiddenNum; %隐含层的节点数
outputNum; %输出层的节点数
w1; w2; b1; b2; %权重及偏置
alpha; % 学习速率
end
methods
function obj = bpnn(x, y, n)
% BP神经网络
% bpnn(x, y, n),x 训练输入,y训练输出,n训练次数
[obj.input, obj.inputps] = mapminmax(x'); %训练数据归一化
obj.output = y;
obj.n = n;
obj.inputNum = size(x, 2); %输入层的节点数
obj.hiddenNum = 3; %隐含层的节点数
obj.outputNum = size(y, 2); %输出层的节点数
% 权重和偏置的初始化
obj.w1 = rands(obj.inputNum, obj.hiddenNum);
obj.b1 = rands(obj.hiddenNum, 1);
obj.w2 = rands(obj.hiddenNum, obj.outputNum);
obj.b2 = rands(obj.outputNum, 1);
obj.alpha = 0.1;
end
function obj = train(obj)
disp('训练开始...')
for r = 1 : obj.n
E(r) = 0; % 统计误差
for m = 1 : size(obj.input, 2)
% 信息的正向流动
x = obj.input(:, m);
% 隐含层的输出
for j = 1: obj.hiddenNum
hiddenOutput(j,:) = sigmoid(obj.w1(:,j)' * x + obj.b1(j,:));
end
% 输出层的输出
outputOutput = obj.w2' * hiddenOutput + obj.b2;
% 计算误差
e = obj.output(m,:)' - outputOutput;
E(r) = E(r) + sum(abs(e));
% 修改权重和偏置
% 隐含层到输出层的权重和偏置调整
dw2 = hiddenOutput * e';
db2 = e;
% 输入层到隐含层的权重和偏置调整
for j = 1 : obj.hiddenNum
partOne(j) = hiddenOutput(j) * (1 - hiddenOutput(j));
partTwo(j) = obj.w2(j,:) * e;
end
for i = 1 : obj.inputNum
for j = 1 : obj.hiddenNum
dw1(i,j) = partOne(j) * x(i,:) * partTwo(j);
db1(j,:) = partOne(j) * partTwo(j);
end
end
obj.w1 = obj.w1 + obj.alpha * dw1;
obj.w2 = obj.w2 + obj.alpha * dw2;
obj.b1 = obj.b1 + obj.alpha * db1;
obj.b2 = obj.b2 + obj.alpha * db2;
end
end
fprintf('训练完毕,共训练 %d 次,%d 项\n', obj.n, size(obj.input, 2));
end
function test(obj)
%测试函数,需要给定testInput、testOutput,否则无法测试。输出测试结果
result = predict(obj);
k = size(obj.testInput, 1);
ok = 0;
for i = 1 : k
fprintf('输入:[%.1f %.1f %.1f %.1f] 预测: %d,实际: %d\n', ...
obj.testInput(i, 1), obj.testInput(i, 2), obj.testInput(i, 3), obj.testInput(i, 4), ...
result(i), find(obj.testOutput(i, :)));
if result(i) == find(obj.testOutput(i, :))
ok = ok + 1;
end
end
fprintf('测试 %d 项,正确 %d 项,准确率 %.2f%%\n', k, ok, ok / k * 100);
end
function [output_fore] = predict(obj)
%预测函数,给定testInput,返回预测结果
test = mapminmax('apply', obj.testInput', obj.inputps); %分类
k = size(obj.testInput, 1);
for m = 1 : k
for j = 1 : obj.hiddenNum
hiddenTestOutput(j,:) = sigmoid(obj.w1(:,j)' * test(:,m) + obj.b1(j,:));
end
outputOfTest(:,m) = obj.w2' * hiddenTestOutput + obj.b2;
end
%根据网络输出找出数据所属类别
output_fore = zeros(k, 1);
for m = 1 : k
output_fore(m) = find(outputOfTest(:,m) == max(outputOfTest(:,m)));
end
end
end
end
function [y] = sigmoid(x)
% 激活函数
y = 1 ./ (1 + exp(-x));
end
第二个文件,运用BP算法处理分类问题
clear; clc;
% 读取数据
[f1,f2,f3,f4,class,~] = textread('Iris.txt' , '%f%f%f%f%f%s', 150);
input = [f1, f2, f3, f4];
%构造输出矩阵
s = length(class);
output = zeros(s, 3);
for i = 1 : s
output(i , class(i)) = 1 ;
end
% 随机提取80%的数据用于训练,20%的数据用于测试
num = size(input, 1) * 0.8;
k = rand(1, 150);
[m, n] = sort(k);
trainInput=input(n(1:num),:);
trainOutput=output(n(1:num),:);
testInput=input(n(num + 1:end),:);
testOutput=output(n(num + 1:end),:);
% 调用BP神经训练函数
a = bpnn(trainInput, trainOutput, 30);
a.train();
a.testInput = testInput;
a.testOutput = testOutput;
a.test()