深度拾遗(04)

为什么要有激活函数?

作用是能够给神经网络加入一些非线性因素。若没有激活函数,那多个神经元,多层网络其实都能归结到一层来做,公式符号都能够直接化简乘(Wx)。加入了激活函数之后,深度神经网络具备了分层的非线性映射学习能力。

特性

可微性: 当优化方法是基于梯度的时候,这个性质是必须的。
单调性: 当激活函数是单调的时候,单层网络能够保证是凸函数。
输出值的范围: 当激活函数输出值是 有限 的时候,基于梯度的优化方法会更加 稳定,因为特征的表示受有限权值的影响更显著;当激活函数的输出是 无限 的时候,模型的训练会更加高效,不过在这种情况小,一般需要更小的learning rate

常见激活函数

  1. sigmoid $ f(x)=frac{1}{1+e^{-x}} $
    它在两边的梯度很容易就成了0,导致了向底层传递的梯度也变得非常小。此时,网络参数很难得到有效训练。这种现象被称为梯度消失。一般来说, sigmoid 网络在 5 层之内就会产生梯度消失现象。

  2. tanh $ f(x)=frac{1-e^{-2x}}{1+e^{-2x}}$

  3. ReLU
    ReLU 能够在x>0时保持梯度不衰减,从而缓解梯度消失问题。这让我们能够直接以监督的方式训练深度神经网络,而无需依赖无监督的逐层预训练
    (f(x)= egin{cases} x, ;if xgeq 0\ 0, ;if x<0 end{cases}\ f(x)=max(0,x) )

损失函数

用来度量训练效果,主要有两类,一类是回归问题常用的平方差(C=frac{1}{2}(a-y)^2),另一类是交叉熵(实际分布与预估分布之间的差异度量)。

熵的计算公式是 (H(y)=-sum_i y_i log(y_i)),实际操作中,我们并不知道y的分布,只能对y的分布做一个估计,也就是算得的a值, 这样我们就能够得到用a来表示y的交叉熵 (H(y,a)=-sum_i y_i log(a_i))

交叉熵函数有个非常好的特质(H'=frac{1}{n}sum(a_n-y_n)=frac{1}{n}sum(sigma(z_n)-y_n))。其中没有了σ′这一项,这样一来也就不会受到饱和性的影响了。当误差大的时候,权重更新就快,当误差小的时候,权重的更新就慢。
[参考](http://blog.csdn.net/u014595019/article/details/52562159

参数初始化

为什么不全初始化为0?

因为如果所有的参数都是0,那么所有神经元的输出都将是相同的,那在back propagation的时候同一层内所有神经元的行为也是相同的 --- gradient相同,weight update也相同。这显然是一个不可接受的结果。

设想你在爬山,但身处直线形的山谷中,两边是对称的山峰。
由于对称性,你所在之处的梯度只能沿着山谷的方向,不会指向山峰;你走了一步之后,情况依然不变。
结果就是你只能收敛到山谷中的一个极大值,而走不到山峰上去。

一种常用方法

用1/sqrt(n)校准方差
考虑(z=w_1∗x_1+w_2∗x_2+...+w_n∗x_n),为了防止z太大或太小,可以看到n越大的话,你就希望w越小,以此来平衡z,那么很合理的设定就是把w设定为1/n。

所以在某一层,初始化权重的方法就是设定值为(sqrt{frac{1}{n^{[l-1]}}}),如下图所示,其中(n^{[l-1]})表示l层的输入特征数。如果你使用的是relu激活,那么用2 / n效果会更好。

保证了网络中所有的神经元最初的输出分布大致相同,并在经验上提高了收敛速度
ReLU

import numpy as np
W = np.random.randn(node_in, node_out) / np.sqrt(node_in / 2)

归一化输入

归一化输入需要两个步骤:零均值化和归一化方差。

零均值化:样本中的每个特征值都减去该特征 的平均值,这样每个特征的均值为0。

归一化方差:样本中每个的特征值除以该特征的方差,这样每个特征的方差为1。

为什么要归一化输入特征?

如下第1个图左侧所示,如果不归一化的话,代价函数可能是一个非常细长狭窄的函数,在训练的时候需要设置很小的步长,迭代时间会变长。

如下第1个图右侧所示,归一化后,各个特征都在相似范围内,代价函数更圆,更容易优化,梯度下降法能够使用较大的步长,更快速地迭代。

原文地址:https://www.cnblogs.com/pigbreeder/p/8053452.html