吴恩达《机器学习》学习笔记十——神经网络相关(2)
- 一、 代价函数
- 二、 反向传播算法
- 三、 理解反向传播算法
- 四、 梯度检测
- 五、 随机初始化
- 1.全部初始化为0的问题
- 2.随机初始化的思想
- 六、 神经网络算法整体流程
- 1.选择网络具体架构
- 2.训练神经网络
课程链接: https://www.bilibili.com/video/BV164411b7dx?from=search&seid=5329376196520099118
上次笔记从非线性假设的问题引入,强调了通过特征映射使线性回归、逻辑回归模型解决非线性问题是不科学的,当初始特征空间比较大时,特征映射之后的特征空间将会非常庞大,非常浪费计算。
从而开始介绍神经网络的历史、结构和工作原理。这次笔记将继续上次内容,对神经网络的反向传播算法进行学习,该算法结合梯度下降算法可以根据给定数据集对参数进行优化。
一、 代价函数
考虑神经网络解决多分类问题:
数据集为:
定义L为网络的层数,sl为第l层神经元的个数,上图中L=4。
分类问题包括两种:二分类与多分类:
二分类的标签只有0/1,而且只需要一个输出神经元;而多分类(K类)的标签可以被表示成one-hot形式,如上图中[1 0 0 0]这样,K分类就需要K个输出神经元。
神经网络的代价函数是逻辑回归代价函数的一般形式,将一个分类器的代价函数推广到了多个,如下图所示:
二、 反向传播算法
这个算法是用来根据数据集优化参数的,过程中需要对代价函数求偏导:
先来看一个数据样本的例子:
前向传播的计算过程图中已经展示,该过程可以计算每一个神经元的激活值。
前向传播计算完之后,才需要进行反向传播,反向传播算法从直观上说,就是需要对除输入层之外的每一个神经元计算一个误差δ_j ^ (l)(表示第l层第j个节点的误差),已知a_j ^ (l)表示第l层第j个节点的激活值,这个δ_j ^ (l)在某种程度上就是这个节点的激活值的误差,所以我们希望这个节点的激活值稍微有所改变。具体来说,以下面这个四层的网络为例:
既然被称为反向传播,那么自然要从输出层开始计算误差,输出层的误差计算如下:
用向量表示的话,就是δ ^ (4)=a ^ (4) - y。然后用计算出来的δ ^ (4)去反向计算第三层的误差δ ^ (3),再用δ ^ (3)去计算δ ^ (2),因为第一层就是输入层,它的值是确定的,没有误差,所以不需要计算δ ^ (1),第二层、第三层的计算公式如图中所示。
再从头理一下反向传播算法:
数据集如下所示:
(1) 初始化误差矩阵:(∆是δ的大写形式)
这个误差后面将用来计算代价函数的偏导数。
(2) 然后是前向传播的计算以及反向传播求误差:
先将输入层的值传给a(1),然后前向计算各神经元的激活值,前向计算完毕之后,从输出层开始,反向计算各层的误差。
(3) 计算D,从而计算代价函数偏导数的值:
计算出偏导数之后,就可以用梯度下降算法或其他高级优化算法去优化参数值,所以反向传播算法的作用就是求出偏导数。
三、 理解反向传播算法
先看一下前向传播的过程:
假设只有一个样本一个输出单元,且不考虑正则化,,那么代价函数变为如下图所示的cost(i):
图中cost(i)表达式有误,正确应该为:
反向传播的计算:
四、 梯度检测
反向传播算法有一个不好的特性,很容易产生一些微妙的bug,当他与梯度下降或其他一些优化算法一同工作时,看起来确实能正常运行,并且代价函数在每次梯度下降的迭代中也在不断减小,但是到最后得到的神经网络其误差将会比无bug的情况下高出一个数量级,并且很可能不知道这个差距是由bug造成的。
那么如何应对这种情况呢?有一种思想叫做梯度检测,它能解决几乎所有这种问题,使用梯度检测,可以保证前向传播和反向传播都会是百分之百正确的。
先来看一下代价函数导数的一种近似数值计算方法(这里的变量θ为实数而非向量):
这里是用割线的斜率来近似切线的斜率,即代价函数的导数,当ε足够小时,可以近似相等,如10 ^ (-4),一般也不能太小,否则会有数值计算上的误差。
当变量θ是向量时,上述近似方法可以推广为:
对每一个变量分别求偏导数。这些等式可以让你从数值上去估算代价函数J所关于的任何参数的偏导数。由此写出的代码如下所示:
这里的gradApprox就是数值计算得到近似偏导数值,而我们把用反向传播算法求得的偏导数值记为DVec,梯度检测的下一步就需要检验:
验证gradApprox是否等于或近似等于DVec,若两种方法计算出来的导数是一样的或者说非常接近,只有几位小数的差距,那么就可以确信反向传播算法的实现是正确的,此时把DVec用到梯度下降算法或其他优化算法中时,就可以确信计算的导数是正确的,那么代码就能正确地运行,并很好的优化J。
总结一下实现的细节:
首先需要实现反向传播算法去计算DVec,然后使用数值计算的方法计算gradApprox,并确保他们两有近似的结果,这一步确保之后,在训练时使用反向传播算法计算梯度,而不再使用梯度检测,因为数值计算法的计算量比较大、速度比较慢,而反向传播算法是一个高性能的计算导数的方法,一旦通过检验确定反向传播算法是正确的,就应该关掉梯度检验不再使用。
五、 随机初始化
当使用梯度下降或高级优化算法时,首先需要为参数确定初始值。初始化结束后可以一步步通过梯度下降来最小化代价函数。
1.全部初始化为0的问题
之前在逻辑回归中是将初始值全部设置成0,但是在神经网络中这是不合适的,如下图所示:
因为权重都为0,那么计算出来的两个激活值a1和a2也相等,所以误差也相等。进而导致,代价函数对两个参数的偏导数也相等,所以用梯度下降更新后的参数值也会相等,只是可能不为0,但还是一直保持相等,后续也都会这样,一直相等。所以这样的话,两条蓝色的线的权重会相等,红色的会相等,绿色的也会相等,所以这个神经网络计算不出什么有趣的函数,每一层的神经元都在进行着相同的计算,这是一种高度冗余的情况。也被称为对称权重的问题。
2.随机初始化的思想
为了避免上述的问题,在神经网络的参数初始化时,需要采用随机初始化的思想:
将参数值初始化为[-ε,ε]范围内的一个随机值。一般ε的值比较小,所以初始化后的参数值也是比较小的随机值。随机性打破了上述提到的对称权重的问题。
六、 神经网络算法整体流程
这节将结合上述所讲的所有内容来做一个总体的回顾,相互之间有怎样的联系以及神经网络学习算法的总体实现过程。
1.选择网络具体架构
对于一个具体的问题,首先要确定神经网络的结构,包含几层、几个输入神经元、几个输出神经元、每个隐藏层各有几个神经元等等。具体的选择依据如下图所示:
根据输入数据的特征数来确定输入神经元的数量,根据需要分几类来确定输出神经元的数量,隐藏层默认使用一层,或几层但每层的神经元数量相同,每层隐藏层的数量一般大于输入层是有效的,越多越好。但隐藏层的具体选择还需依据具体问题来具体分析。
2.训练神经网络
这里分为了六步:
(1) 随机初始化权重为很小的数
(2) 执行前向传播算法对所有输入计算得到相应的预测值h(x)
(3) 按照公式计算出代价函数J(θ)
(4) 反向传播算法计算代价函数的偏导数
然后是5、6两步:
(5) 使用梯度检测去比较通过反向传播算法和数值估计两种方法求出来的偏导数是否近似相等,如果近似相等,则停止梯度检测,训练过程将只使用反向传播算法。
(6) 使用梯度下降法或高级优化方法用反向传播求得的偏导数的结果去最小化代价函数,优化参数。
需要注意的一点是,神经网络的代价函数J(θ)是非凸的,所以优化算法只能得到局部最优值。