《神经网络与深度学习》读书笔记

第一章 使用神经网络识别手写数字

感知器

感知器在20世纪五、六十年代由科学家Frank Rosenblatt发明,其受到Warren McCulloch和Walter Pitts早期的工作影响。一个感知器接受几个二进制输入,$x_1,x_2,…,$,并产生一个二进制的输出:


mark

示例中的感知器有三个输入,$x_1,x_2,x_3$,通常可以有更多或更少的输入,通过引入相应的权重,$w_1,w_2,…$表示相应输入对于输出的重要性的实数。神经元的输出,0或者是1,则由分配权重后的总和$\sum_{j}w_jx_j$小于或大于一些给定的阈值决定。和权重一样,阈值是一个实数,一个神经元的参数。可以用下面的形式来表示:

mark

简化一下感知器的数学描述,用$w·x=\sum_{j}w_jx_j,b=-threshold$,则感知器的规则可以重写为:

mark

S型神经元

单个感知器上一个权重或偏置的微小改动有时会引起那个感知器的输出完全翻转,如从0变到1。这样的翻可能接下来引起其余网络的行为以极其复杂的方式完全改变。因此,虽然有时可以正确对一类进行分类,但网络在其他图像的行为很可能以一些很难控制的方式被完全改变。这使得逐步修改权重和偏置来让网络接近期望行为变得很困难。


mark

可以引入一种称为S型神经元来克服这个问题。S型神经元和感知器类似,但是被修改为权重和偏置的微小改动只引起输出的微小变化。这对于让神经元网络学习起来是很关键。S型神经元同样有多个输入,$x_1,x_2,…$,对应每个输入有权重,$w_1,w_2,…$和一个总的偏置,b。但是输出不是0和1,而是$\sigma(w·x+b)$,$\sigma$被称为S型函数,定义为:$$\sigma(z)=\frac {1}{1+e^{-z}}$$
可以看到:当$z=w·x+b$为很大的正数时,S型神经元的输出近似为1;当$z=w·x+b$为很小的负数时,S型神经元的输出近似为0。这种行为与感知器很像,只有在$w·x+b$取中间值时,和感知器模型有比较大的偏离。利用S型神经元,会得到一个平滑的感知器。$\sigma$是平滑的,利用其特性,权重和偏置的微小变化会输出一个为微小的变化,不会像感知器那样变化剧烈。S型函数的形状如下:
mark

神经网络的架构

一个典型的神经网络架构如下图所示:
mark
主要包括:输入神经元、隐藏层和输出神经元三个部分。以上一层的输出作为下一层的输入,这种网络被称为前馈神经网络。这意味着网络中是没有回路的-信息总是向前传播,从不反向回馈。

使用梯度下降算法进行学习

使用神经网络构建手写体识别分类算法,使用二次代价函数作为损失函数,训练神经网络找到最小化二次代价函数C(w,b)的权重和偏置。:

mark

为什么使用二次代价,而不是直接最大化正确分类图像的数量?
因为,在神经网络中,被正确分类的图像数量关联权重和偏置的函数并不是一个平滑的函数。大多数情况下,对权重和偏置做出的微小变动完全不会影响被正确分类的图像的数量。这会导致很难去解决如何改变权重和偏置来取得改进的性能。而用一个类似二次代价的平滑代价函数则能更好地解决如何用权重和偏置中的微小改变来取得更好的效果。

梯度下降法
假设我们要最小化某些函数,$C(v)$。它可以是任意的多元实值函数,$v=v_1,v_2,…$,用v代替w和b以强调它可能是任意的函数,并不局限于神经网络的环境。为了最小化$C(v)$,想象C是一个只有两个变量$v_1$和$v_2$的函数,如下图所示:

mark

如果在$v_1$和$v_2$方向上分别改变很小的量,即$\Delta v_1$和$\Delta v_2$,微积分告诉我们$C$将会有如下变化:
$$\Delta C \approx \frac {\partial C}{\partial v_1}\Delta v_1 + \frac {\partial C}{\partial v_2}\Delta v_2 $$
因为,我们要最小化$C$,所以要寻找中选择$\delta v_1$和$\delta v_2$的方法,使得$\Delta C$为负;为了弄明白如何选择,需要定义$\delta v$为v变化的向量,$\Delta v= (\Delta v_1,\Delta v_2)^T$;定义$C$的梯度为偏导数的向量$\nabla C$:
$$\nabla C =(\frac {\partial C}{\partial v_1},\frac {\partial C}{\partial v_2})^T$$
那么,
$$\Delta C \approx \nabla C · \Delta v$$
这个表达式解释了为什么$\nabla C$被称为梯度向量:$\nabla C$把v的变化关联为$C$的变化,正如我们期望的用梯度来表示。如果选取:
$$\Delta v=-\eta \nabla C$$
那么,可以看到$\Delta C \approx -\eta \nabla C · \nabla C = -\eta ||\nabla C||^2$ 是永远小于等于0的,如果按照这种方式去改变v,那么$C$会一直减小,不会增加。因此,可以用如下方式更新$v$:
$$v \rightarrow v^{new} = v - \eta \nabla C$$
然后用它再次更新规则来计算下一次的更新,如果反复持续这样做,我们将持续减小C直到获得一个全局的最小值。如果$C$是一个具有更多变量的函数,也同样适用。梯度下降法就是通过这种方式重复改变$v$来找到函数$C$的最小值。

如何在神经网络中使用梯度下降法去学习呢?其思想就是利用梯度下降算法去寻找能使得代价函数取得最小值的权重$w_k$和偏置$b_l$。我们将权重和偏置代替变量$v_j$,那么可以得到:$$
w_k \rightarrow w_k^{new} = w_k - \eta \frac {\partial C}{\partial w_k}\\\\
b_l = b_l^{new}=b_l - \eta \frac {\partial C}{\partial b_l}
$$
随机梯度下降,就是通过随机选取小量的训练输入样本来计算$\nabla C_x$,进而估计梯度$\nabla C$。通过计算少量的样本的平均值可以快速得到一个对于实际梯度$\nabla C$的很好的估算,有助于加速梯度下降,进而加速学习过程。

批量梯度下降,随机选取小批量的数据,在这批数据上计算梯度,并更新参数。

第二章 反向传播算法是如何工作的

反向传播算法的推导

首先,定义神经网络中的权重,我们使用$w_{jk}^l$表示从(l-1)层的第k个神经元到l层的第j个神经元的连接上的权重。如下图所示:
mark
同时,我们使用$b_{j}^l$表示在第l层第j个神经元的偏置,使用$a_j^l$表示第l层第j个神经元的激活值,下图清楚地解释了这样表示的含义:


mark

于是,第l层的第j个神经元的激活值$a_j^l$就和第(l-1)层的激活值通过下面的公式联系起来$$
a_j^l = \sigma(\sum_k w_{jk}^la_k^{l-1} + b_j^l)
$$
对每一层l都定义一个权重矩阵$w^l$,表示连接到第l层神经元的权重,同时,每一层,定义一个偏置向量,$b^l$。于是,第l层的激活值向量$a^l$可以写成如下形式:$$
a^l = \sigma(w^l a^{l-1} + b^l)
$$
这个表达式给出了一种更加全局的思考每层的激活值和前一层激活值的关联方式:我们仅仅用权重矩阵作用在激活值上,然后加上一个偏置向量,最后作用于$\sigma$函数。在计算$a^l$的过程中,我们计算了中间量$z^l = w^la^{l-1}+b^l$,我们称其为l层神经元的带权输入,这样$a^l = \sigma(z^l)$。

其次,看一下神经网络代价函数的两个假设。上一章使用的是二次代价函数:

mark

其中,n是训练样本总数;求和运算遍历了每个训练样本x;y=y(x)是对应的目标输出;L表示网络的层数;$a^L=a^L(x)$是当输入是x时网络输出的激活值向量。

反向传播的目标是计算代价函数$C$分别关于w和b的偏导数,为了让反向传播可行需要作出以两个假设:
第一个假设就是代价函数可以被写成一个在每个训练样本x上的点检函数$C_x$的均值$C=\frac {1}{n} \sum_x C_x$。需要这个假设的原因是反向传播实际上是对一个独立的训练样本计算了$\frac {\partial C_x}{\partial w}$和$\frac {\partial C_x}{\partial b}$。然后,我们通过在所有训练样本上进行平均化获得$\frac {\partial C}{\partial w}$和$\frac {\partial C}{\partial b}$。实际上,有了这个假设,我们会认为训练样本x已经被固定住了,丢掉了其下标,将代价函数$C_x$看做$C$。
第二个假设就是代价函数可以写成神经网络输出的函数
mark

最后,反向传播算法的推导。
反向传播其实是对权重和偏置变化影响代价函数的过程的理解。最终极的含义其实就是计算偏导数$\frac {\partial C}{\partial w_{jk}^j}$和$\frac {\partial C}{\partial b_j^l}$。为了计算这些值,首先引入一个中间量$\delta_j^l$,称为在第l层第j个神经元上的误差。反向传播将给出计算误差$\delta_j^l$的流程,然后将其关联到计算$\frac {\partial C}{\partial w_{jk}^j}$和$\frac {\partial C}{\partial b_j^l}$上。
反向传播的4个基本方程:
(1) 输出层误差的方程,$\delta^L$,每个元素定义如下:$$\delta_j^L = \frac {\partial C}{\partial a_j^L}\sigma^\prime{(z_j^L)} (BP1)
$$
(2) 使用下一层的误差$\delta^{l+1}$ 来表示当前的误差$\delta^l$:$$
\delta ^l = ((w^{l+1})^T \delta^{l+1})\bigodot\sigma^\prime(z^l) (BP2)
$$
其中,$(w^{l+1})^T$是第l+1层的权重矩阵$w^{l+1}$的转置。
(3) 代价函数关于网络中任意偏置的改变率:$$
\frac {\partial C}{\partial b_j^l} = \delta_j^l (BP3)
$$
(4) 代价函数关于任何一个权重的改变率:$$
\frac {\partial C}{\partial w_{jk}^l} = a_k^{l-1}\delta_j^l (BP4)$$
现在证明这四个基本的方程,所有的这些都是多元微积分的链式法则的推论。首先,从方程(BP1)开始,它给出了输出误差$\delta^L$的表达式。首先有如下的定义:$$
\delta_j^L=\frac {\partial C}{\partial z_j^L}$$
表示L层上第j个神经元的误差,应用链式法则,可以用输出激活值的偏导数的形式重新表示上面的偏导数:$$
\delta_j^L=\sum_k \frac {\partial C}{\partial a_k^L}\frac {\partial a_k^L}{\partial z_j^L}$$
这里求和是在输出层的所有神经元k上运行的。当然,第k个神经元的输出激活值$a_k^L$只依赖于当k=j时第j个神经元的输入权重$z_j^L$。所以,当k不等于j时$\partial a_k^L/\partial z_j^L$消失了。结果我们可以简化上一个方程为:$$
\delta_j^L=\frac {\partial C}{\partial a_j^L}\frac {\partial a_j^L}{\partial z_j^L}$$
于是,由$a_j^L=\sigma(z_j^L)$,上式右边的第二项可以写成$\sigma^\prime(z_j^L)$,方程就变成:$$
\delta_j^L = \frac {\partial C}{\partial a_j^L}\sigma^\prime{(z_j^L)}$$
下一步,证明(BP2),它给出了以下一层误差$\delta ^{l+1}$的形式表示误差$\delta^l$。为此,我们想要以$\delta_k^{l+1}=\partial C/ \partial z_k^{l+1}$的形式重写$\delta_j^l=\partial C/\partial z_j^l$。我们可以应用链式法则:
$$
\delta_j^l = \frac {\partial C}{\partial z_j^l}=\sum_k \frac {\partial C}{\partial z_k^{l+1}} \frac {\partial z_k^{l+1}}{\partial z_j^l}=\sum_k \frac {\partial z_k^{l+1}}{\partial z_j^l}\delta_k^{l+1} $$
这里,最后一行交换了右边两项,并用$\delta_k^{l+1}$的定义带入。为了对最后一样的最后一项进行求值,注意:$$
z_k^{l+1}=\sum_j w_{kj}^{l+1}a_j^l = \sum_j w_{kj}^{l+1}\sigma(z_j^l)+b_k^{l+1}$$
做微分,我们得到:$$
\frac {\partial z_k^{l+1}}{\partial z_j^l}=w_{kj}^{l+1}\sigma^\prime(z_j^l)$$
带入,就可得到:$$\sigma_j^l = \sum_k w_{kj}^{l+1}\sigma_k^{l+1}\sigma^\prime(z_j^l)$$
总结一下

mark

反向传播算法

反向传播算法给出了一种计算代价函数梯度的方法。用算法描述出来就是:


mark

第三章 改进神经网络的学习方法

交叉熵代价函数

使用sigmod作为激活函数,使用二次代价函数作为损失函数时,当神经元的输出接近1的时候,曲线变得相当平,$\sigma^\prime(z)$就很小,相应计算出的梯度也会非常小,学习的速度就会变慢。假设神经元的输出为$a=\sigma(z)$,其中,$z=\sum_j w_jx_j+b$是输入的带权和。我们定义这个神经元的交叉熵代价函数:$$C = -\frac {1}{n}\sum_x[yln a + (1-y)ln(1-a)]$$其中,n是训练样本总数,求和是在所有的训练输入x上进行的,y是对应的目标输出。
交叉熵为何能够解释成一个代价函数?
将交叉熵看做是代价函数有两点原因。第一,它是非负的,C>0。第二,如果对于所有的训练输入x,神经元实际的输出接近目标值,那么交叉熵接近0,假设在这个例子中,y=0而a接近0,交叉熵的值为接近于0,反之y=1而a接近于1,交叉熵的值也接近于0,所以,在实际输出和目标输出之间的差距越少,最终的较差熵的值就越低。综上所述,交叉熵是非负的,在神经元达到很好的正确率的时候接近0。交叉熵代价函数有一个比二次代价函数更好的特性就是它避免了学习速度下降的问题。
首先,看一下交叉熵函数关于权重的偏导数,将$a=\sigma(z)$带入交叉熵损失函数,应用链式法则,得到:

mark

将结果合并一下,简化成:

mark

最终,可以得到:
mark
可以看到,权重的学习的速度受到$\sigma(z)-y$,也就是输出中的误差的控制。更大的误差,更快的学习速度。特别地,这个代价函数还避免了像二次代价函数类似方程中$\sigma^\prime(z)$导致学习的缓慢。交叉熵代价函数的学习曲线:
mark
特别地,当我们使用二次代价函数时,学习在神经元犯了明显的错误时却比学习快接近真实值的时候缓慢;而使用交叉熵学习正是在神经元犯了明显错误的时候速度更快。特别地,当我们使用二次代价函数时,当神经元在接近正确的输出前犯了明显错误的时候,学习变得更加缓慢;而使用交叉熵,在神经元犯明显错误时学习得更快。这些现象不依赖于如何设置学习速率。


### 过度拟合和规范化
过度拟合是神经网络的一个主要问题。这在现代网络中特别正常,因为网络权重和偏置数量巨大。检测过度拟合的明显方法是使用上面的方法-跟踪测试数据集合的准确率随训练变化情况。如果我们看到测试数据上的准确率不再提升,那么我们就停止训练。严格地说,这其实并非是过度拟合的一个必要现象,因为测试集和训练集上的准确率可能会同时停止提升。当然,采用这样的策略是可以防止过度拟合的。

使用validation_data而不是test_data来防止过度拟合,在每个迭代期的最后都计算在validation_data上的分类准确率。一旦分类准确率已经饱和,就停止训练。这个策略被称为early stopping。在实际应用中,我们不会立即知道什么时候准确率会饱和。相反,我们会一直训练直到我们确信准确率已经饱和。

为何要使用validation_data来代替test_data防止过度拟合问题?
实际上,这是一个更为一般的策略的一部分,这个一般的策略就是使用validation_data来衡量不同的超参数(如迭代次数、学习速率、最好的网络架构等等)的选择的效果。如果设置超参数是基于test_data的话,可能最终我们得到过度拟合于test_data的超参数,这些超参数符合test_data的特点,但是网络的性能并不能够泛化到其他的数据集合上。我们借助validation_data来克服这个问题,一旦获得了想要的超参数,最终我们就使用test_data进行准确率测量。

规范化
增加训练样本的数量是一种减轻过度拟合的方法。还有其他的一些方法能够减轻过度拟合,就是规范化,有时被称为权重衰减(weight decay)或者L2规范化。L2规范化的思想就是增加一个额外的项到代价函数上,这个项叫做规范化项。下面是规范化的较差熵:
mark
可以看出,规范化的效果是让网络倾向于学习小一点的权重,其他的东西都是一样的。大的权重只有能够给出代价函数第一项足够的提升时才被允许。换而言之,规范化可以当做一种寻找小的权重和最小化原始的代价函数之间的折中。这两部分之前相对的重要性就由$\lambda$的值来控制了:$\lambda$越小,就偏向于最小的原始代价函数,反之,倾向于小的权重。新的权重的学习规则就变成:
mark
这正和通常的梯度下降学习规则相同,除了通过一个因子$1-\frac {n\lambda}{n}$重新调整了权重$w_0$。这种调整有时被称为权重衰减,因为它使得权重变小。

我们已经把规范化描述为一种减轻过度拟合和提高分类准确率的方法。实际上,这不是仅有的好处。实践表明,在使用不同的权重初始化进行多次MNIST网络训练的时候,我们发现无规范化的网络会偶然被限制住,明显困在了代价函数的局部最优值处。结果就是不同的运行会给出相差很大的结果。对比看来,规范化的网络能够提供更容易复制的结果。

为什么会这样子呢?,从经验上来看,如果代价函数是无规范化的,那么权重向量的长度可能会增长,而其他的东西都保持一样。随着时间的推移,这会导致权重向量变得非常大。所以会使得权重向量卡在朝着更多还是更少的方向上变化,因为当长度很大的时候梯度下降带来的变化仅仅会引起在那个方向发生微小的变化。我们相信这个现象让我们的学习算法更难有效地探索权重空间,最终导致很难找到代价函数的最优值。

为何规范化可以帮助减轻过度拟合?
通常的说法是:小的权重在某种程度上,意味着更低的复杂性,也就对数据给出了一种更简单却更强大的解释,因此应该优先选择。

L2规范化没有限制偏置,实际上可以对偏置进行限制,但在某种程度上,对不对偏置进行规范化其实就是一种习惯了。然而,需要注意的是,有一个大的偏置并不会向大的权重那样会让神经元对输入太过敏感。所以,我们不需要对大的偏置带来的学习训练数据的噪声太过担心。同时,允许大的偏置能够让网络更加灵活,因为,大的偏置让神经元更加容易饱和,这有时候是我们所要达到的效果。所以,我们通常不会对偏置进行规范化。

规范化的其他技术
除了L2外还有很多规范化技术,另外给出三种减轻过拟合的其他方法:L1规范化、弃权和人为增加训练样本。
L1规范化:这个方法是在未规范化的代价函数上加上一个权重绝对值的和:$$
C=C_0 + \frac{\lambda}{n} \sum_w |w|
$$
在L1规范化中,权重通过一个常量向0进行缩小。在L2规范化中,权重通过一个和w成比例的量进行缩小。所以,当一个特定的权重绝对值|w|很大时,L1规范化的权重缩小得要远比L2规范化要小的多、相反,当一个特定的权重绝对值|w|很小时,L1规范化的权重缩小得要比L2规范化大的多。最终的结果是:L1规范化倾向于聚集于网络的权重在相对少量的高重要度连接上,而其他权重就会被驱使向0接近。

弃权(DropOut)是一种相当激进的技术。和L1、L2规范化不同,弃权技术并不依赖对代价函数的修改。而是,在弃权中,我们改变了网络本身。弃权技术在训练大规模深度网络时尤其有用,这样的网络中过度拟合问题经常特别突出。

人为扩展训练数据


### 权重初始化
在创建了神经网络后,我们需要进行权重和偏置的初始化。之前的方式是根据独立高斯随机变量来选择权重和偏置,其被归一化为均值0,标准差1。假设我们使用一个有大量输入神经元的网络,比如说1000个。假设,我们已经使用归一化的高斯分布初始化了连接的第一个隐藏层的权重。现在我们将注意力集中在这一层的连接权重上,忽略网络的其他部分:

mark

为了简化,假设我们使用训练输入x,其中一半的输入神经元的值为1,另一半为0。以下的论点更普遍适用,让我们考虑隐藏神经元输入的带权和$z=\sum_j w_jx_j+b$。其中,500个项消去了,因为对应的输入$x_j$为0。所有z是遍历总共501个归一化的高斯随机变量的和,包含500个权重项和额外的1个偏置项。因此,z本身是一个均值为0,标准差为22.4的高斯分布。z其实有一个非常宽的高斯分布,完全不是非常尖的形状:

mark

尤其是,我们可以从上图看出|z|会变得非常大,如果这样,隐藏神经元的输出$\sigma(z)$就会接近1或0。也就表示我们的隐藏神经元会饱和。所以,当出现这样的情况时,在权重中进行微小的调整仅仅会给隐藏神经元的激活值带来极其微弱的改变。而这种微弱的改变也会影响网络中剩下的神经元,然后会带来相应的代价函数的改变。结果就是,这些权重在我们进行梯度下降算法时会学习得非常缓慢。
我们可以进行更好地初始化,能够避免这种类型的饱和,最终避免学习速度的下降,假设我们有n个输入神经元,我们可以使用均值为0标准差为$1/\sqrt[]{n}$的高斯随机分布初始化这些权重。也就是说,我们会向下挤压高斯分布,让我们的神经元更不可能饱和。

第五章 深度神经网络为何很难训练

当神经网络层数加深,先前的层可能学习的比较好,但是后面的层却停滞不变。实际上,我们发现,在深度神经网络中使用基于梯度下降的学习方法本身存在着内在的不稳定性。这种不稳定性使得先前或者后面的层的学习过程阻滞。

消失的梯度问题

在某些深度神经网络中,在我们在隐藏层BP的时候梯度倾向于变小。这意味着在前面的隐藏层中的神经元学习速度要慢与后面的隐藏层。在很多神经网络中存在着更加根本的导致这个现象出现的原因。这个现象也被称作是消失的梯度问题(vanishing gradient problem)

更一般地说,在深度神经网络中的梯度是不稳定的,在前面的层中或会消失或会爆炸。这种不稳定性才是神经网络中基于梯度学习的根本问题。
下图是一个有三层隐藏层的神经网络:


mark

其中,$w_1,w_2,…$是权重,而$b_1,b_2,…$是偏置,C是某个代价函数。现在看一下关联于第一个隐藏层神经元梯度$\partial C/ \partial b_1$。下图给出了具体的表达式:
mark

为何会出现梯度消失:现在把梯度的整个表达式写下来:
mark

除了最后一项,该表达是一系列形如$w_j\sigma^\prime(z_j)$的乘积。如果我们使用标准方法来初始化网络中的权重,那么会使用一个均值为0标准差为1的高斯分布。因此,所有的权重通常会满足$|w_j|<1$。有了这些信息,我们就会发现$w_j\sigma^\prime(z_j)<1/4$。并且在我们进行了所有这些项的乘积时,最终的结果肯定会指数级下降:项越多,乘积下降的越快。这样就能够解释消失的梯度问题。

不稳定的梯度问题:根本问题其实并非是消失的梯度问题或者爆炸的梯度问题,而是在前面的层上的梯度是来自后面的层上的乘积。当存在过多的层次时,就出现了内在本质上的不稳定场景。唯一让所有层都接近相同的学习速度的方式是所有这些项的乘积都能得到一种平衡。如果没有某种机制或者更加本质的保证来达成平衡,那网络就很容易不稳定了。简而言之,真实的问题就是神经网络受限于不稳定梯度的问题。所以,如果我们使用标准的基于梯度的学习算法,在网络中的不同层会出现按照不同学习速度学习的情况。

坚持原创技术分享,您的支持将鼓励我继续创作!