Andrew Ng 机器学习笔记 09 :神经网络

非线性假设

对于许多实际的机器学习问题,特征个数n是很大的。

随着特征数量n的增加,二次项的个数大约以 O ( n 2 ) 的量级增长,此时包含所有的二次项是困难的,如果我们还要引入三次项,那么我们的项的个数将以 O ( n 3 ) 的量级增长。

而项数过多时,结果很有可能过拟合。此外,这里也存在运算量过大的问题。

神经网络逻辑单元

在一个计算机的神经网络里,我们将使用一个非常简单的模型来模拟神经元的工作:

黄色的圆圈,可以理解为类似神经元的东西,然后我们通过它的树突(或者说是它的输入神经)传递给它一些信息。然后神经元做一些计算,并通过它的输出神经(即它的轴突)输出计算结果。

这里的 h θ ( x ) 通常值的是:

h θ ( x ) = 1 1 + e θ T x

绘制一个神经网络时,有时会额外增加一个 x 0 的输入节点,这个 x 0 节点有时也被称作偏置单位(或偏置神经元)。但由于 x 0 = 1 ,是否画出它,取决于它是否对例子有利。

激励函数

神经网络中的激励函数(activation function),只是对类似非线性函数g(z)的另一个术语称呼:

g ( z ) = 1 1 + e z

z = θ T x

在之前我们一值称 θ 为模型的参数,但在神经网络的文献里,有时会称 θ 为模型的权重(weight)。

输入层,输出层,隐藏层

  • 第一层也被称为输入层,因为我们在这一层输入我们的特征项 x 1 x 2 x 3 ,当然我们也可以加入值为1的 x 0
  • 中间层有三个神经元: a 1 ( 2 ) a 2 ( 2 ) a 3 ( 2 ) ,同理,你可以加上值永远为1的偏置单元 a 0 ( 2 )

    中间层,也被称为隐藏层,隐藏层的值在训练过程中是看不到的,所以叫它隐藏层。神经网络可以有不止一个的隐藏层。在神经网络中,任何一个非输入层且非输出层,就被称为隐藏层。

  • 最后一层,也被称为输出层,因为这一层的神经元会输出假设函数的最终计算结果 h Θ ( x )

前向传播(forward propagation)的向量化实现

a i ( j ) 表示第j层的第i个神经元,表示的是第 j 层的第 i 个激励。

把隐藏层的三个神经元的计算结果都写出来:

a 1 ( 2 ) = g ( Θ 10 ( 1 ) x 0 + Θ 11 ( 1 ) x 1 + Θ 12 ( 1 ) x 2 + Θ 13 ( 1 ) x 3 )

a 2 ( 2 ) = g ( Θ 20 ( 1 ) x 0 + Θ 21 ( 1 ) x 1 + Θ 22 ( 1 ) x 2 + Θ 23 ( 1 ) x 3 )

a 3 ( 2 ) = g ( Θ 30 ( 1 ) x 0 + Θ 31 ( 1 ) x 1 + Θ 32 ( 1 ) x 2 + Θ 33 ( 1 ) x 3 )

简化上面的式子,改写为:

a 1 ( 2 ) = g ( z 1 ( 2 ) )

可见:

z 1 ( 2 ) = Θ 10 ( 1 ) x 0 + Θ 11 ( 1 ) x 1 + Θ 12 ( 1 ) x 2 + Θ 13 ( 1 ) x 3

这里其实是一个矩阵的乘法运算:

Θ ( 1 ) x

这样一来,就能将神经网络的计算,向量化了。

具体而言,我们定义特征向量x:

x = [ x 0 x 1 x 2 x 3 ]

其中 x 0 = 1

并定义 z ( 2 )

z ( 2 ) = [ z 1 ( 2 ) z 2 ( 2 ) z 3 ( 2 ) ]

我们只需要两个步骤,就可以计算出 a ( 2 ) 向量了:

z ( 2 ) = Θ ( 1 ) x

a ( 2 ) = g ( z ( 2 ) )

最后,在输出层,我们还有一个单元,它用来计算 h Θ ( x )

h Θ ( x ) = a 1 ( 3 ) = g ( Θ 10 ( 2 ) a 0 ( 2 ) + Θ 11 ( 2 ) a 1 ( 2 ) + Θ 12 ( 2 ) a 2 ( 2 ) + Θ 13 ( 2 ) a 3 ( 2 ) )

z ( 3 ) = Θ ( 2 ) a ( 2 )

h Θ ( x ) = a ( 3 ) = g ( z ( 3 ) )

这就是计算 h Θ ( x ) 的过程,也称为前向传播(forward propagation)。

AND、OR、NOT、XNOR的实现

拟合AND

假设我们有二进制输入 x 1 x 2 ,目标函数是 y = x 1 AND x 2 ,为网络分配一些权重(参数):

即,假设函数是:

h Θ ( x ) = g ( 30 + 20 x 1 + 20 x 2 )

x1 x2 hΘ(x)
0 0 g(−30)≈0
0 1 g(−10)≈0
1 0 g(−10)≈0
1 1 g(10)≈1

这就是逻辑“与”的计算结果。

拟合OR

即,假设函数是:

h Θ ( x ) = g ( 10 + 20 x 1 + 20 x 2 )

x1 x2 hΘ(x)
0 0 g(−10)≈0
0 1 g(10)≈1
1 0 g(10)≈1
1 1 g(30)≈1

拟合NOT

假设函数为:

h Θ ( x ) = g ( 10 20 x 1 )

x1 hΘ(x)
0 g(10)≈1
1 g(−10)≈0

拟合XNOR

接下来我们使用上面求解的以下三个神经网络,就可以来运算 x 1 XNOR x 2 了:

为了拟合 x 1 XNOR x 2 的非线性的样本分布:

可以构建以下神经网络的隐藏层:

最终的真值表如下:

x1 x2 a 1 ( 2 ) a 2 ( 2 ) hΘ(x)
0 0 0 1 1
0 1 0 0 0
1 0 0 0 0
1 1 1 0 1

神经网络的多类别分类

建立一个具有四个输出单元的神经网络,四个类别分别是行人、轿车、摩托车、卡车:

也就是说,此时神经网络的输出是一个思维向量。因此现在的输出需要用一个向量来表示,这个向量中有四个元素,而我们要做的是对第一个输出元素进行分辨图片上是不是一个行人(Pedestrian),然后对第二个元素分辨它是不是一辆轿车(Car),对第三个元素分辨它是不是摩托车(Motorcycle),对第四个元素分辨它是不是一辆卡车(Truck)。

因此,如果判断是行人,输出结果是:

h Θ ( x ) [ 1 0 0 0 ]

代价函数

以神经网络在分类问题中的应用为例:

L :神经网络结构的总层数。对于上面的网络结构, L = 4
S l 表示第 l 层的神经元的数量,这其中不包括 L 层的偏置单元。 S 1 = 3 (也就是输入层)

在多类别分类(Multi-class classification)问题中,会有K个不同的类,比如说如果我们有四类的话,我们就用下面这种表达形式来代表y。在这类问题里,我们就会有K个输出单元。

在神经网络里,使用的代价函数,应该是逻辑回归里使用的代价函数的一般形式。

逻辑回归的代价函数:

J ( θ ) = 1 m [ i = 1 m y ( i ) l o g h θ ( x ( i ) ) + ( 1 y ( i ) ) l o g ( 1 h θ ( x ( i ) ) ) ] + λ 2 m j = 1 n θ j 2

其中 λ 2 m j = 1 n θ j 2 这一项是个额外的正则化项,是一个j从1到n的求和形式。因为我们并没有把偏置项0正则化。

对于神经网络,我们使用的代价函数是这个式子的一般化形式。

J ( Θ ) = 1 m [ i = 1 m k = 1 K y k ( i ) l o g ( h Θ ( x ( i ) ) ) k + ( 1 y ( i ) ) k ) l o g ( 1 ( h Θ ( x ( i ) ) ) k ) ] + λ 2 m l = 1 L 1 i = 1 S l j = 1 S l + 1 ( Θ j i ( l ) ) 2

神经网络输出了在K维的向量hΘ(x):

h Θ ( x ) R K

( h Θ ( x ) ) i 来表示第i个输出。

最后式子中的这一项 λ 2 m l = 1 L 1 i = 1 S l j = 1 S l + 1 ( Θ j i ( l ) ) 2 类似于我们在逻辑回归里所用的正则化项,这个求和项看起来确实非常复杂,它所做的就是把这些项全部加起来,也就是对所有的 Θ j i ( l ) 的值都相加。

反向传播(B-P)

反向传播算法(BP算法)是一种让代价函数最小化的算法,从直观上说就是对每一个节点求误差项: δ j ( l ) ,即第 l 层的第 j 个结点的误差。

用上面的那个四层的神经网络结构做例子:

每一项的输出单元(layer L = 4)

δ j ( 4 ) = a j ( 4 ) y j

对于每一个输出单元,我们准备计算 δ 项,所以第四层的第 j 个单元的 δ 就等于这个单元的激励值减去训练样本里的真实值。

下一步就是计算网络中前面几层的误差项δ。

δ ( 3 ) 的计算公式:

δ ( 3 ) = ( Θ ( 3 ) ) T δ ( 4 ) . g ( z ( 3 ) )

应用一个相似的公式来求得 δ ( 2 ) :

δ ( 2 ) = ( Θ ( 2 ) ) T δ ( 3 ) . g ( z ( 2 ) )

这里我们没有 δ ( 1 ) 项,因为第一层是输入层,不存在误差。

如果你忽略标准化所产生的项,我们可以证明我们想要的偏导项,恰好就是下面这个表达式:

Θ i j ( l ) J ( Θ ) = a j ( l ) δ i ( l + 1 )

梯度检验(Gradient Checking)

反向传播作为一个有很多细节的算法,在实现的时候会有点复杂,而且有一个不好的方面是在实现反向传播时,会遇到很多细小的错误。

用数值方法计算近似导数的过程:
找到 θ + ε θ ε 这两个点,然后用一条直线把这两点连起来,求近似导数:

θ J ( θ ) J ( θ + ε ) J ( θ ε ) 2 ε

通常 ε 取很小的值,比如可能取 ε = 10 4 ε 的取值在一个很大的范围内都是可行的,实际上,如果你让 ε 非常小,那么数学上上面的式子实际上就是导数。

在实现神经网络时,用for循环来计算代价函数对每个网络中的参数的偏导数估计值gradApprox,然后和我们从反向传播得到的导数DVec进行对比,看是否相等或近似于DVec。如果这两种计算导数的方法给了你相同的结果,或者非常接近的结果,那么我就非常确信我实现的反向传播是正确的。

随机初始化Θ

虽然说在逻辑回归时,初始化所有变量为0是可行的,但在训练神经网络时,这样做是不可行的。

为了解决这个神经网络变量初始化的问题,我们采用随机初始化的方法。对 Θ i j ( l ) 的每个值进行初始化,范围在 [ ε , ε ] 之间 ε Θ ( l ) i j ε

选择一个合适的神经网络结构

  • 输入单元的数目,由特征 x ( i ) 的维度确定。
  • 输出层的单元数目,由分类问题中的类别个数确定。
  • 如果使用超过一层的隐藏层,每一个隐藏层通常都应该拥有相同的单元数。通常来说,只使用一层隐藏层的结构是较为合理的默认结构。

训练神经网络的步骤

训练神经网络的六个步骤:

  1. 构建一个神经网络并且随机初始化权值(Randomly initialize Weight)我们通常把权值初始化为很小的值,接近于0。

  2. 执行向前传播算法,也就是对于神经网络的任意一个输入 x ( i ) 计算出对应的 h Θ ( x ( i ) )

  3. 通过代码计算出代价函数 J ( Θ )
  4. 执行反向传播算法(Backprop)来算出这些偏导数: Θ j k ( l ) J ( Θ )
  5. 使用梯度检查来校验结果。用梯度检查来比较这些已经用反向传播算法得到的偏导数值 Θ j k ( l ) J ( Θ ) 与用数值方法得到的估计值进行比较,来检查,确保这两种方法得到值是基本相近的。

    通过梯度检查,我们能确保我们的反向传播算法得到的结果是正确的,但必须要说明的一点是,检查结束后我们需要去掉梯度检查的代码,因为梯度检查计算非常慢。

  6. 使用一个最优化算法(比如说梯度下降算法或者其他更加高级的优化方法,比如说BFGS算法,共轭梯度法,或者其他一些已经内置到fminunc函数中的方法),将所有这些优化方法和反向传播算法相结合,这样我们就能计算出这些偏导数项的值 Θ j k ( l ) J ( Θ )

猜你喜欢

转载自blog.csdn.net/lk3030/article/details/79931893