其他分享
首页 > 其他分享> > [C1W3] Neural Networks and Deep Learning - Shallow neural networks

[C1W3] Neural Networks and Deep Learning - Shallow neural networks

作者:互联网

第三周:浅层神经网络(Shallow neural networks)

神经网络概述(Neural Network Overview)

神经网络的表示(Neural Network Representation)

神经网络中,我们将使用上标方括号的形式表示这些值来自于哪一层,有趣的是在约定俗成的符号传统中,在这里你所看到的这个例子,只能叫做一个两层的神经网络。原因是输入层是不算入总层数内,所以隐藏层是第一层,输出层是第二层。第二个惯例是我们将输入层称为第零层,所以在技术上,这仍然是一个三层的神经网络,因为这里有输入层、隐藏层,还有输出层。但是在传统的符号使用中,如果你阅读研究论文或者在这门课中,你会看到人们将这个神经网络称为一个两层的神经网络,因为我们不将输入层看作一个标准的层。

计算一个神经网络的输出(Computing a Neural Network's output)

单个样本时,向量化图示

单个样本时,运用四行代码计算出一个简单神经网络的输出(预测)。

多样本向量化(Vectorizing across multiple examples)

上一节使用的是单个样本,如果把单个样本的向量横向堆叠成矩阵,就可以计算全部样本的神经网络输出(预测)。

向量化实现的解释(Justification for vectorized implementation)

激活函数(Activation functions)

Pros and cons of activation functions

结果表明,如果在隐藏层上使用 tanh (双曲正切)函数效果总是优于 sigmoid 函数。因为函数值域在 -1 和 +1 的激活函数,其均值是更接近 0 均值的,而不是0.5,这会使下一层学习简单一点。
在讨论优化算法时,有一点要说明:我基本已经不用 sigmoid 激活函数了,tanh 函数在所有场合都优于 sigmoid 函数。
但有一个例外:在二分类的问题中,对于输出层,想让的数值介于 0 和 1 之间,而不是在 -1 和 +1 之间,所以需要使用 sigmoid 激活函数。

sigmoid 函数和 tanh 函数两者共同的缺点是,在 \(Z\) 特别大或者特别小的情况下,导数的梯度或者函数的斜率会变得特别小,最后就会接近于0,导致降低梯度下降的速度。

在机器学习另一个很流行的函数是:修正线性单元的函数(ReLu)。只要 \(Z\) 是正值的情况下,导数恒等于1,当 \(Z\) 是负值的时候,导数恒等于 0。从实际上来说,当使用 \(Z\) 的导数时,\(Z=0\) 的导数是没有定义的。但是当编程实现的时候,\(Z\) 的取值刚好是 0.0000000000 的概率很低,所以不用担心这个。你也可以在 \(Z=0\) 时 ,给它的导数赋值 0 或 1 都可以。

这有一些选择激活函数的经验法则:

如果输出是0、1值(二分类问题),则输出层选择 sigmoid 函数,然后其它的所有单元都选择 Relu 函数。这是很多激活函数的默认选择,如果在隐藏层上不确定使用哪个激活函数,那么通常会使用 Relu 激活函数。有时,也会使用 tanh 激活函数,Relu 的一个缺点是:当 \(Z\) 是负值的时候,导数等于0,在实践中这没什么问题。

但 Relu 还有另外一个版本叫 Leaky Relu。当 \(Z\) 是负值时,这个函数的导数不是为 0,而是有一个平缓的斜率。这个函数通常比 Relu 激活函数效果要好,尽管在实际中 Leaky ReLu 使用的并不多。这些选一个就好了,我通常只用 Relu。

Relu 和 Leaky Relu 的好处在于,for a lot of the space of \(Z\),激活函数的导数和 0 差很远,所以在实践中使用 Relu 激活函数,你的神经网络学习速度通常会快很多。原因是 Relu 没有这种函数斜率接近 0 时,减慢学习速度的效应。我知道对于 \(Z\) 的一半范围来说,Relu 的斜率为 0,但在实践中,有足够多的隐藏单元令 \(Z\) 大于 0,所以对于大多数训练样本来说还是很快的。

在选择自己神经网络的激活函数时,有一定的直观感受,在深度学习中的经常遇到一个问题:在编写神经网络的时候,会有很多选择:隐藏层单元的个数、激活函数的选择、初始化权值……这些选择想得到一个对比较好的指导原则是挺困难的。

鉴于以上三个原因,以及在工业界的见闻,提供一种直观的感受,哪一种工业界用的多,哪一种用的少。但是,自己的神经网络的应用,以及其特殊性,是很难提前知道选择哪些效果更好。所以通常的建议是:如果不确定哪一个激活函数效果更好,可以把它们都试试,然后在交叉验证集或者在我们稍后会讲到的开发集上跑跑,看看哪一个表现好,就用哪个。在你的应用中自己多尝试下不同的选择,很可能你会搭建出具有前瞻性的神经网络架构,可以对你的问题的特质更有针对性,让你的算法迭代更流畅。这里不会告诉你一定要使用 Relu 激活函数,而不用其他的,这对你现在或未来要处理的问题而言,可能管用,也可能不管用。

为什么需要非线性激活函数?(why need a nonlinear activation function?)

如果你使用线性激活函数或者叫恒等激励函数,那么神经网络只是把输入线性组合再输出。

如果你使用线性激活函数或者没有使用一个激活函数,那么无论你的神经网络有多少层一直在做的只是计算线性函数,所以不如直接去掉全部隐藏层。

事实证明如果你在隐藏层用线性激活函数,在输出层用 sigmoid 函数,那么这个模型的复杂度和没有任何隐藏层的标准Logistic回归是一样的。

除非你引入非线性,否则你无法计算更有趣的函数,即使你的网络层数再多也不行;只有一个地方可以使用线性激活函数,就是你在做机器学习中的回归问题。举个例子,\(y\) 是一个实数,比如你想预测房地产价格, 就不是二分类任务 0 或 1,而是一个实数,从 0 到正无穷。如果 \(y\) 是个实数,那么在输出层用线性激活函数也许可行,你的输出 \(y\) 也是一个实数,从负无穷到正无穷。而且,此时隐藏层也不能用线性激活函数,可以用 ReLU 或者 tanh 或者 leaky ReLU 或者其他的非线性激活函数,唯一可以用线性激活函数的通常就是输出层;除了这种情况,会在隐层用线性函数的,还有一些特殊情况,比如与压缩有关的,不在这里深入讨论。另外,因为房价都是非负数,所以我们也可以在输出层使用 ReLU 函数,这样你的 \(\hat{y}\) 都大于等于 0。

激活函数的导数(Derivatives of activation functions)

sigmoid 导数为 \(a(1-a)\),当 a 已知的时候 ,可以很方便计算出其导数。

tanh 导数为 \(1-a^2\),当 a 已知的时候 ,可以很方便计算出其导数。

注:

神经网络的梯度下降(Gradient descent for neural networks)

这里 np.sum 是 python 的 numpy 命令,axis=1 表示水平相加求和,keepdims = True 是防止 python 输出秩为 1 的数组,如果不使用 keepdims,可以可以使用 reshape 显性指明数组的维度。

图中唯一的一个乘号是元素相乘。

以上就是正向传播的 4 个方程和反向传播的 6 个方程,这里我是直接给出的,在下一节,我会讲如何导出反向传播的这 6 个式子的。如果你要实现这些算法,你必须正确执行正向和反向传播运算,你必须能计算所有需要的导数,用梯度下降来学习神经网络的参数;

(选修)直观理解反向传播(Backpropagation intuition)

随机初始化(Random+Initialization)

如果把 \(W\) 全部初始化为 0,意味着每个隐藏层中所有激活单元的权重全部相同,输出也全部相同,当梯度下降算法计算出更新 \(W\) 的梯度之后,梯度也完全相同。如此的隐藏层毫无意义,无法自动的捕捉到一些有意思的特征,所以在初始化 \(W\) 的时候需要打破这种对称性(symmetry breaking problem),令外 \(b\) 在初始化时可以全部初始化为 0,因为 \(W\) 已经打破对称,整个激活单元数出也就打破对称了。

如何初始化?

  1. 在吴恩达老师机器学习课程中,初始化神经网络参数的方法是让 \(W\) 为一个在 \([-\epsilon, \epsilon]\) 之间的随机数。
    epsilon_init = 0.12;
    np.random.rand(\(s_l\), \(s_{l-1}\)) * 2 * epsilon_init - epsilon_init

  2. 在吴恩达老师本门课程(深度学习)中,使用如下方法:
    \(W^{[1]}\)=np.random.randn(\(s_l\), \(s_{l-1})\) * 0.01 (生成高斯分布)
    \(b^{[1]}\) = np.zeros((\(s_l\), 1))
    之所以 * 0.01,而不是 100 或 1000 ...是因为通常我们倾向于将 \(W\) 初始化为一个很小的随机数。试想,如果 \(W\) 很大, 导致 \(Z\) 过大或过小都会令 tanh 或者 sigmoid 激活函数的梯度处于平坦接近 0 的地方,从而导致龟速梯度下降。如果没有 sigmoid / tanh 激活函数在整个的神经网络里,就不成问题。但如果你做二分类并且你的输出单元是 Sigmoid 函数,那么你是不会希望初始参数太大的,所以乘上 0.01 或者其他一些很小的数都是合理的尝试。事实上有时候也有比 0.01 更好的常数,当你训练一个只有一层隐藏层的网络时(这是相对浅的神经网络,没有太多的隐藏层),设为 0.01 或许还可以。但当你训练一个非常非常深的神经网络时,可能需要试试 0.01 以外的常数。下面课程中我们会讨论 how & when 去选择一个不同于 0.01 的常数,但是无论如何它通常都会是个相对很小的数。

标签:函数,导数,Neural,C1W3,Shallow,shape,Relu,神经网络,激活
来源: https://www.cnblogs.com/keyshaw/p/11160359.html