神经网络算法分析
2
2
1 (k ) y a (j L ,k ) zi( L ) 2
nL j 1
1 nL ( k ) ( y j a(jL,k ) )2 zi( L ) 2 j 1
( y (jk ) a (j L ,k ) )
nL ( L.k ) a ( y (jk ) a (j L ,k ) ) ( L ) f ( zi( L ,k ) ) j ( L) zi zi j 1
为了提高运算的速度,在运算过程中,我们不是一个个数据来进行计算,而是一次性 将所有数据代入运算,因此上述的 k 就可以省去,得到终式:
( L,k ) ( y a ( L ) ) f ' ( z ( L ) )
( l ) ( l 1) ' (l ) (l ,k ) (W ) f (z )
结合上述所有式子,并将之转变为矩阵运算
( L,k ) ( y ( k ) a ( L,k ) ) f ' ( z ( L,k ) )
( l ) ( l 1, k ) ' (l ,k ) (l ,k ) (W ) f (z )
(6) .
(6) (5) .(4) (3)
i(l ,k )
n 1 (l 1,k ) ' (l ,k ) (k ) (k ) jl J ( W ; x , y ) zi f ( zi ) ( l 1, k ) 1 zi ai(l ) n 1 ( l 1, k ) (l ) jl W ji f ' ( zi( l ,k ) ) 1 i
四、 参数的选取
对于W的初始化,我采用的正态分布的随机数,并取种子为1。 rng(1); w_ini = randn(n,num); 而对神经网络来说,还有两个十分重要的参数,landa和步长p。 通过试验,当这两个参数至少有一个比2大时,matlab计算会出现溢出,出现Nan和 Inf,即不存在和无穷大这两个数。 那么我就开始向下取,随着两个参数的减小,得到的W的效果慢慢地变好。但是在减小 的过程中,又出现了一个新的问题,那就是收敛速度。当两个参数都较小的时候,它们的收 敛速度变得十分缓慢,这样也不是我们想要的。所以经过测试,我取landa为1,p为0.1。 最后就只剩下分层问题了。一个神经网络分几层,每层有几个元素,这些可以说是根据 问题来定的,我们事先是不知道的,而且这个分层对结果也是有很大的影响的。 如果只是分两层,即不存在隐层。那么神经网络和感知器是十分相似的,而且得到的效 果也是很不错的。 但是分为三层时,第一次分层,我是将隐层的元素个数设为前一层的一半(这里是还没 增广化的元素个数,如里增广化后就要加多一个元素。)得到的结果十分地奇怪,一开始它 的误差是向减小的方向移动的,但是到了一定的值时,误差开始变大了。我尝试过当误差开 始变大时,将p=-p,然后进入一个while循环,让它的误差重新向减小的方向再移动才结 束循环,得到的效果也是十分差的。 后来我将隐层的元素个数设为与前一层一样。 刚才所述的情况并没有出现, 最后也是收 敛的,可是效果没有分为两层时的好。
并命名为残差。 而在众多的 i
( l 1, k )中来自 i( L,k )是最容易求出的。因为计算的输出可以通过前向传播求
得,而实际值为一项输入参数。
i( L ,k )
1 J (W ; x ( k ) , y ( k ) ) ( L ) y ( k ) hW ( x ( k ) ) ( L) zi zi 2
1* e a 1 (1 e a ) 1 * f (a)(1 f (a)) (1 e a )2 1 e a 1 e a
Sigmoid 函数的取值范围为(0,1) 。 而双曲正切函数为:
ea e a 2 f (a) a a 1 e e 1 e2 a
三、 反向传播
因为样本数据都已经增广化,那么质量评价函数为:
J (W ; x, y )
目标函数也会随之改写为:
1 hW ( x) y 2
2
1 m L 1 nl ( l 1) J (W ) J (W ; x ( x ) , y ( k ) ) (Wij(l ) ) 2 m k 1 2 l 1 j 1 i 1
六、 改进
程序还是有很多的地方要改进的,例如编码是要人为来进行的,没有实现机械化,还是 测试函数也不适用于多类。
七、 附录
代码实现: 1、
clear all
main.m 文件如下:
clc cd('E:\模式识别\第六次作业');%感知器程序所在目录 addpath('E:\模式识别\MNIST');%MNIST 数据及其读取程序所在的目录 X = cell(1,3); images = loadMNISTImages('train-images.idx3-ubyte'); labels = loadMNISTLabels('train-labels.idx1-ubyte'); X{1} = images(:,labels==0); X{2} = images(:,labels==1); clear images; clear labels; L = 2; XX = [X{1} X{2}]; XX = [ones(1,size(XX,2));XX]; Y = [zeros(1,size(X{1},2)) ones(1,size(X{2},2))]; [ w ] = fnn_bp( XX,Y,L,1,0.1 ); %提取测试数据 X_te = cell(1,3); images_te = loadMNISTImages('t10k-images.idx3-ubyte'); labels_te = loadMNISTLabels('t10k-labels.idx1-ubyte'); X_te{1} = images_te(:,labels_te==0); X_te{2} = images_te(:,labels_te==1); ss = cell(1,2); [~,ss{1}] = size(X_te{1}); [~,ss{2}] = size(X_te{2}); clear images_te; clear labels_te; X = [X_te{1} X_te{2}]; X = [ones(1,size(X,2));X]; Y = [zeros(1,size(X_te{1},2)) ones(1,size(X_te{2},2))]; err = fnn_demo( X,Y,w,L,2 ); %输出错误统计 fprintf('第一类错误率是 %d/%d = %f 第二类错误率是 %d/%d = %f 总错误率是 %d/%d = %f\n',err{1}, ss{1},err{1}/ss{1},err{2}, ss{2},err{2}/ss{2},err{1}+err{2}, ss{1}+ss{2},(err{1}+err{2})/(ss{1}+ss{2}))
上面说到除最后一层之外的运算, 这是因为最后一层的输出有与其他层是不同的。 因为 使用改写的公式, 我们对每一层的输出都要增广化, 但是最后一层的输出是不需要这个操作 的,所以这个输出要单独编写:
i = L; z{i} = w{i-1}*a{i-1}; a{i} = act_f( z{i} );
这样我们就得到前向传播的神经元汇总输入 z 和神经元输出/激活值 a。
神经网络算法分析
一、 前向传播
在前向传播之前, 我们先对训练数据进行增广化, 即在每一个数据的第一个元素前加上 一个 1,使其增广化,并将之后得到的每一层的神经元汇总输入所组成的向量也进行同样的 增广化。那么因为维度的关系,如下公式的(1)式将无法使用
zi(l 1, x ) j 1Wij(l ) a (jl , x ) bi(l )
五、 测试结果
% 我的结果: % 将网络分为三层,隐层的元素个数比第一层的元素个数大 1 时,程序迭代了 20 次 % 第一类错误率是 77/980 = 0.078571 第二类错误率是 134/1135 = 0.118062 总错误率是 211/2115 = 0.099764 % % 将网络分为两层,即不含有隐层时,程序迭代了 39 次,但是运算的时间比分为三层时要 少很多 % 第一类错误率是 4/980 = 0.004082 第二类错误率是 1/1135 = 0.000881 总错误率是 5/2115 = 0.002364
第二项是已知的,那么式子就只剩下第一项是非知的。 J (W ; x 我们可以变为 J (W ; x
( x)
( x)
, y ( k ) ) 对 Wij(l ) 求导,
, y ( k ) ) 对 zi(l 1) 求导,再乘上 zi(l 1) 对 Wij(l ) 求导。就有:
J (W ; x ( x ) , y ( k ) ) (l 1) J (W ; x ( x ) , y ( k ) ) * z ( l 1) i( l 1, k ) a (jl , k ) (l ) (l ) i Wij zi Wij
( y (jk ) a (j L ,k ) ) f ' ( zi( L ,k ) )
而其他的残差应该会和它们前一层的残差有一定的关系的,
(l ) (k ) (k ) (k ) ( k ) ai J ( W ; x , y ) J ( W ; x , y ) zi(l ) ai(l ) zi(l )
n 2 1 m 1 L 1 nl ( l1) hW ( x ( k ) y ( k ) ) (Wij(l ) ) 2 2 l 1 j 1 i 1 m k 1 2 n