在读完Michael A. Nielsen编写的《Neural Networks and Deep Learning》后想着把里面的一些知识点做个整理,主要是重要的公式以及概念,当做复习一遍。书的GitHub地址
序言
虽然人工智能的研究发展地如火如荼,但是现在的人工智能还是很浅层的伪智能,没有研究能够表明人工智能能否走到那最后的终点。是否智能也有那么一个简单的规律或者能通用的算法去模拟呢?
研究智能,就是去探索和研究人类为什么能产生智慧的问题。这个问题是如此的高深,绝不仅仅是涉及到计算机研究领域,数学,生物学,医学,物理学,化学,这个问题的解答必定是多个学科交叉努力的过程。
很多人对人工智能的未来不感到乐观,也有坚信这个领域的研究有光明未来的人。回顾过往,牛顿提出万有引力把天体运动复杂的现象用简单精妙的规律描述了,门捷列夫的元素周期表把纷繁复杂的物质组成进行总结。我们是不是有理由相信也有那么一条简单的规律,去解释现在门类众多的人工智能模型目前获得的成功,巧妙地展示智能的诞生。
虽然人工智能的研究从二十世纪四十年代左右其实就已经开始发展,并在二十世纪八十年代由于反向传播算法的提出重新兴起,在但是相比起化学和物理学的悠久历史,只是个新兴的领域。无论能否找到那最终的规律,目前的研究所作的努力和探索都是我们逐步获得洞察力的途径,或许某天我们就能获得对智能的奥秘足够的理解。所以前路漫漫,保持乐观,写此序言,表达感慨也作为鼓励,希望永远保持对未知的好奇和对新事物不断学习的态度。
基础概念和公式
神经网络的概念和学习以了解公式为主,所以还是得费点时间用LaTex把公式写出来。
神经元
介绍几种常见的激活函数(Activation)。
S型神经元
Sigmoid激活函数
公式定义:
一个具有输入x1,x2,...,权重w1,w2,..., 和偏置b的S型神经元的输出是
<img src = 'http://breezepicture.oss-cn-beijing.aliyuncs.com/neural%20network/sigmoid.png'>
说到Sigmoid函数就要说到Logistic回归,Logistic回归的工作原理如下,根据Sigmoid函数的输出更偏向0还是1,决定输出值是0还是1,实现简单的二分类。
<img src='http://breezepicture.oss-cn-beijing.aliyuncs.com/neural%20network/logistic.jpeg'>
tanh神经元
使用双曲正切(hyperbolic tangent)函数代替了Sigmoid激活函数
输入为x,权重向量为w,偏置为b的tanh神经元的输出是:
tanh函数的定义:
代入运算后:
从图像上看tanh是S型函数的按比例变化版本,和S型函数很相似,主要差异就是tanh神经元的输出的值域是(-1,1),这也是tanh相较于S型的意义所在,隐藏层的激活值有可能能够在正负间保持平衡。
<img src = 'http://breezepicture.oss-cn-beijing.aliyuncs.com/neural%20network/tanh.png'>
修正线性神经元(rectified linear neuron)
也叫做rectified linear unit,简记为ReLU。输入为x,权重向量为w,偏置为b的ReLU神经元的输出是:
函数图像如下:
<img src = 'http://breezepicture.oss-cn-beijing.aliyuncs.com/neural%20network/ReLU.png'>
显然ReLU和S型或者tanh神经元差别有点大。好处是ReLU不会像S型或者tanh那样在输出接近0或者1的时候饱和,ReLU的特殊性使得它不存在学习速度的下降,学习速度完全就是权重w决定的,当带权输入是负数的时候,梯度就消失了,神经元就完全停止了学习。
代价函数
均方误差(MSE)代价函数
为什么是除以2n呢,第一反应不应该除以n吗?这是为了后续数学计算的方便。因为这里无论是除以2n还是n,代价函数的最优化结果是一致的。但是如果是2n,当梯度下降需要求导的时候,2n中的2正好与求导出来的2相消除,结果更加简洁便于计算。
n训练输入数据的个数,y(x)网络的预期输出,a表示输入为x时输出的向量,求和是在总的训练输入x上进行。当然代价函数有多种形式,均方误差是最简单和容易理解的形式,也是回归问题的常用代价函数。
交叉熵(cross entropy)代价函数
其中神经元的输出是,n是训练数据的总数,求和是在所有的训练输入x上进行的,y是对应的目标输出。交叉熵是非负的,在神经元达到很好的正确率的时候会接近0,符合代价函数的特性。
同时如果把代入交叉熵函数,我们可以发现交叉熵函数相比于均方误差在代数上的简化。
化简得到
同时可以注意到我们可以得到代入我们上面化简的公式。
得到的最终形式是
这样交叉熵函数就避免了太小时导致的学习缓慢。同样的,我们还能得到
结合这两个式子我们发现交叉熵函数表现出一个简单的特性。当越大,也就是初始误差越大时候,神经元学习得越快。
交叉熵的概念起源于信息论,可以理解为刻画的其实是两个概率分布之间的距离,交叉熵越小,说明模型预测的概率分布和真实情况的概率分布越接近,也就是我们的预测值接近了答案。
柔性最大值(softmax)
柔性最大值是另一种输出层,常常作为一层额外的处理层,将神经网络的最后输出变成一个概率分布。公式定义:
容易发现,所以用柔性最大值作为输出时候可以看做一种概率分布。特别是对于分类问题的时候,这种概率特性使得输出激活值能够和实际问题结合理解。
从而softmax常常和交叉熵结合来计算预测的概率分布和实际情况的概率分布之间的距离。
在一个简单的二分类问题中,数值要么属于这个类也就是预计输出为1,要么就是不属于这个类,也就是预计输出为0。那么交叉熵函数会退化成(y是label值,a是预测值):
对于一个k分类问题,选用softmax分类器还是用logistic回归算法建立k个独立的二元分类器取决于分类类别之间是否互斥。例如,如果你有四个类别的音乐,分别为:古典音乐、乡村音乐、摇滚乐和爵士乐,那么你可以假设每个训练样本只会被打上一个标签(即:一首歌只能属于这四种音乐类型的其中一种),此时你应该使用类别数 k = 4 的softmax回归。如果你的四个类别如下:人声音乐、舞曲、影视原声、流行歌曲,那么这些类别之间并不是互斥的。例如:一首歌曲可以来源于影视原声,同时也包含人声 。这种情况下,使用4个二分类的 logistic 回归分类器更为合适。
对于一个互斥的三分类问题,如果某一个样例数据的正确答案是(1,0,0)。经过softmax回归后的预测答案是(0.5,0.4,0.1),那么这个预测和正确答案之间的交叉熵为:
梯度向量
假设C是一个有m个变量,...,的多元函数。那么对于C中的自变量的变化。。其中:
取,就能不断减少函数C的数值。这里的也被称为学习速率。
如果求取函数C对于变量到的二阶偏导,计算量很大。现在我们用权重和偏置去了解一下梯度下降的特点。
梯度下降(Gradient Descent)
一般情况会采用随机梯度下降(SGD-Stochastic Gradient Descent)结合批梯度下降算法(BGD-Batch Gradient Descent)的方法来加速学习。通过随机选取一批小量训练输入样本,对每个训练输入x单独地计算,因为其实是每个训练样本代价的平均值。现在通过随机选取m个训练输入来工作,把这些随机输入标记为,并把他们称作一个小批量数据(mini_batch)。
可以通过求平均值来求取:
权重和偏置的更新规则如下:
当我们利用这一批的数据完成了对代价函数C的权重和偏置的更新,使其不断变小,我们称为完成了一个训练周期(epoch)
反向传播算法(backpropagation)
把上面介绍的SGD方法和代价函数的形式结合起来看,我们计算和需要进行二次偏导,这个运算代价在参数多的时候很大。反向传播算法提供了一种快速计算梯度的方法。具体推导过程参考教程,或者利用计算图(computational graph)角度看BP(back propagation)。计算图参考
反向传播的四个方程式:
- 为层第个神经元的带权输入
- 是在层第个神经元上的误差,误差的定义是
- 是Hadamard乘积,。例子
下面对四个公式的含义进一步理解:
1 第一条公式:
第一条公式其实是下面这条公式的矩阵形式
对于在这个公式右边第一项代表代价C随着输出激活值的变化而变化的速度。右边第二项刻画了在处激活函数变化的速度。
第一条公式的作用其实是给出计算第L层,也就是最后一层神经元的代价的计算方法。
2 第二条公式:
使用下一层的误差来表示当前层的误差。这条公式其实是反向传播算法的最重要的公式,也体现了反向传播算法中反向的含义。在我们计算出最后一层的代价之后乘以这一层的权重矩阵通过链式法则一层层反向推导前几层的代价。
3 第三条和第四条公式:
这条公式我们可以发现误差和偏置的偏导数值完全一致。权重的二次偏导就是用那一层的代价乘以上一层的输出值。这两条可以结合第二条公式理解,对求导,也对其中的一部分求导之后变成1,保留了下来。
以反向传播的四条公式为基础,我们可以总结一下使用反向传播算法计算代价函数梯度的方法。
<img src = 'http://breezepicture.oss-cn-beijing.aliyuncs.com/neural%20network/neural1.png' width = '500'>
训练障碍
梯度消失与梯度爆炸
当深度学习模型设置的隐藏神经元层数不断变大时,会出现前面的隐藏层要比后面的隐藏层学习地更慢的情况,也就是出现了梯度消失的情况。
来看一下下面的每一层只有单一的神经元的三层隐层的神经网络。
<img src = 'http://breezepicture.oss-cn-beijing.aliyuncs.com/neural%20network/gradient_disappear.png'>
再看一下这幅解释图,这幅图从偏置上解释了,如果隐藏层层数过多的话,前面的隐藏层的偏置或者权重变化相比于后面的隐藏层对代价函数的影响更小,这也是前面的隐藏层梯度消息的原因,一旦层数变多,前面的隐藏层的权重和偏置会很快就固定不变,导致整个网络的效果变差。
<img src = 'http://breezepicture.oss-cn-beijing.aliyuncs.com/neural%20network/gradient_explain.png' width = '500'>
那么梯度激增是怎么回事呢,如果各个w都很大的话,超过了的影响,会出现远远大于的情况。
过拟合(overfitting)
一个模型特别是神经元数量较多的模型,在经过多次训练后能够完美拟合已有的数据,但这不一定表明这是一个完美的模型。可能只是模型很好的记忆了训练数据集中随机噪音的部分,忽略了训练数据中通用的趋势。因为这个模型实际上并没有洞悉所要解决的问题的本质,所以这种模型被用到一个新的数据集上的时候会表现地很差。
有个特别易于理解的例子,发生过拟合的模型可能会训练出下面这样的函数曲线去尽量拟合所有的点。
<img src="http://breezepicture.oss-cn-beijing.aliyuncs.com/neural%20network/overfitting1.png" width = '500'>
但是实际上我们只是想要一个线性函数模型。
<img src="http://breezepicture.oss-cn-beijing.aliyuncs.com/neural%20network/overfitting2.png" width = '500'>
其他障碍
梯度消失和梯度爆炸以及过拟合是神经网络最常见的训练障碍。其他的障碍如激活函数的选择,代价函数的选择,权重如何初始化,网络结构和超参数的选择,对于不同的问题有没有更好的梯度下降方式。太多的影响决定了一个神经网络的成功与否,所以这也是很多人觉得深度学习是在炼丹的原因,下面介绍比较经典的优化方法,当然目前很多神经网络研究人员都在寻找更多新的优化方法,如Momentum,RMSProp,Adam等新的方法不断出现,在之后会不断补充和跟进。
优化方法
加速学习过程
选取更好的代价函数能够获得更好或者更快的梯度下降效果。针对不同的实际问题需要选择不同的代价函数,有时候甚至需要自己根据问题情况自定义代价函数。
选取不同的激活函数,用不同的输出层也能改变学习的速度。
避免过度拟合
避免过度拟合的方法多种多样,最简单的就是增加训练样本的数量,当然还有其他方法:
规范化(regularization)
也叫正则化。规范化的思想就是在损失函数中加入刻画模型复杂程度的指标。假设用于刻画模型在训练数据上表现的损失函数为,那么在优化时候不是直接对这个损失函数优化,而是优化。这里的表示的是所有的权重和偏置,R(w)刻画的是模型的复杂程度,而表示的是模型复杂损失在总损失中的比例,也叫规范化参数。
L2规范化
L2规范化也叫权重衰减(weight decay),想法是增加一个额外的项到代价函数上,这个项叫做规范化项。规范化之后的交叉熵如下:
更一般的,代价函数经过规范化之后:
其中就是规范化参数,而n就是训练集的大小。规范化项里面不包含偏置。
从式子上看规范化的效果是让网络学习小一点的权重,避免特别大的权重的出现。只有权重对于代价函数的第一项的提升要足够大的时候才被允许。越大就越倾向于小的权重。
现在我们再来看看权重的随机梯度下降在加了L2规范化之后会变成什么样:
规范化是能够减少过拟合的,从直觉上看:小的权重在某种程度上,意味着更低的复杂性,也就对数据给出了一种更简单却更强大的解释,应该优先选择。其实如果要解释的话一个神经网络如果有很多很小的权重的时候,它不会受到局部偶然出现的噪声太大的干扰,因此能够更好地泛化,这一点能够结合过拟合的两张图来理解。
L1规范化
在未规范化的代价函数上加一个权重绝对值的和:
弃权(Dropout)
通常我们训练一个网络,假设我们有一个训练数据x和对应的目标输出y。我们会现在网络中前向传播x,然后进行反向传播来修改权重和偏置。
弃权的机制比较奇特,在保持输入层和输出层的神经元不变时,随机地删除网络中的一半的隐藏神经元。然后前向传播输入x中的一小批数据,通过已经经过修改的网络,反向传播结果,并进行修改。
之后在进行下一批小批量数据的训练之前,把上一步弃置的隐藏神经元重新激活重置,选择一个新的随机的隐藏神经元子集进行弃置。然后重复一开始的操作。
权重初始化优化
在神经网络开始训练之前都要进行权重的初始化来进行前向传播,初始化地够好的话可能不需要把权重修改太多就可以达到很好的效果,从而使得网络快速收敛,学习地更快。
在教程的前面使用的是独立高斯随机变量来选择权重和偏置,被归一化为0,标准差为1。这个权重初始化在神经元数量少的时候表现还行,但是当神经元数量达到更高数量如1000时候,其实是一个非常宽的高斯分布,并不是靠近0的非常尖的形状。这就会导致部分会变得非常的大,如果这样就会接近1或者0,表示我们的隐藏神经元会饱和。
所以如果我们有个输入权重的神经元,更好的方法是使用均值为0标准差为的高斯随机分布初始化这些权重。这么做相当于从两侧积压高斯分布,使得变得尖锐,更多集中在0附近。
卷积神经网络(CNN-Convolutional neural networks)
卷积神经网络最初被独特设计并且应用于图像的分类和识别。它采用了三个基本概念:局部感受野(local receptive fields),共享权重(shared weights),和混合(pooling)。卷积神经网络结合了传统图像处理中的思路,这种结构更适合表现图像的整体特点和特征的提取,除了图像,这个模型也被广泛应用于其他应用场景。
局部感受野
局部感受野是输入像素上的一个小窗口,有点像一个规定大小的小镜头,每次只能看到原图像的一部分区域,然后把看到的局部特征信息传递给隐藏层的神经元,之后不断移动这个小镜头直到隐藏层把各个部分的特征不断拼接整合,最后学习到整体的图形特性。这个思想和图像处理中使用不同的卷积核对图像进行特征的提取和放大是一致的,所以得名卷积神经网络。
从两幅图了解这个概念比较方便:
这是第一层隐层的第一行第一个神经元通过局部感受野和输入神经元之间产生的关系
<img src='http://breezepicture.oss-cn-beijing.aliyuncs.com/neural%20network/local%20field_1.png' width = '500'>
然后我们往右一个像素(即一个神经元)移动局部感受野,连接到第二个隐藏神经元:
<img src='http://breezepicture.oss-cn-beijing.aliyuncs.com/neural%20network/local%20field_2.png' width = '500'>
这样的话按照图中所示,如果我们有一个的输入图像,的局部感受野,那么隐藏层中就会有个神经元。在这个例子中局部感受野每次移动一个像素,实际上可以使用不同的跨距。如选择往右或者往下移动2个像素的局部感受野,这种情况下使用了2个跨距。
共享权重和偏置
结合卷积核的概念很容易理解这个概念,以上面的局部感受野为例,这个局部感受野有一个的权重矩阵w和一个偏置b,每个隐层的神经元的输出值结果都是用这个共享的权重和偏置与每次局部感受野对应的输入层激活值进行计算后得来的。
其实就是个简单的卷积计算,用公式来解释,对于第个隐藏神经元,也就是第个输出节点,输出为:
这里是神经元的激活函数,表示位置为的输入层激活值。
上面的例子默认照片是只有一层图层的灰度图,如果是RGB图的话,局部感受野就会为每一个图层设置一个的权重矩阵和一个偏置b,对于第个隐藏层神经元,输出为:
我们可以理解为这个共享权重和共享偏置实现了从输入层到隐藏层的一个特征映射,第一层隐藏层的所有神经元都是在努力检测和表征完全相同的特征。由于和卷积关系密切,这一层也叫做卷积层。
为了检测图片的多种特征,一个完整的卷积层由好几个特征映射组成。例如如果第一个卷积层使用的是尺寸,深度为的过滤器,就由个特征映射组成。
如果输入层的维度是,那么这个卷积层需要设置的参数为
混合(pooling)
除了上面提到的卷积层,卷积神经网络里面也包括混合层(pooling layer),它的目的是简化从卷积层输出的信息。
一个常见的混合方法是最大值混合(max-pooling)。一个混合单元简单地输出其输入区域的最大激活值。
<img src = 'http://breezepicture.oss-cn-beijing.aliyuncs.com/neural%20network/max-pooling.png'>
还有的混合方法有如L2混合,取区域中激活值的平方和的平方根。
结构示例
如果有三个特征映射,组合在一起的卷积层和最大值混合层添加上额外的一层10个输出神经元。结构如下:
<img src = 'http://breezepicture.oss-cn-beijing.aliyuncs.com/neural%20network/CNN-model.png' width = '500'>
上图中网络的最后连接的层是一个全连接层。这一层将最大值混合层的每一个神经元连接到每一个输出神经元。为了简化只用了一个箭头来表示这个全连接的关系。