作者:寒小阳
时间:2016年1月。
出处:http://blog.csdn.net/han_xiaoyang/article/details/50447834
声明:版权全部。转载请联系作者并注明出处
1.神经元与含义
大家都知道最開始深度学习与神经网络,是受人脑的神经元启示设计出来的。所以我们依照惯例也交代一下背景。从生物学的角度開始介绍,当然也是对神经网络研究的先驱们致一下敬。
1.1 神经元激励与连接
大家都知道。人脑的基本计算单元叫做神经元。现代生物学表明,人的神经系统中大概有860亿神经元,而这数量巨大的神经元之间大约是通过
以下有一幅示意图,粗略地描绘了一下人体神经元与我们简化过后的数学模型。
每一个神经元都从树突接受信号。同一时候顺着某个轴突传递信号。
而每一个神经元都有非常多轴突和其它的神经元树突连接。而我们能够看到右边简化的神经元计算模型中,信号
也是顺着轴突
(比方
我们能够这么理解这个模型:在信号的传导过程中,突触能够控制传导到下一个神经元的信号强弱(数学模型中的权重
以下是一个简单的程序样例,表明前向传播中单个神经元做的事情:
class Neuron:
# ...
def forward(inputs):
"""
假定输入和权重都是1维的numpy数组。同一时候bias是一个数
"""
cell_body_sum = np.sum(inputs * self.weights) + self.bias
firing_rate = 1.0 / (1.0 + math.exp(-cell_body_sum)) # sigmoid activation function
return firing_rate
稍加解释,每一个神经元对于输入和权重做内积,加上偏移量bias。然后通过激励函数(比方说这里是sigmoid函数)。然后输出结果。
特别说明:实际生物体内的神经元相当复杂。比方说,神经元的种类就灰常灰常多,它们分别有不同的功能。而加和信号之后的激励函数的非线性变换。也比数学上模拟出来的函数复杂得多。我们用数学建模的神经网络仅仅是一个非常简化后的模型,有兴趣的话你能够阅读材料1或者材料2。
1.2 单个神经元的分类作用
以sigmoid函数作为神经元的激励函数为例,这个大家可能略微熟悉一点。毕竟我们逻辑回归部分重点提到了这个非线性的函数,把输入值压缩成0-1之间的一个概率值。而通过这个非线性映射和设定的阈值。我们能够把空间切分开,分别相应正样本区域和负样本区域。
而相应回如今的神经元场景,我们假设稍加拟人化,能够觉得神经元具备了喜欢(概率接近1)和不喜欢(概率接近0)线性划分的某个空间区域的能力。这也就是说。仅仅要调整好权重,单个神经元能够对空间做线性切割。
二值Softmax分类器
对于Softmax分类器具体的内容欢迎參见前面的博文系列,我们标记
二值SVM分类器
相同的。我们能够设定max-margin hinge loss作为损失函数,从而将神经元训练成一个二值支持向量机分类器。具体的内容依然欢迎大家查看之前的博客。
对于正则化的解释
对于正则化的损失函数(无论是SVM还是Softmax)。事实上我们在神经元的生物特性上都能找到相应的解释。我们能够将其(正则化项的作用)视作信号在神经元传递过程中的逐步淡化/衰减(gradual forgetting),由于正则化项的作用是在每次迭代过程中,控制住权重
单个神经元的作用。可视作完毕一个二分类的分类器(比方Softmax或者SVM分类器)
1.3 经常使用激励函数
每一次输入和权重w线性组合之后,都会通过一个激励函数(也能够叫做非线性激励函数),经非线性变换后输出。
实际的神经网络中有一些可选的激励函数,我们一一说明一下最常见的几种:
1.3.1 sigmoid
sigmoid函数提到的次数太多。相信大家都知道了。数学形式非常简单。是
不得不说,早期的神经网络中。sigmoid函数作为激励函数使用非常之多,由于大家觉得它非常好地解释了神经元受到刺激后是否被激活和向后传递的场景(从差点儿没有被激活,也就是0,到全然被激活,也就是1)。
只是似乎近几年的实际应用场景中。比較少见到它的身影,它基本的缺点有2个:
- sigmoid函数在实际梯度下降中。easy饱和和终止梯度传递。我们来解释一下,大家知道反向传播过程。依赖于计算的梯度。在一元函数中,即斜率。而在sigmoid函数图像上。大家能够非常明显看到。在纵坐标接近0和1的那些位置(也就是输入信号的幅度非常大的时候)。斜率都趋于0了。我们回忆一下反向传播的过程。我们最后用于迭代的梯度,是由中间这些梯度值结果相乘得到的。因此假设中间的局部梯度值非常小,直接会把终于梯度结果拉近0,也就是说。残差回传的过程,由于sigmoid函数的饱和被杀死了。说个极端的情况,假设一開始初始化权重的时候。我们取值不是非常恰当,而激励函数又全用的sigmoid函数,那么非常有可能神经元一个不剩地饱和到无法学习,整个神经网络也根本没办法训练起来。
- sigmoid函数的输出没有
0中心化
,这是一个比較闹心的事情。由于每一层的输出都要作为下一层的输入。而未0中心化会直接影响梯度下降,我们这么举个样例吧,假设输出的结果均值不为0。举个极端的样例。全部为正的话(比如f=wTx+b 中全部x>0 ),那么反向传播回传到w 上的梯度将要么全部为正要么全部为负(取决于f的梯度正负性)。这带来的后果是,反向传播得到的梯度用于权重更新的时候,不是平缓地迭代变化,而是相似锯齿状的突变。当然。要多说一句的是。这个缺点相对于第一个缺点。还略微好一点。第一个缺点的后果是,非常多场景下,神经网络根本没办法学习。
1.3.2 Tanh
Tanh函数的图像如上图所看到的。
它会将输入值压缩至-1到1之间,当然,它相同也有sigmoid函数里说到的第一个缺点,在非常大或者非常小的输入值下,神经元非常easy饱和。可是它缓解了第二个缺点,它的输出是0中心化的。
所以在实际应用中,tanh激励函数还是比sigmoid要用的多一些的。
1.3.3 ReLU
ReLU是修正线性单元(The Rectified Linear Unit)的简称,近些年使用的非常多。图像如上图所看到的。它对于输入x计算
换言之,以0为分界线,左側都为0。右側是y=x这条直线。
它有它相应的优势。也有缺点:
- 长处1:实验表明。它的使用,相对于sigmoid和tanh。能够非常大程度地提升随机梯度下降的收敛速度。只是有意思的是,非常多人说,这个结果的原因是它是线性的,而不像sigmoid和tanh一样是非线性的。具体的收敛速度结果对照方下图,收敛速度大概能快上6倍:
- 长处2:相对于tanh和sigmoid激励神经元。求梯度不要简单太多好么。!!
毕竟,是线性的嘛。。
。
- 缺点1:ReLU单元也有它的缺点。在训练过程中,它事实上挺脆弱的。有时候甚至会挂掉。
举个样例说吧,假设一个非常大的梯度
流经
ReLU单元,那权重的更新结果可能是,在此之后不论什么的数据点都没有办法再激活它了。一旦这样的情况发生,那本应经这个ReLU回传的梯度,将永远变为0。当然,这和參数设置有关系,所以我们要特别小心,再举个实际的样例哈,假设学习速率被设的太高,结果你会发现。训练的过程中可能有高达40%的ReLU单元都挂掉了。所以我们要小心设定初始的学习率等參数,在一定程度上控制这个问题。
1.3.4 Leaky ReLU
上面不是提到ReLU单元的弱点了嘛,所以孜孜不倦的ML researcher们,就尝试修复这个问题咯,他们做了这么一件事,在x<0的部分。leaky ReLU不再让y的取值为0了。而是也设定为一个坡度非常小(比方斜率0.01)的直线。f(x)因此是一个分段函数。x<0时。
1.3.5 Maxout
也有一些其它的激励函数。它们并非对
一个近些年非常popular的激励函数是Maxout(具体内容请參见Maxout)。简单说来,它是ReLU和Leaky ReLU的一个泛化版本号。对于输入x,Maxout神经元计算
1.4 激励函数/神经元小总结
以上就是我们总结的经常使用的神经元和激励函数类型。顺便说一句,即使从计算和训练的角度看来是可行的,实际应用中,事实上我们非常少会把多种激励函数混在一起使用。
那我们咋选用神经元/激励函数呢?一般说来。用的最多的依然是ReLU。可是我们确实得小心设定学习率,同一时候在训练过程中。还得时不时看看神经元此时的状态(是否还『活着』)。当然,假设你非常操心神经元训练过程中挂掉,你能够试试Leaky ReLU和Maxout。额,少用sigmoid老古董吧,有兴趣倒是能够试试tanh。只是话说回来,通常状况下。它的效果不如ReLU/Maxout。
2. 神经网络结构
2.1 层级连接结构
神经网络的结构事实上之前也提过。是一种单向的层级连接结构。每一层可能有多个神经元。再形象一点说,就是每一层的输出将会作为下一层的输入数据,当然,这个图一定是没有循环的。不然数据流就有点混乱了。
普通情况下。单层内的这些神经元之间是没有连接的。最常见的一种神经网络结构就是全连接层级神经网络,也就是相邻两层之间,每一个神经元和每一个神经元都是相连的。单层内的神经元之间是没有关联的。
以下是两个全连接层级神经网的示意图:
命名习俗
有一点须要注意,我们再说N层神经网络的时候。通常的习惯是不把输入层计算在内,因此输入层直接连接输出层的。叫做单层神经网络。从这个角度上说,事实上我们的逻辑回归和SVM是单层神经网络的特例。上图中两个神经网络各自是2层和3层的神经网络。
输出层
输出层是神经网络中比較特殊的一层,由于输出的内容一般是各类别的打分/概率(在分类问题中)。我们通常都不在输出层神经元中加激励函数。
关于神经网络中的组件个数
通常我们在确定一个神经网络的时候,有几个描写叙述神经网络大小的參数会提及到。最常见的两个是神经元个数,以及细化一点说,我们能够觉得是參数的个数。还是拿上面的图举例:
- 第一个神经网络有4+2=6个神经元(我们不算输入层),因此有[3*4]+[4*2]=20个权重和4+2=6个偏移量(bias项),总共26个參数。
- 第二个神经网络有4+4+1个神经元,有[3*4]+[4*4]+[4*1]=32个权重。再加上4+4+1=9个偏移量(bias项),一共同拥有41个待学习的參数。
给大家个具体的概念哈。如今有用的卷积神经网。大概有亿级别的參数。甚至可能有10-20层(因此是深度学习嘛)。只是不用操心这么多參数的训练问题,因此我们在卷积神经网里会有一些有效的方法。来共享參数,从而降低须要训练的量。
2.2 神经网络的前向计算演示样例
神经网络组织成以上的结构,一个重要的原因是,每一层到下一层的计算能够非常方便地表示成矩阵之间的运算。就是一直反复权重和输入做内积后经过激励函数变换的过程。为了形象一点说明。我们还举上面的3层神经网络为例。输入是一个3*1的向量,而层和层之间的连接权重能够看做一个矩阵。比方第一个隐藏层的权重np.dot(W1,x)
实际上就计算出输入下一层的激励函数之前的结果,经激励函数作用之后的结果又作为新的输出。用简单的代码表演示样例如以下:
# 3层神经网络的前向运算:
f = lambda x: 1.0/(1.0 + np.exp(-x)) # 简单起见,我们还是用sigmoid作为激励函数吧
x = np.random.randn(3, 1) # 随机化一个输入
h1 = f(np.dot(W1, x) + b1) # 计算第一层的输出
h2 = f(np.dot(W2, h1) + b2) # 计算第二层的输出
out = np.dot(W3, h2) + b3 # 终于结果 (1x1)
上述代码中,W1,W2,W3,b1,b2,b3
都是待学习的神经网络參数。注意到我们这里全部的运算都是向量化/矩阵化之后的,x不再是一个数,而是包括训练集中一个batch的输入,这样并行运算会加快计算的速度,细致看代码,最后一层是没有经过激励函数,直接输出的。
2.3 神经网络的表达力与size
一个神经网络结构搭起来之后,它就包括了数以亿计的參数和函数。我们能够把它看做对输入的做了一个非常复杂的函数映射,得到最后的结果用于完毕空间的切割(分类问题中)。那我们的參数对于这个所谓的复杂映射有什么样的影响呢?
事实上,包括一个隐藏层(2层神经网络)的神经网络已经具备大家期待的能力,即仅仅要隐藏层的神经元个数足够。我们总能用它(2层神经网络)去逼近不论什么连续函数(即输入到输出的映射关系)。
具体的内容能够參加Approximation by Superpositions of Sigmoidal Function或者Michael Nielsen的介绍。我们之前的博文手把手入门神经网络系列(1)_从初等数学的角度初探神经网络也有提到。
问题是,假设单隐藏层的神经网络已经能够近似逼近随意的连续值函数。那么为什么我们还要用那么多层呢?非常可惜的是。即使数学上我们能够用2层神经网近似差点儿全部函数,但在实际的project实践中,却是没啥大作用的。
多隐藏层的神经网络比单隐藏层的神经网络project效果好非常多。即使从数学上看。表达能力应该是一致的。
只是还得说一句的是,通常情况下,我们project中发现,3层神经网络效果优于2层神经网络,可是假设把层数再不断添加(4,5,6层),对最后结果的帮助就没有那么大的跳变了。
只是在卷积神经网上还是不一样的,深层的网络结构对于它的准确率有非常大的帮助,直观理解的方式是,图像是一种深层的结构化数据。因此深层的卷积神经网络能够更准确地把这些层级信息表达出来。
2.4 层数与參数设定的影响
一个非常现实的问题是。我们拿到一个实际问题的时候,怎么知道应该怎样去搭建一个网络结构,能够最好地解决问题?应该搭建几层?每一层又应该有多少个神经元?
我们直观理解一下这个问题,当我们加大层数以及每一层的神经元个数的时候。我们的神经网络容量
变大了。更通俗一点说,神经网络的空间表达能力变得更丰富了。放到一个具体的样例里我们看看。假如我们如今要处理一个2分类问题,输入是2维的。我们训练3个不同神经元个数的单隐层神经网络。它们的平面表达能力对照画出来例如以下:
在上图中。我们能够看出来,很多其它的神经元,让神经网络有更好的拟合复杂空间函数的能力。
可是不论什么事物都有双面性。拟合越来越精确带来的另外一个问题是。太easy过拟合了!。。,假设你非常任性地做一个实验。在隐藏层中放入20个神经元。那对于上图这个一个平面,你全然能够做到100%把两类点分隔开。可是这样一个分类器太努力地学习和记住我们如今图上的这些点的分布状况了,以至于连噪声和离群点都被它学习下来了,这对于我们在新数据上的泛化能力,也是一个噩梦。
经我们上面的讨论之后,或许你会觉得,好像对于不那么复杂的问题,我们用更少数目的层数和神经元,会更不easy过拟合,效果好一些。可是这个想法是错误的!
!
!。永远不要用降低层数和神经元的方法来缓解过拟合!!!这会极大影响神经网络的表达能力!。。我们有其它的方法,比方说之前一直提到的正则化来缓解这个问题。
不要使用少层少神经元的简单神经网络的另外一个原因是,事实上我们用梯度下降等方法,在这样的简单神经网上,更难训练得到合适的參数结果。对,你会和我说,简单神经网络的损失函数有更少的局部最低点。应该更好收敛。是的,确实是的。更好收敛,可是非常快收敛到的这些个局部最低点。通常都是全局非常差的。
相反,大的神经网络,确实损失函数有很多其它的局部最低点,可是这些局部最低点,相对于上面的局部最低点。在实际中效果却更好一些。对于非凸的函数,我们非常难从数学上给出100%精准的性质证明,大家要是感兴趣的话,能够參考论文The Loss Surfaces of Multilayer Networks。
假设你愿意做多次实验,会发现,训练小的神经网络,最后的损失函数收敛到的最小值变动非常大。
这意味着,假设你运气够好,那你maybe能找到一组相对较为合适的參数。但大多数情况下。你得到的參数仅仅是在一个不太好的局部最低点上的。
相反。大的神经网络,依然不能保证收敛到最小的全局最低点,可是众多的局部最低点,都有相差不太大的效果,这意味着你不须要借助”运气”也能找到一个近似较优的參数组。
最后,我们提一下正则化。我们说了要用正则化来控制过拟合问题。
正则话的參数是
恩,总之中的一个句话,我们在非常多实际问题中,还是得使用多层多神经元的大神经网络。而使用正则化来减缓过拟合现象。