3.1 神经元
神经细胞利用“电-化学”过程进行信号交换,但信号在大脑中实际怎样传输是一个相当复杂的过程。深度学习并不模拟完整的神经元,为了方便计算机使用,我们简化其模型,通常只借用神经科学中的一些概念去帮助我们理解。
我们将大脑的神经细胞简化为两种状态:兴奋(fire)和不兴奋(即抑制),发射信号的强度不变,变化的仅仅是频率。神经细胞利用我们还不知道的方法,把所有输入进神经元的信号进行累加,如果全部信号的总和超过某个阈值,就会刺激神经细胞进入兴奋状态,这时就会有电信号发送给其他神经细胞。如果信号总和没有达到某个阈值,神经细胞就会处于抑制状态,不向周围发送信号。虽然这样的解释有点过于简单,但已能满足我们的目的了。
如图3-1所示,为神经元模型。该模型主要由两部分构成,第一部分进行信号累加,就如我们第2章介绍过的得分函数(score function),该部分仅对输入信号(输入数据)进行累加求和,如式(3.1)所示,每一权重wi对应着相应的数据维度xi,而w0作为我们的偏置项(bias)就相当于函数的截距项或常数项。为了简化描述,我们通常增加第0维输入,该输入为常数1,将偏置项作为第0维的权重处理,在几何学中,我们也将这种计算称为仿射变换(Affine Transformation)。
第二部分为激活函数(Activation Function),这是神经元的关键,通常使用某类激活函数,就被称为某类神经元。如果我们的激活函数使用Sigmoid激活函数,那该神经元就相当于Logistic回归[1]。
图3-1 神经元模型
如图3-2所示,最开始的激活函数使用的是阈值(Threshold)[2]激活函数,就如我们对神经元的最简化描述一样,如果阈值超过了0,那函数就恒定输出1;如果小于0,函数就恒定输出0。该函数虽然不能求导,但使用感知机收敛理论[3](可以说是随机梯度下降的鼻祖),依然可以学习线性可分的数据。但该神经元无法在多层感知机中学习基于梯度的优化算法,因此很少应用在现代神经网络中。
图3-2 阈值激活函数图像
3.1.1 Sigmoid神经元
以上的阈值函数已经可以很好地模拟神经元了,但其最致命的缺点(无法求导)也使得它无法应用到神经网络中。为了克服这一障碍,就引进了一种“软阈值”函数,也就是如图3-3所示的Sigmoid函数[4]。式(3.2)为该函数的表达式,如式(3.3)所示,Sigmoid函数还有着非常简洁的导数表达式。
Sigmoid函数的导函数。
在很长一段时间内,Sigmoid神经元都是神经网络的默认配置,其不但能很好地模拟生物神经元的特点,并且还有着很和谐的函数性质,但它也有着一个过去人们比较忽视的缺点,那就是易饱和性(saturation),当输入值非常大或者非常小的时候,这些神经元的梯度就接近于0。从图3-3中函数的变化趋势可以看出,当输入值远离0时,其函数会很快变得平稳,而这种平稳的代价就是梯度接近于0。也就是说,当我们试图修改权重时,几乎得不到梯度进行学习。就如同一杯几乎饱和了的盐水,想要让其变淡,但每次只能加入几滴水。因此,使用Sigmoid神经元时,尤其需要注意参数的初始值来尽量避免饱和情况。如果初始值很大的话,大部分神经元可能都会处在饱和状态,这会导致网络变得很难学习,此时的学习就像“清水滴石”“铁杵磨针”,对于初学者而言或许没有太多感触,但当你进行实验时,就会发现这有多糟糕。
图3-3 Sigmoid神经元函数曲线
Sigmoid神经元还有一个小缺点,那就是其输出的期望不是0,这是不可取的,因为这会导致后一层的神经元将得到上一层输出的非0均值信号作为输入,这一知识点将会在第5章批量归一化(Batch Normalization)[5]章节中重点描述。
3.1.2 Tanh神经元
如图3-4所示,为双曲线正切(Hyperbolic Tangent)[6]激活函数的函数图像。该函数的取值为(-1,1),由于其函数期望为0,因此可算作是Sigmoid神经元的一个小改进,通常在需要使用Sigmoid神经元的情况下,双曲线正切神经元是一个比较好的替代。但该神经元依然存在易饱和的性质,如式(3.4)所示,为该激活函数的表达式。
虽然该函数看着比较复杂,但如式(3.5)所示,该函数化简之后其实就是Sigmoid函数的一个变形。
如式(3.6)所示,是该函数的导数,其导数为1减去该函数自身的平方。
图3-4 Tanh神经元函数
3.1.3 ReLU神经元
从2006年至今可以被称为神经网络的第三次高潮,大量的研究人员在此期间提出了重要的方法,但若非要列举几个最重要的突破,修正线性单元(Rectified Linear Units,ReLU)[7]的使用必然位列其中。在2006年之前,深度学习就像是机器学习领域的异类,过高的模型复杂度,使其难以进行数学分析,大量的训练“技巧”让外人难以进入该领域,非常容易过拟合又让人看不到希望。
当时深度学习最严重的问题就是梯度消失问题,模型的层数较多时,甚至只有三四层时,模型几乎就无法训练了。而以Hinton为首的深度学习研究者终于使用逐层贪婪非监督预训练学习的方法缓解了梯度消失这一问题。由于每一层都有较好的初始化,即使神经网络的底层依然无法得到有效的训练,但也能有一个非常好的训练结果。于是研究深度学习的“异类”们才渐渐地得到了鲜花和掌声,但逐层贪婪预训练方法并没有解决梯度消失问题,梯度消失始终就像是悬挂在深度学习头顶的“达摩克里斯之剑”。
故事并不像小说那样,主角都需要骨骼惊奇,万中无一,但故事又如人们期望的那样,救世主总是命中注定的。这就是本节将重点推介的平凡主角——修正线性单元(Rectified Linear Units,ReLU)。我喜欢戏称ReLU为“平凡的天选之人”,所谓平凡,指的是该神经元的简单;所谓的“天选之人”,指的是该神经元是更加接近生物神经元的模型。
深度学习早已脱离了“模拟大脑”的僵化描述,但深度学习的每一次重大突破,又和我们对自身大脑的认知脱不了关系。我们对于大脑、神经元的过简描述并不能有效地帮助我们。同样地,我们对于神经元的过于复杂或过充分模拟也无法有效地帮助我们,如何折中并找到平衡,我们或许只能是“摸着石头过河”。就ReLU而言,比其简单的模型有过,比其复杂的模型也多不胜举,随着时间的推移,研究人员“众里寻他千百度”,提出了各种复杂“高深”的观点及算法,但蓦然回首,找到了如此简单又如此合理的ReLU,如图3-5所示。
图3-5 修正线性单元函数图像
看完图3-5所示的修正线性单元函数图像,不知你是什么感觉,“这不就是被阉割的线性函数吗?有什么了不起的。”如果你有这样的想法那也很正常,如式(3.7)所示,该函数正半部分仅是一次函数的正半部分,负半部分是x轴的负半部分。
我们知道线性单元组合后的模型能力依然是线性能力,那首先需要质疑的就是,这被“砍了半截”的线性单元又有多强的能力呢?为了回答这个问题,我们使用致使神经网络第一次大衰败的“异或”问题作为案例。
图3-6 异或数据空间展示图
如图3-6所示,有{ (1,1), (1,0), (0,1), (0,0) }4个数据,数据(1,1)和数据(0,0)属于同一类,我们用“0”表示;而数据(1,0)和数据(0,1)属于同一类,我们用“1”表示。就相当于我们的数据有两维,若两维值相同就输出“0”,相反就输出“1”。我们使用任意的直线都无法完全分割该数据空间,而我们想要验证的就是ReLU这种“半截直线”的组合是否可以解决著名的“异或”问题,从而证明ReLU是否是一种非线性转换函数,也就证明了ReLU虽然外表“简单”,但同样拥有强大的非线性转换能力,换句话说,就是这家伙“城府深”。
图3-7为我们设计用于解决异或问题的网络模型,该模型为一个标准的前馈神经网络,网络中每一个神经元都使用ReLU激活函数。式(3.8)为该网络的函数表达。其中矩阵W为第一层网络的连接权重,向量c为第一层的偏置项(也就是函数的常数项或截距),向量w为第二层的连接权重,向量b为第二层的偏置项。如式(3.9)所示,列出了其中各连接的权值。
图3-7 解决异或问题的网络模型
如式(3.10)所示,X用于存放异或数据,X中的每一行代表一条数据,每一列代表数据的维度。
首先将数据的输入与对应的权重相乘再相加,也就是式(3.11),使用矩阵乘法。
接下来我们加上向量c,就得到如下左侧所示的结果,但我们的激活函数会将负数全部截断为0,因此就得到如下右侧所示的最终结果。
我们将该结果用图3-8表示,就会发现一些有趣的现象,“异号”的数据被正确地映射到了同一点。那现在我们就可以轻松地找到一条直线,然后完美地分割这些数据。最后再使用向量w去乘特征转换后的数据,就得到了如下所示的最终结果,该结果是使用线性函数无法分割的异或数据问题。
图3-8 使用ReLU激活函数学习到的特征数据
目前为止,我们训练神经网络只有一招,那就是构造代价函数,然后求解梯度,修改网络权重。但使用ReLU函数时会有麻烦,因为ReLU在0点处不可导,该函数在零点的左导数为0,而右导数为1,当我们编程实现深度学习时,返回该激活函数其中一边的导数(如右导数)即可。不知对于比较“严谨”的读者来说,这算不算灾难,但请放松些,我们学的并不是数学。在实际应用中,虽然这些部分不可导,但其执行的性能依然足够好。
其中的部分原因在于,深度学习算法通常不是寻找代价函数最低点(训练数据的最优值不一定是测试数据的最优值),而是显著地降低代价函数。由于我们并不期望能到达梯度为0的点(山谷最低点),那么使用不严谨的梯度,如随机梯度下降法,也是可以接受的。ReLU函数还有一个致命的缺点,那就是当神经元没有激活时,将永远无法修改其权重,就相当于神经元死亡了。
ReLU可以看作是两条分段线性函数,只是其中一条分段函数输出恒为零。如式(3.12)所示,为通用的修正线性单元的函数表达式。
当α=0时,就是我们前面介绍的ReLU。若固定α= -1,该函数可表示为f(x)=|x|,其就被称为绝对值修正单元(Absolute Value Rectification)[8]。而将α固定为较小的值,如0.01时,就称之为裂缝修正单元(Leaky ReLU)[9]。当α的值较小时,该函数的负半轴函数和横坐标的夹角就非常的小,因此使用“leaky”一词来形容,当然也可以使用PReLU[10]将α作为一个可变参数来调整学习。
如果喜欢追求函数的表达能力,可以使用Maxout单元(Maxout Units)[11]。Maxout由k段线性分段函数构成,具有很强的拟合能力。由Maxout组成的神经网络,不仅要学习神经元间的关系,还需要学习激活函数本身,这就好比一般的神经网络是一群比较“愚笨”的人去相互协作,而Maxout就好像一群比较“聪明”的人去互相帮助。Maxout虽然能力强大,但大量的参数也加重了训练的负担。