造轮子–MLP与EBP的实现
目录
引入
MLP是一个人工神经网络(ANN),它将一组输入向量映射到一组输出向量,可以被认为是一个由多层节点组成的有向图,每个节点与下一个节点完全连接。除了输入节点外,每个节点都是一个具有非线性激活函数的神经元。在本文章中,误差反向传播(EBP)的监督学习方法被用来训练MLP。
一、Multi-Layer Perceptron(MLP)
在本文章中,我们使用一个4-2-4结构的MLP来实现编码器。其具体结构如图1所示。
图1. 网络结构
MLP有一个有4个单元的输入层,一个有2个隐藏单元的单一隐藏层,以及一个有4个单元的输出层。每个单元都有一个sigmoid激活函数。编码器的输入输出模式如表1。
表1:编码器的输入输出模式
Input | Output |
---|---|
1, 0, 0, 0 | 1, 0, 0, 0 |
0, 1, 0, 0 | 0, 1, 0, 0 |
0, 0, 1, 0 | 0, 0, 1, 0 |
0, 0, 0, 1 | 0, 0, 0, 1 |
由于神经网络中的每一层输入都会通过sigmoid函数,而sigmoid函数的输出永远无法到达1或0,而只能无限逼近1或0。所以出于实际考虑,最好将表1中的1替换成0.9,0替换成0.1。
sigmoid函数:
o j = ϕ ( n e t j ) = 1 1 + e − n e t j o_j = \phi(net_j) = \frac{1}{1 + e^{-net_j}} oj=ϕ(netj)=1+e−netj1
对于本次文章中的MLP,在确定MLP的框架结构(4-2-4)、训练的输入输出数据以及sigmoid激活函数后,所需要做的任务就是确定神经网络传播中的权值。
二、Error Back-Propagation(EBP)
EBP主要被用来更新MLP中的权值。EBP是一个迭代的过程,每次迭代MLP中的权值矩阵W1和W2的值都会被更新。
两个矩阵W1和W2分别存储输入层和隐藏层的权值,W1的大小定为4x2,W2的大小定为2x4。通过矩阵乘法,可以分别得出隐藏层和输出层的数据。一旦得到输出层的数据,我们便可以计算误差。该误差可以帮助我们判断系统的工作状态。
梯度下降法和复合函数的链式法则在EBP算法中起着举足轻重的作用。在本次求解EBP算法时,我们的目的就是为了训练两组权值,使得系统的误差最小。由于误差函数可以看作是由所有待求权值W为自变量的复合函数。所以应用梯度下降法即可有效的求解最小化误差函数的问题。
同时,应用链式法则可以很好的帮助我们求解梯度下降法中的多层偏导数问题。
参数解释:
E E E:误差函数
W i j W_{ij} Wij:各个权值
n e t j net_j netj:第j个单元的输入
o j o_j oj:第j个单元的输出
η \eta η:系统的学习率
将矩阵的每层输入分别与各个权值相乘,则有各层输出层公式:
各层输出层公式(其中
i
i
i,
j
j
j,
k
k
k… 分别为网络第一,二,三…层):
o
j
=
ϕ
(
n
e
t
j
)
=
ϕ
(
∑
k
=
1
K
w
k
,
j
o
k
)
o_j = \phi(net_j) = \phi(\sum_{k=1}^{K} w_{k,j} o_{k})
oj=ϕ(netj)=ϕ(k=1∑Kwk,jok)
链式法则:
∂
E
∂
w
i
j
=
∂
E
∂
o
j
∂
o
j
∂
n
e
t
j
∂
n
e
t
j
∂
w
i
j
\frac{\partial E}{\partial w_{ij}} = \frac{\partial E}{\partial o_j} \frac{\partial o_j}{\partial net_j} \frac{\partial net_j}{\partial w_{ij}}
∂wij∂E=∂oj∂E∂netj∂oj∂wij∂netj
通过解算得
∂
E
∂
w
i
j
=
δ
i
o
j
\frac{\partial E}{\partial w_{ij}} = \delta_i o_j
∂wij∂E=δioj
其中
δ
j
\delta_j
δj的值有两种情况:
- 当第j层网络是输出层时
δ j = ( o j − t j ) o j ( 1 − o j ) \delta_j = (o_j - t_j)o_j(1 - o_j) δj=(oj−tj)oj(1−oj)
- 当第j层网络是非输出层时
δ j = ( ∑ k = 1 K w j k δ k ) o j ( 1 − o j ) \delta_j = (\sum_{k=1}^{K} w_{jk} \delta_k) o_j (1 - o_j) δj=(k=1∑Kwjkδk)oj(1−oj)
最后,更新权值并进入下一次迭代。
w i j = w i j + δ w i j = w i j − η δ j o i w_{ij} = w_{ij} + \delta w_{ij} = w_{ij} - \eta \delta_j o_i wij=wij+δwij=wij−ηδjoi
三、偏置Bias
MLP模型本质上是一个使用 y = w x + b i a s y = wx + bias y=wx+bias 函数绘制决策面的函数。其中 w w w是权重,也就是函数的斜率。而 b i a s bias bias,是函数的截距。
显然,函数y=wx+bias是二维/三维/高维空间的直线/平面/超平面。如果没有这个偏向,那么我们就只能在过了原点的空间里画直线/平面/超平面。在这一点上,对于绝大多数情况来说,要求决策平面通过原点,将会造成非常炸裂的影响。
因此,如果你正在为神经网络编写代码,请确保你添加了偏置项。否则,网络可能会变得非常差,收敛速度慢,精度差,甚至可能会死掉,无法收敛。
带有偏置的MLP模型:
四、代码测试结果
1、未加偏置Bias的MLP系统
让学习率eta=1,迭代次数为10000。
图中有四条曲线(蓝、绿、红、黄),表示输入矩阵中每组数据产生的结果的误差(输入矩阵有四行,一行数据作为一组输入,构成四组)。
结果显示,在10000次迭代中,有两组数据迅速收敛到接近0,然而另外两组数据从未收敛(误差E始终保持在0.2左右)。
Test0: MLP without Bias, eta = 1, number of iterations = 10000.
2.有偏置Bias的MLP系统
通过向MLP添加Bias,得到了以下结果。
在Test1.1中,结果显示,在10000次迭代中,两组数据相对快速地收敛到接近0,然而,另外两组数据从未收敛(一个误差E持续保持在0.15左右,另一个保持在0.1左右)。
在Test1.2中,结果显示所有四组数据在10000次迭代后都相对快速地收敛到接近0。
Test1.1: eta = 1 number of iterations = 10000.
Test1.2: eta = 1 number of iterations = 10000.
在Test2.1和Test2.2中,结果显示,在10000次迭代中,所有四组数据都收敛到接近0,但速度比Test1.1和Test1.2慢。
Test2.1: eta = 0.2 number of iterations = 10000.
Test2.1: eta = 0.2 number of iterations = 10000.
在Test3.1中,结果显示,在10000次迭代中,只有一组数据收敛到0附近,而其他三组数据仍在收敛中。收敛速度非常慢。
Test3.1: eta = 0.02, number of iterations = 10000.
五、Conclusion
总结以上结果,我们可以得出以下结论。
没有Bias的MLP性能可能很差,误差结果E会不能收敛。
对于有Bias的MLP来说,学习率eta的大小非常关键。当eta值过大时,误差E会急剧振荡,结果可能不会收敛。太小的Eta会导致收敛缓慢,使训练效率太低。所以大家在使用这个模型时要自己尝试,找出最合适的学习率的值。
附录:代码(Matlab)
clc
clear
input = [0.9 0.1 0.1 0.1 1;
0.1 0.9 0.1 0.1 1;
0.1 0.1 0.9 0.1 1;
0.1 0.1 0.1 0.9 1];
output = [0.9 0.9 0.1 0.1;
0.1 0.9 0.1 0.1;
0.1 0.1 0.9 0.1;
0.1 0.1 0.1 0.9];
W1 = rand(5,2);
W2 = rand(3,4);
Layer_i = sigmoid(input);
N = 10000;
eta = 0.2;
E_temp = zeros(N, 4);
for n=1:1:N
for m=1:1:4
Layer_j = sigmoid(Layer_i(m,:) * W1);
Layer_j_Bias = [Layer_j, [1]];
Layer_k = sigmoid(Layer_j_Bias * W2);
output_expect = output;
E1 = Layer_k - output_expect(m,:);
E = 0;
for d=1:1:4
E = E + 0.5 * E1(1,d) * E1(1,d);
end
E_temp(n, m) = E;
[deltaW1, deltaW2] = BP(W2, Layer_i, Layer_j, Layer_j_Bias, Layer_k, output_expect, eta, m);
W1 = W1 + deltaW1;
W2 = W2 + deltaW2;
end
end
x = 1:1:N;
plot(x,E_temp(:,1), 'g', x, E_temp(:,2), 'r',x,E_temp(:,3), 'b',x,E_temp(:,4), 'y');
function [deltaW1, deltaW2] = BP(W2, Layer_i, Layer_j, Layer_j_Bias, Layer_k, output_expect, eta, m)
cache = (Layer_k - output_expect(m,:)) .* Layer_k .* (1 - Layer_k);
partial_deriv = Layer_j_Bias' * cache;
deltaW2 = -eta * partial_deriv;
W2 = W2 + deltaW2;
mediate_result1 = cache .* W2(1,:);
mediate_result2 = cache .* W2(2,:);
sum_result1 = 0;
sum_result2 = 0;
for n = 1:1:4
sum_result1 = sum_result1 + mediate_result1(1,n);
sum_result2 = sum_result2 + mediate_result2(1,n);
end
deltaW1_tmp = [sum_result1,sum_result2];
deltaW1 = -eta * Layer_i(m,:)' * deltaW1_tmp .* Layer_j .* (1 - Layer_j);
end