本节从神经元讲起,分别介绍了激活函数和神经网络结构
在线性分类中,我们使用
s=Wx
计算类别的评分函数,其中
W
为一个矩阵,
神经元
大脑的基本计算单位是神经元(neuron)。人类的神经系统中大约有860亿个神经元,由大约
1014−1015
个突触(synapses)连接起来。下面第一幅图是一个生物学的神经元,第二幅是一个常用的数学模型。每个神经元都从它的树突获得输入信号,然后沿着它唯一的轴突(axon)产生输出信号。轴突在末端会逐渐分枝,通过突触和其他神经元的树突相连。
在神经元的计算模型中,信号顺着轴突(比如
x0
)传递,然后在轴突处受到激励(
w0
),然后变成
w0x0
,可以这么认为,突触的强度(也就是权重
w
),是可学习的并且可以控制一个神经元对于另一个神经元的影响强度,还可以控制影响方向:使其兴奋(正权重)或使其抑制(负权重)。
在基本模型中,树突将信号传递到细胞体,信号在细胞体中相加。如果最终之和高于某个阈值,那么神经元将会激活,向其轴突输出一个峰值信号。在计算模型中,我们将神经元的激活率建模为激活函数(activation function),它表达了轴突上激活信号的频率。历史上,激活函数常使用sigmoid函数,该函数输入实数值(求和后的信号强度),输出值被压缩到
![这里写图片描述](http://cs231n.github.io/assets/nn1/neuron.png)
![这里写图片描述](http://cs231n.github.io/assets/nn1/neuron_model.jpeg)
一个简单的神经元前向传播代码如下所示
class Neuron(object):
# ...
def forward(inputs):
""" 假设输入和权重是1-D的numpy数组,偏差是一个数字 """
cell_body_sum = np.sum(inputs * self.weights) + self.bias
firing_rate = 1.0 / (1.0 + math.exp(-cell_body_sum)) # sigmoid激活函数
return firing_rate
注意:这只是个粗糙的模型,实际上生物体内的神经元相当复杂,比如神经元的种类就非常多,并且加和信号之后的激励函数的非线性变换,也比数学上模拟出来的函数复杂得多。数学建模的神经网络只是一个非常简化的模型,跟实际神经元还有很大差距。
单个神经元分类
像线性分类器中那样,神经元有能力“喜欢”(激活函数值接近1),或者不喜欢(激活函数值接近0)输入空间中的某些线性区域。因此,只要在神经元的输出端有一个合适的损失函数,就能让单个神经元变成一个线性分类器。
二分类Softmax分类器。我们标记
σ
为sigmoid映射函数,则
二分类SVM分类器。在神经元的输出外增加一个最大边界折叶损失(max-margin hinge loss)函数,就可以将其训练成一个二分类的支持向量机。
理解正则化。在SVM/Softmax的例子中,正则化损失从生物学角度可以看做逐渐遗忘,因为它的效果是让所有突触(权重)在参数更新过程中逐渐向着0变化。
一个单独的神经元可以用来实现一个二分类分类器,比如二分类的Softmax或者SVM分类器。
常用激活函数
Sigmoid函数
![这里写图片描述](http://cs231n.github.io/assets/nn1/sigmoid.jpeg)
sigmoid函数的数学公式是
Sigmoid函数饱和特性使梯度消失。当神经元的激活在接近0或1处时会饱和:在这些区域,梯度几乎为0。反向传播时,这个(局部)梯度将会与整个损失函数关于该门单元输出的梯度相乘。因此,如果局部梯度非常小,那么相乘的结果也会接近零,这会有效地“杀死”梯度,几乎没有信号可通过神经元传到权重再到数据。另外,为了防止饱和,必须对于权重矩阵初始化特别留意。如果初始化权重过大,那么大多数神经元将会饱和,网络几乎不会学习。
Sigmoid函数输出不是零中心对称。神经网络后面层中的神经元得到的数据将不是零中心的。这一情况将影响梯度下降的运作,因为如果输入神经元的数据总是正数(比如在 f=wTx+b 中每个元素都 x>0 ),那么关于 w 的梯度在反向传播的过程中,将会要么全部是正数,要么全部是负数。这将会导致梯度下降权重更新时出现
z 字型的下降。当然,如果整个批量的数据的梯度被加起来后,权重的最终更新将会有不同的正负。因此,该问题相对神经元饱和问题来说只是个小麻烦。
Tanh函数
![这里写图片描述](http://cs231n.github.io/assets/nn1/tanh.jpeg)
Tanh函数会将输入值压缩至 [−1-1] ,当然,它同样也有sigmoid函数里在很大或者很小的输入值下,神经元很容易饱和的缺点。但是它它的输出是零中心化的。因此实际应用中,tanh激励函数还是比sigmoid要用的多。tanh神经元是一个简单放大的sigmoid神经元,具体说来就是: tanh(x)=2σ(2x)−1 。
ReLU函数
![这里写图片描述](http://cs231n.github.io/assets/nn1/relu.jpeg)
ReLU函数公式为 f(x)=max(0,x) ,近些年来变得非常流行。可以说,这个激活函数就是一个关于0的阈值(如上图)。ReLU函数优缺点如下:
- 优点1:相较于sigmoid和tanh函数,ReLU对于随机梯度下降的收敛有巨大的加速作用( 相关论文指出有6倍之多)。据称这是由它的线性,非饱和的公式导致的。
- 优点2:sigmoid和tanh神经元含有指数运算等耗费计算资源的操作,而ReLU可以简单地通过对一个矩阵进行阈值计算得到。
- 缺点:在训练的时候,ReLU单元比较脆弱并且可能“死掉”。举例来说,当一个很大的梯度流过ReLU的神经元的时候,可能会导致梯度更新到一种特别的状态,此时神经元将无法被其他任何数据点再次激活。如果这种情况发生,那么从此所以流过这个神经元的梯度将都变成0,这个ReLU单元在训练中将不可逆转的死亡,从而导致数据多样化的丢失。如果学习率设置得太高,可能会发现网络中40%的神经元都会死掉(在整个训练集中这些神经元都不会被激活)。通过合理设置学习率,这种情况的发生概率会降低。
Leaky ReLU函数
针对ReLU单元的弱点,研究者做了这么一件事,在
x<0
的部分,leaky ReLU不再让
y=0
,而是设定为一个坡度很小(比如斜率0.01)的直线。
f(x)
因此是一个分段函数,
x<0
时,
f(x)=αx
(
α
是一个很小的常数),
Maxout函数
近些年非常受欢迎的激励函数Maxout,它并不是对
WTX+b
做非线性映射
f(WTX+b)
。简单说来,它是ReLU和Leaky ReLU的一个泛化版本。对于输入
x
,Maxout神经元计算
激励函数/神经元小总结
即使从计算和训练的角度看来是可行的,实际应用中,其实我们很少会把多种激励函数混在一起使用。
一般说来,用的最多的依旧是ReLU,但是我们确实得小心设定学习率,同时在训练过程中,还得时不时看看神经元此时的状态(是否死亡)。当然,如果你非常担心神经元训练过程中挂掉,你可以试试Leaky ReLU和Maxout。不要用sigmoid函数了,可以试试tanh,不过通常状况下,它的效果不如ReLU/Maxout。
神经网络结构
组建层
神经网络结构是一种单向的层级连接结构,每一层可能有多个神经元,神经元之间以无环图的形式进行连接。
普通神经网络,最普通的层的类型是全连接层。全连接层中神经元与其前后两层的神经元是完全成对连接的,但同一层内的神经元之间没有连接。下图是两个使用的全连接层的神经网络:
命名规则。当我们说N层神经网络的时候,我们没有把输入层算入。因此,单层的神经网络就是没有隐层的(输入直接映射到输出)。有的认为逻辑回归或者SVM只是单层神经网络的一个特例。研究者们也会使用人工神经网络(Artificial Neural Networks 缩写ANN)或者多层感知器(Multi-Layer Perceptrons 缩写MLP)来指代神经网络。很多研究者倾向于用单元(unit)而不是神经元作为术语。
输出层。和神经网络中其他层不同,输出层神经元一般不会有激活函数(或可认为它们有一个线性相等的激活函数)。这是因为最后的输出层大多用于表示分类评分值,因此是任意值的实数,或者某种实数值的目标数(比如在回归中)。
确定网络尺寸。用来度量神经网络的尺寸的标准主要有两个:一个是神经元的个数,另一个是参数的个数,用上面图示的两个网络举例:
- 第一个网络有4+2=6个神经元(输入层不算),[3x4]+[4x2]=20个权重,还有4+2=6个偏置,共26个可学习的参数。
- 第二个网络有4+4+1=9个神经元,[3x4]+[4x4]+[4x1]=32个权重,4+4+1=9个偏置,共41个可学习的参数。
神经网络前向传播示例
神经网络组织成层状的一个主要原因,就是这个结构让神经网络算法使用矩阵向量操作变得简单和高效。上图3层神经网络,输入是np.dot(W1, x)
就能计算该层中所有神经元的激活数据。类似的,
W2
将会是
[4,4]
矩阵,存储着第二个隐层的连接,
W3
是
[1,4]
的矩阵,用于输出层。代码如下:
# 一个3层神经网络的前向传播:
f = lambda x: 1.0/(1.0 + np.exp(-x)) # 激活函数(用的sigmoid)
x = np.random.randn(3, 1) # 含3个数字的随机输入向量(3x1)
h1 = f(np.dot(W1, x) + b1) # 计算第一个隐层的激活数据(4x1)
h2 = f(np.dot(W2, h1) + b2) # 计算第二个隐层的激活数据(4x1)
out = np.dot(W3, h2) + b3 # 神经元输出(1x1)
上述代码中,W1,W2,W3,b1,b2,b3
都是待学习的神经网络参数。注意到我们这里所有的运算都是向量化/矩阵化之后的,x
不再是一个数,而是包含训练集中一个batch的输入,这样并行运算会加快计算的速度。最后一层是没有经过激励函数,直接输出。
全连接层的前向传播一般就是先进行一个矩阵乘法,然后加上偏置并运用激活函数。
神经网络表达能力
现在看来,拥有至少一个隐层的神经网络是一个通用的近似器。在研究(例如1989年的论文Approximation by Superpositions of Sigmoidal Function,或者Michael Nielsen的直观解释。)中已证明,给出任意连续函数
f(x)
和任意
ϵ>0
,均存在一个至少含1个隐层的神经网络
g(x)
(并且网络中有合理选择的非线性激活函数,比如sigmoid),对于
∀x
,使得
|f(x)−g(x)|<ϵ
。换句话说,神经网络可以近似任何连续函数。
既然一个隐层就能近似任何函数,那为什么还要构建更多层来将网络做得更深?答案是:虽然一个2层网络在数学理论上能完美地近似所有连续函数,但在实际操作中效果相对较差。在一个维度上,虽然以
a,b,c
为参数向量“指示块之和”函数
g(x)=∑ici1(ai<x<bi)
也是通用的近似器,但是谁也不会建议在机器学习中使用这个函数公式。神经网络在实践中非常好用,是因为它们表达出的函数不仅平滑,而且对于数据的统计特性有很好的拟合。同时,网络通过最优化算法(例如梯度下降)能比较容易地学习到这个函数。类似的,虽然在理论上深层网络(使用了多个隐层)和单层网络的表达能力是一样的,但是就实践经验而言,深度网络效果比单层网络好。
另外,在实践中3层的神经网络会比2层的表现好,然而继续加深(做到4,5,6层)很少有太大帮助。卷积神经网络的情况却不同,对于一个良好的识别系统来说,深度是一个极端重要的因素(比如数十(以10为量级)个可学习的层)。对于该现象的一种解释观点是:因为图像拥有层次化结构(比如脸是由眼睛等组成,眼睛又是由边缘组成),所以多层处理对于这种数据就有直观意义。
层数与尺寸的影响
首先,要知道当我们增加层的数量和尺寸时,网络的容量上升了。即神经元们可以合作表达许多复杂函数,所以表达函数的空间增加。例如,如果有一个在二维平面上的二分类问题。我们可以训练3个不同的神经网络,每个网络都只有一个隐层,但是每层的神经元数目不同:
在上图中,可以看见有更多神经元的神经网络可以表达更复杂的函数。然而这既是优势也是不足,优势是可以分类更复杂的数据,不足是可能造成对训练数据的过拟合。过拟合是网络对数据中的噪声有很强的拟合能力,而没有重视数据间(假设)的潜在基本关系。
上图中,有20个神经元隐层的网络拟合了所有的训练数据,但是其代价是把决策边界变成了许多不相连的红绿区域。而有3个神经元的模型的表达能力只能用比较宽泛的方式去分类数据。它将数据看做是两个大块,并把个别在绿色区域内的红色点看做噪声。在实际中,这样可以在测试数据中获得更好的泛化(generalization)能力。
基于上面的讨论,看起来如果数据不是足够复杂,则似乎小一点的网络更好,因为可以防止过拟合。然而并非如此,防止神经网络的过拟合有很多方法。
在实践中,不要去减少网络神经元数目,使用L2正则化,dropout和输入噪音等方法来控制过拟合比减少网络神经元数目要好得多。
不要减少网络神经元数目的主要原因在于小网络更难使用梯度下降等局部方法来进行训练
虽然小型网络的损失函数的局部极小值更少,也比较容易收敛到这些局部极小值,但是这些最小值一般都很差,损失值很高。相反,大网络拥有更多的局部极小值,但就实际损失值来看,这些局部极小值表现更好,损失更小。
神经网络是非凸的,很难从数学上研究这些特性。有一些文章尝试对这些目标函数进行理解,比如The Loss Surfaces of Multilayer Networks。
实际中,你将发现如果训练的是一个小网络,那么最终的损失值将展现出多变性:某些情况下运气好会收敛到一个好的地方,某些情况下就收敛到一个不好的极值。而如果你训练一个大的网络,你将发现许多不同的解决方法,最终损失值的差异将会小很多,对于随机初始化参数好坏的依赖也会小很多。
重申一下,正则化强度是控制神经网络过拟合的好方法,而不要去减少神经元。
上图是不同正则化强度的效果:每个神经网络都有20个隐层神经元,但是随着正则化强度增加,它的决策边界变得更加平滑。
不应该因为害怕出现过拟合而使用小网络。相反,应该进尽可能使用大网络,然后使用正则化技巧来控制过拟合。
参考资料
链接:http://cs231n.github.io/neural-networks-1/
链接:https://zhuanlan.zhihu.com/p/21462488?refer=intelligentunit
https://zhuanlan.zhihu.com/p/21513367?refer=intelligentunit
链接:http://blog.csdn.net/han_xiaoyang/article/details/50447834