目录
神经网络概述
神经网络的表示
计算一个神经网络的输出
多样本向量化
向量化实现的解释
激活函数
为什么需要非线性激活函数
激活函数的导数
神经网络的梯度下降
直观理解反向传播
随机初始化
【此为本人学习吴恩达的深度学习课程的笔记记录,有错误请指出!】
神经网络看起来如下这个样子,也就是把许多sigmoid 单元堆叠起来形成一个神经网络:
整个计算过程如下:
第一层前向传播:
第一层反向传播:
第二层反向传播:
本例中的神经网络只包含一个隐藏层:
神经网络的符号定义:
隐藏层的计算输出过程:
隐藏层的输出的详细结果如下:
向量化计算:
一个完整的神经网络的计算输出过程:
以上是一个样本的神经网络的输出预测值的过程。
对于多个训练样本,需要标明训练样本的标号。
【注】: :() 指第 个训练样本,[2] 是指第二层。
对于所有训练样本,需要让 从 1 到 实现这四个等式:
向量化的细节:
样本的向量化:
的向量化:
输出 的向量化:
简化公式(从向量到矩阵):
[1] 是一个矩阵, (1), (2), (3)都是列向量,矩阵乘以列向量得到列向量,下面用图形直观的表示出来:
使用向量化的方法,可以不需要显示循环。
神经网络中的每一层都重复着相似的计算。
使用一个神经网络时,需要决定使用哪种激活函数用隐藏层上,哪种用在输出节点上。
sigmoid 函数(值域为 0 和 1 之间):
tanh 函数或者双曲正切函数(值域是位于 +1 和 -1 之间,总体上优于 sigmoid 函数):
因为该激活函数值域在-1 和+1,其均值是更接近零均值。在训练一个算法模型时,如果使用 tanh 函数代替 sigmoid 函数中心化数据,使得数据的平均值更接近 0 而不是 0.5。
sigmoid 函数和 tanh 函数两者共同的缺点是,在 特别大或者特别小的情况下,导数的梯度或者函数的斜率会变得特别小,最后就会接近于 0,导致降低梯度下降的速度。
ReLu 函数或修正线性单元的函数( 当是正值时,导数恒等于 1,当是负值时,导数恒等于 0):
Leaky Relu(另一个版本的 Relu, 当是负值时,这个函数的值不是等于 0,而是轻微的倾斜):
如图:
Relu和Leaky Relu两者优点:
第一,在 的区间变动很大的情况下,激活函数的导数或者激活函数的斜率都会远大于0,在程序实现就是一个 if-else 语句,而 sigmoid 函数需要进行浮点四则运算,在实践中,使用 ReLu 激活函数神经网络通常会比使用 sigmoid 或者 tanh激活函数学习的更快。
第二, sigmoid 和 tanh 函数的导数在正负饱和区的梯度都会接近于 0,这会造成梯度弥散,而 Relu 和 Leaky ReLu 函数大于 0 部分都为常数,不会产生梯度弥散现象。 (同时应该注意到的是, Relu 进入负半区的时候,梯度为 0,神经元此时不会训练,产生所谓的稀疏性,而 Leaky ReLu 不会有这问题)。
概括一下不同激活函数的过程和结论:
sigmoid 激活函数:除了输出层是一个二分类问题基本不会用它。
tanh 激活函数: tanh 是非常优秀的,几乎适合所有场合。
ReLu 激活函数:最常用的默认函数,如果不确定用哪个激活函数,就使用 ReLu 或者 Leaky ReLu。
如果不确定哪一个激活函数效果更好,可以把它们都试试,然后在验证集或者发展集上进行评价。然后看哪一种表现的更好,就去使用它。
如果用线性激活函数或者叫恒等激励函数,那么神经网络只是把输入线性组合再输出。 那么无论神经网络有多少层,一直在做的只是计算线性函数,所以不如直接去掉全部隐藏层。
如果你在隐藏层用线性激活函数,在输出层用 sigmoid 函数,那么这个模型的复杂度和没有任何隐藏层的标准 Logistic 回归是一样的,如果你愿意的话,可以证明一下。
在这里线性隐层一点用也没有,因为这两个线性函数的组合本身就是线性函数,所以除非你引入非线性,否则你无法计算更有趣的函数。
总而言之,不能在隐藏层用线性激活函数,可以用 ReLU 或者 tanh 或者 leaky ReLU 或者其他的非线性激活函数,唯一可以用线性激活函数的通常就是输出层。
在神经网络中使用反向传播的时候,需要计算激活函数的斜率或者导数。针对以下四种激活,求其导数如下:
1) sigmoid activation function
求导如下:
注:
在神经网络中:
2) Tanh activation function
求导如下:
3) Rectified Linear Unit (ReLU)
求导如下:
注:通常在 = 0 的时候给定其导数 1 或 0,当然=0 的情况很少。
4) Leaky linear unit (Leaky ReLU)
求导如下:
注:通常在 = 0 的时候给定其导数 1 或 0.01,当然 = 0的情况很少
正向传播方程如下:
反向传播方程如下:
以上就是正向传播的 4 个方程和反向传播的 6 个方程。
神经网络的计算与逻辑回归十分类似,但中间会有多层的计算。
前向传播:
计算[1], [1],再计算[2], [2],最后得到 loss function 。
反向传播
向后推算出[2],然后推算出[2],接着推算出[1],然后推算出[1] 。
当训练神经网络时,权重随机初始化是很重要的。
对于逻辑回归,把权重初始化为 0 当然也是可以的(只有一个计算单元)。但是对于一个神经网络,如果你把权重或者参数都初始化为 0,那么梯度下降将不会起作用(同一层的计算单元计算效果都一样)。
如图(初始化权重或参数为 0):
初始化权重或参数为 0,导致相同的隐藏层的计算单元的输出结果一样、导数的结果一样、更新后的权重或参数也一样。
因此这种情况下,相同的隐藏层有多个计算单元和只有一个计算单元的效果是一样的,这对神经网络的学习没有任何帮助。
如果一次迭代后同样的表达式结果仍然是相同的,即隐含单元是对称的。
是对称的(不能初始化为 0), 不是对称的(可以初始化为 0)。
解决方法就是随机初始化参数 。
因此只要随机初始化 就有不同的隐含单元计算不同的东西,就不会有 symmetry breaking 问题。
如上面的例子:
把 [1] 设为 np.random.randn(2,2) (生成高斯分布),通常再乘上一个小的数,比如 0.01,这样把它初始化为很小的随机数:
[1] = . . (2,2) ∗ 0.01 ,
[1] = . ((2,1))
[2] = . . (1,2) ∗ 0.01 ,
[2] = 0
这个常数从哪里来,为什么是 0.01,而不是 100 或者 1000,通常倾向于初始化为很小的随机数。
如果初始化 很大, 就会很大(甚至在训练刚刚开始的时候), 这种情况下很可能停在 tanh/sigmoid 函数的平坦的地方,这些地方梯度很小也就意味着梯度下降会很慢,因此学习也就很慢。如果神经网络中没有 sigmoid/tanh 激活函数,就不成问题。但如果做二分类并且输出单元是 Sigmoid 函数,那么你不会想让初始参数太大,因此这就是为什么乘上 0.01或者其它一些小数是合理的尝试。