神经网络要点理解

目录

第一次接触神经网络总是被其诸多的符号弄的眼花缭乱。几个重要的符号包括:

  1. 样本的个数m;
  2. 单个样本的feature个数n;
  3. 神经网络的层数L;
  4. 神经网络输出的类别数量K;

假设我们对5000幅20×20的手写数字灰度图像进行识别,则m=5000,n=400,K=10。对于本文用到的神经网络,L=3

1 损失函数及其正则化

一个未经正则化的神经网络损失函数为:

J(Θ)=1mmi=1Kk=1[y(i)klog((hθ(x(i)))k)(1y(i)k)log(1(hθ(x(i)))k)]

其中hθ(x)的计算如下:

20171014htheta.png

此处L=3.

针对上面的公式,我们有x(i)表示第i个样本的矢量,这个矢量的大小是400×1hθ(x(i))k表示第i个输入在第K个类上的输出。每一个输入样本x(i)都会在神经网络的输出层产生K个输出,表示x(i)属于这K个类中每个类的可能性。

当我们给定Θ1Θ2时,我们可以根据上图来计算每一个hθ(xi),进而根据J(Θ)的公式来计算损失函数。

注意在计算的过程中,我们遇到的一些矩阵(从上图到J(Θ)的计算过程中遇到的矩阵)的维度为:

矩阵 维度
a(1) 5000×401
Θ(1) 25×401
z(2) 25×5000
a(2) 26×5000
Θ(2) 10×26
z(3) 10×5000
a(3) 10×5000
Y 10×5000

其中a(1) 为添加了a(1)0后的矩阵;a(2)为添加了a(2)0后的矩阵;Y为把1,2,…,10映射为矢量后的矩阵。

J(Θ)计算的是5000个用户在10个类上的cost之和。所以式~(1)的方括号中如果是矩阵的话应该是一个10×5000的矩阵。

计算J(Θ)的部分代码为:

a1 = [ones(m,1) X];
z2 = Theta1*a1';
a2 = 1./(1 + exp(-z2));
a2 = [ones(1,size(a2,2));a2];%add a_0^(2)
z3 = Theta2 * a2;

a3 = 1./(1 + exp(-z3));%10X5000

temp = eye(num_labels);
Y = temp(:,y);
J = (Y .* log(a3) + (1-Y).* log(1-a3))./m;
J = -1*sum(sum(J));

注意为了支持任何大于K>3的分类,代码中不允许出现任何的magic number。比如:

temp = eye(num_labels);

就不能写成:

temp = eye(10);

虽然在这个例子中 num_labels=10 magic number 也是不被允许的。

接下来是正则项的计算:

λ2m[25j=1400k=1(Θ(1)j,k)2+10j=125k=1(Θ2j,k)2]

同样magic number是不被允许的。

2 后向传递算法

后向传递算法的步骤为:

  1. 给定一个训练样本x(t),y(t) 首先计算前向过程,直到输出hθ(x)
  2. 对每个层l的每个节点j,计算误差项δ(l)j,这个误差项用来度量这个节点对输出负多大的“责任”;
  3. 对于输出节点,我们直接计算网络的activation输出和真实的目标值之间的差即可。用这个差值作为δ(3)j,对于隐藏的层,计算δ(l)j时需要加权考虑层l+1上的错误。

20171014BPimplement.png

根据上图,我们需要循环处理所有样本,一次处理一个,所以一定会有一个 for t=1:m 。在第t次迭代的时候处理第t个样本。循环内的步骤为:

  1. 设定输入层的值为xt,执行前向过程,计算z(2),a(2),z(3),a(3)。注意在计算过程中需要为a添加一个bias项。
  2. 对于层3中的每一个输出单元,设定δ(3)k=(a(3)kyk) 其中yk是二进制数表示当前的训练样本是不是第k类,如果是,则yk=1;如果当前样本属于其他类则yk=0
  3. 对隐藏层l=2,设定:δ(2)=(Θ(2))Tδ(3).g(z(2))
  4. 从这个样本中累计梯度值。Δ(l)=Δ(l)+δ(l+1)(a(l))T
    注意要去掉δ(2)0
  5. 获得梯度值:Θ(l)ijJ(Θ)=D(l)ij=1mΔ(l)ij

在matlab实现的过程中,也需要仔细核对相关变量的维度。由于我们在计算a(2),a(3),z(2),z(3)的过程中使用的是矢量计算,在计算Θ(l)ijJ(Θ)的过程中我们也可以使用全矢量计算。

%% calculate the theta gradient
delta3 = a3 - Y;
temp = Theta2;
temp(:,1) = 0;
Theta2_grad = delta3 * a2'./m + lambda./m*temp ;

delta2 = Theta2(:,2:end)'*delta3 .* sigmoidGradient(z2);
temp = Theta1;
temp(:,1) = 0;
Theta1_grad = delta2 * a1./m + lambda./m*temp;

需要注意的是在正则化过程中需要把Θ中对应bias项的那些值去掉,在代码中我才用了置零处理。另外在计算δ(2)的过程中也需要把Θ2中与bias相关的项去掉。