赞
踩
本文是吴恩达老师的深度学习课程[1]笔记部分。
作者:黄海广[2]
主要编写人员:黄海广、林兴木(第四所有底稿,第五课第一二周,第三周前三节)、祝彦森:(第三课所有底稿)、贺志尧(第五课第三周底稿)、王翔、胡瀚文、 余笑、 郑浩、李怀松、 朱越鹏、陈伟贺、 曹越、 路皓翔、邱牧宸、 唐天泽、 张浩、 陈志豪、 游忍、 泽霖、沈伟臣、 贾红顺、 时超、 陈哲、赵一帆、 胡潇杨、段希、于冲、张鑫倩
参与编辑人员:黄海广、陈康凯、石晴路、钟博彦、向伟、严凤龙、刘成 、贺志尧、段希、陈瑶、林家泳、王翔、 谢士晨、蒋鹏
备注:笔记和作业(含数据、原始作业文件)、视频都在 github[3]中下载。
我将陆续将课程笔记发布在公众号“机器学习初学者”,敬请关注。
本周你将学习如何实现一个神经网络。在我们深入学习具体技术之前,我希望快速的带你预览一下本周你将会学到的东西。如果这个视频中的某些细节你没有看懂你也不用担心,我们将在后面的几个视频中深入讨论技术细节。
现在我们开始快速浏览一下如何实现神经网络。上周我们讨论了逻辑回归,我们了解了这个模型(见图 3.1.1)如何与下面公式 3.1 建立联系。图 3.1.1 :
公式 3.1:
如上所示,首先你需要输入特征
接下来使用
神经网络看起来是如下这个样子(图 3.1.2)。正如我之前已经提到过,你可以把许多sigmoid单元堆叠起来形成一个神经网络。对于图 3.1.1 中的节点,它包含了之前讲的计算的两个步骤:首先通过公式 3.1 计算出值
图 3.1.2
在这个神经网络(图 3.1.2)对应的 3 个节点,首先计算第一层网络中的各个节点相关的数
公式 3.3:
公式 3.4:
类似逻辑回归,在计算后需要使用计算,接下来你需要使用另外一个线性方程对应的参数计算
公式 3.5:
我知道这其中有很多细节,其中有一点非常难以理解,即在逻辑回归中,通过直接计算
你应该记得逻辑回归中,有一些从后向前的计算用来计算导数
现在你大概了解了一下什么是神经网络,基于逻辑回归重复使用了两次该模型得到上述例子的神经网络。我清楚这里面多了很多新符号和细节,如果没有理解也不用担心,在接下来的视频中我们会仔细讨论具体细节。
那么,下一个视频讲述神经网络的表示。
先回顾一下我在上一个视频画几张神经网络的图片,在这次课中我们将讨论这些图片的具体含义,也就是我们画的这些神经网络到底代表什么。
我们首先关注一个例子,本例中的神经网络只包含一个隐藏层(图 3.2.1)。这是一张神经网络的图片,让我们给此图的不同部分取一些名字。
图 3.2.1
我们有输入特征
现在我们再引入几个符号,就像我们之前用向量
最后输出层将产生某个数值
图 3.2.2
最后,我们要看到的隐藏层以及最后的输出层是带有参数的,这里的隐藏层将拥有两个参数
在下一个视频中。我们将更深入地了解这个神经网络是如何进行计算的,也就是这个神经网络是怎么输入
在上一节的视频中,我们介绍只有一个隐藏层的神经网络的结构与符号表示。在这节的视频中让我们了解神经网络的输出究竟是如何计算出来的。
首先,回顾下只有一个隐藏层的简单两层神经网络结构:
图 3.3.1
其中,
神经网络的计算
关于神经网络是怎么计算的,从我们之前提及的逻辑回归开始,如下图所示。用圆圈表示神经网络的计算单元,逻辑回归的计算有两个步骤,首先你按步骤计算出
图 3.3.2
回到两层的神经网络,我们从隐藏层的第一个神经元开始计算,如上图第一个最上面的箭头所指。从上图可以看出,输入与逻辑回归相似,这个神经元的计算与逻辑回归一样分为两步,小圆圈代表了计算的两个步骤。
第一步,计算
第二步,通过激活函数计算
隐藏层的第二个以及后面两个神经元的计算过程一样,只是注意符号表示不同,最终分别得到
向量化计算如果你执行神经网络的程序,用 for 循环来做这些看起来真的很低效。所以接下来我们要做的就是把这四个等式向量化。向量化的过程是将神经网络中的一层神经元参数纵向堆积起来,例如隐藏层中的
公式 3.9:
详细过程见下: 公式 3.10:
公式 3.11:
对于神经网络的第一层,给予一个输入
图 3.3.3
如上图左半部分所示为神经网络,把网络左边部分盖住先忽略,那么最后的输出单元就相当于一个逻辑回归的计算单元。当你有一个包含一层隐藏层的神经网络,你需要去实现以计算得到输出的是右边的四个等式,并且可以看成是一个向量化的计算过程,计算出隐藏层的四个逻辑回归单元和整个隐藏层的输出结果,如果编程实现需要的也只是这四行代码。
总结通过本视频,你能够根据给出的一个单独的输入特征向量,运用四行代码计算出一个简单神经网络的输出。接下来你将了解的是如何一次能够计算出不止一个样本的神经网络输出,而是能一次性计算整个训练集的输出。
在上一个视频,了解到如何针对于单一的训练样本,在神经网络上计算出预测值。
在这个视频,将会了解到如何向量化多个训练样本,并计算出结果。该过程与你在逻辑回归中所做类似。
逻辑回归是将各个训练样本组合成矩阵,对矩阵的各列进行计算。神经网络是通过对逻辑回归中的等式简单的变形,让神经网络计算出输出值。这种计算是所有的训练样本同时进行的,以下是实现它具体的步骤:
图 3.4.1
上一节视频中得到的四个等式。它们给出如何计算出
对于一个给定的输入特征向量
用第一个训练样本
然后,用
用激活函数表示法,如上图左下所示,它写成
【注】:
如果有一个非向量化形式的实现,而且要计算出它的预测值,对于所有训练样本,需要让
对于上面的这个方程中的
本课程需要使用很多线性代数的内容,重要的是能够正确地实现这一点,尤其是在深度学习的错误中。实际上本课程认真地选择了运算符号,这些符号只是针对于这个课程的,并且能使这些向量化容易一些。
所以,希望通过这个细节可以更快地正确实现这些算法。接下来讲讲如何向量化这些: 公式3.12:
公式3.13:
公式3.14:
公式3.15:
前一张幻灯片中的for循环是来遍历所有个训练样本。 定义矩阵
以此类推,从小写的向量
同理,
同理,
同样的,对于
这种符号其中一个作用就是,可以通过训练样本来进行索引。这就是水平索引对应于不同的训练样本的原因,这些训练样本是从左到右扫描训练集而得到的。
在垂直方向,这个垂直索引对应于神经网络中的不同节点。例如,这个节点,该值位于矩阵的最左上角对应于激活单元,它是位于第一个训练样本上的第一个隐藏单元。它的下一个值对应于第二个隐藏单元的激活值。它是位于第一个训练样本上的,以及第一个训练示例中第三个隐藏单元,等等。
当垂直扫描,是索引到隐藏单位的数字。当水平扫描,将从第一个训练示例中从第一个隐藏的单元到第二个训练样本,第三个训练样本……直到节点对应于第一个隐藏单元的激活值,且这个隐藏单元是位于这
从水平上看,矩阵
对于矩阵
神经网络上通过在多样本情况下的向量化来使用这些等式。
在下一个视频中,将证明为什么这是一种正确向量化的实现。这种证明将会与逻辑回归中的证明类似。
在上一个视频中,我们学习到如何将多个训练样本横向堆叠成一个矩阵
在这个视频中,我们将会继续了解到,为什么上一节中写下的公式就是将多个样本向量化的正确实现。
我们先手动对几个样本计算一下前向传播,看看有什么规律: 公式3.16:
这里,为了描述的简便,我们先忽略掉
现在
视频中,吴恩达老师很细心的用不同的颜色表示不同的样本向量,及其对应的输出。所以从图中可以看出,当加入更多样本时,只需向矩阵
所以从这里我们也可以了解到,为什么之前我们对单个样本的计算要写成
最后,对这一段视频的内容做一个总结:
由公式3.12、公式3.13、公式3.14、公式3.15可以看出,使用向量化的方法,可以不需要显示循环,而直接通过矩阵运算从
以上就是对神经网络向量化实现的正确性的解释,到目前为止,我们仅使用sigmoid函数作为激活函数,事实上这并非最好的选择,在下一个视频中,将会继续深入的讲解如何使用更多不同种类的激活函数。
使用一个神经网络时,需要决定使用哪种激活函数用隐藏层上,哪种用在输出节点上。到目前为止,之前的视频只用过sigmoid激活函数,但是,有时其他的激活函数效果会更好。
在神经网路的前向传播中,的
更通常的情况下,使用不同的函数
如图,
事实上,tanh函数是sigmoid的向下平移和伸缩后的结果。对它进行了变形后,穿过了
结果表明,如果在隐藏层上使用函数 公式3.20:
这会使下一层学习简单一点,在第二门课中会详细讲解。
在讨论优化算法时,有一点要说明:我基本已经不用sigmoid激活函数了,tanh函数在所有场合都优于sigmoid函数。
但有一个例外:在二分类的问题中,对于输出层,因为
所以,在不同的神经网络层中,激活函数可以不同。为了表示不同的激活函数,在不同的层中,使用方括号上标来指出
sigmoid函数和tanh函数两者共同的缺点是,在
在机器学习另一个很流行的函数是:修正线性单元的函数(ReLu),ReLu函数图像是如下图。 公式3.22:
这有一些选择激活函数的经验法则:
如果输出是0、1值(二分类问题),则输出层选择sigmoid函数,然后其它的所有单元都选择Relu函数。
这是很多激活函数的默认选择,如果在隐藏层上不确定使用哪个激活函数,那么通常会使用Relu激活函数。有时,也会使用tanh激活函数,但Relu的一个优点是:当
这里也有另一个版本的Relu被称为Leaky Relu。
当
这个函数通常比Relu激活函数效果要好,尽管在实际中Leaky ReLu使用的并不多。
图3.6.1
两者的优点是:
第一,在
第二,sigmoid和tanh函数的导数在正负饱和区的梯度都会接近于0,这会造成梯度弥散,而Relu和Leaky ReLu函数大于0部分都为常数,不会产生梯度弥散现象。(同时应该注意到的是,Relu进入负半区的时候,梯度为0,神经元此时不会训练,产生所谓的稀疏性,而Leaky ReLu不会有这问题)
快速概括一下不同激活函数的过程和结论。
sigmoid激活函数:除了输出层是一个二分类问题基本不会用它。
tanh激活函数:tanh是非常优秀的,几乎适合所有场合。
ReLu激活函数:最常用的默认函数,,如果不确定用哪个激活函数,就使用ReLu或者Leaky ReLu。公式3.23:
在选择自己神经网络的激活函数时,有一定的直观感受,在深度学习中的经常遇到一个问题:在编写神经网络的时候,会有很多选择:隐藏层单元的个数、激活函数的选择、初始化权值……这些选择想得到一个对比较好的指导原则是挺困难的。
鉴于以上三个原因,以及在工业界的见闻,提供一种直观的感受,哪一种工业界用的多,哪一种用的少。但是,自己的神经网络的应用,以及其特殊性,是很难提前知道选择哪些效果更好。所以通常的建议是:如果不确定哪一个激活函数效果更好,可以把它们都试试,然后在验证集或者发展集上进行评价。然后看哪一种表现的更好,就去使用它。
为自己的神经网络的应用测试这些不同的选择,会在以后检验自己的神经网络或者评估算法的时候,看到不同的效果。如果仅仅遵守使用默认的ReLu激活函数,而不要用其他的激励函数,那就可能在近期或者往后,每次解决问题的时候都使用相同的办法。
为什么神经网络需要非线性激活函数?事实证明:要让你的神经网络能够计算出有趣的函数,你必须使用非线性激活函数,证明如下:
这是神经网络正向传播的方程,现在我们去掉函数
如果我们改变前面的式子,令:
(1)
(2)
(3) 简化多项式得
如果你是用线性激活函数或者叫恒等激励函数,那么神经网络只是把输入线性组合再输出。
我们稍后会谈到深度网络,有很多层的神经网络,很多隐藏层。事实证明,如果你使用线性激活函数或者没有使用一个激活函数,那么无论你的神经网络有多少层一直在做的只是计算线性函数,所以不如直接去掉全部隐藏层。在我们的简明案例中,事实证明如果你在隐藏层用线性激活函数,在输出层用sigmoid函数,那么这个模型的复杂度和没有任何隐藏层的标准Logistic回归是一样的,如果你愿意的话,可以证明一下。
在这里线性隐层一点用也没有,因为这两个线性函数的组合本身就是线性函数,所以除非你引入非线性,否则你无法计算更有趣的函数,即使你的网络层数再多也不行;只有一个地方可以使用线性激活函数------
总而言之,不能在隐藏层用线性激活函数,可以用ReLU或者tanh或者leaky ReLU或者其他的非线性激活函数,唯一可以用线性激活函数的通常就是输出层;除了这种情况,会在隐层用线性函数的,除了一些特殊情况,比如与压缩有关的,那方面在这里将不深入讨论。在这之外,在隐层使用线性激活函数非常少见。因为房价都是非负数,所以我们也可以在输出层使用ReLU函数这样你的
理解为什么使用非线性激活函数对于神经网络十分关键,接下来我们讨论梯度下降,并在下一个视频中开始讨论梯度下降的基础——激活函数的导数。
在神经网络中使用反向传播的时候,你真的需要计算激活函数的斜率或者导数。针对以下四种激活,求其导数如下:
1)sigmoid activation function
图3.8.1
其具体的求导如下: 公式3.25:
注:
当
当
在神经网络中
Tanh activation function
图3.8.2
其具体的求导如下: 公式3.26:
公式3.27:
当
当
在神经网络中;
3)Rectified Linear Unit (ReLU)
注:通常在
4)Leaky linear unit (Leaky ReLU)
与ReLU类似
注:通常在
在这个视频中,我会给你实现反向传播或者说梯度下降算法的方程组,在下一个视频我们会介绍为什么这几个特定的方程是针对你的神经网络实现梯度下降的正确方程。
你的单隐层神经网络会有
在我们的例子中,我们只介绍过的这种情况,那么参数:
矩阵
你还有一个神经网络的成本函数,假设你在做二分类任务,那么你的成本函数等于:
Cost function: 公式: loss function和之前做logistic回归完全一样。
训练参数需要做梯度下降,在训练神经网络的时候,随机初始化参数很重要,而不是初始化成全零。当你参数初始化成某些值后,每次梯度下降都会循环计算以下预测值:
公式3.29:
其中
公式3.30:
公式3.31:
正向传播方程如下(之前讲过):
forward propagation:
(1)
(2)
(3)
(4)
反向传播方程如下:
back propagation:
公式3.32:
公式3.33:
公式3.34:
公式3.35: 公式3.36:
公式3.37:
上述是反向传播的步骤,注:这些都是针对所有样本进行过向量化,
np.sum
是python的numpy命令,axis=1
表示水平相加求和,keepdims
是防止python输出那些古怪的秩数
目前为止,我们计算的都和Logistic回归十分相似,但当你开始计算反向传播时,你需要计算,是隐藏层函数的导数,输出在使用sigmoid函数进行二元分类。这里是进行逐个元素乘积,因为
还有一种防止python输出奇怪的秩数,需要显式地调用reshape
把np.sum
输出结果写成矩阵形式。
以上就是正向传播的4个方程和反向传播的6个方程,这里我是直接给出的,在下个视频中,我会讲如何导出反向传播的这6个式子的。如果你要实现这些算法,你必须正确执行正向和反向传播运算,你必须能计算所有需要的导数,用梯度下降来学习神经网络的参数;你也可以许多成功的深度学习从业者一样直接实现这个算法,不去了解其中的知识。
这个视频主要是推导反向传播。
下图是逻辑回归的推导:
回想一下逻辑回归的公式(参考公式3.2、公式3.5、公式3.6、公式3.15)
公式3.38:
所以回想当时我们讨论逻辑回归的时候,我们有这个正向传播步骤,其中我们计算
公式3.39:
神经网络的计算中,与逻辑回归十分类似,但中间会有多层的计算。下图是一个双层神经网络,有一个输入层,一个隐藏层和一个输出层。
前向传播:
计算
反向传播:
向后推算出
公式3.40: (注意:逻辑回归中;为什么
公式3.41:
证明过程: 见公式3.42,其中
实现后向传播有个技巧,就是要保证矩阵的维度相互匹配。最后得到
公式3.43:
可以看出
由:
注意:大写的
下图写了主要的推导过程:
公式3.44:
公式3.45:
公式3.46:
公式3.47:
公式3.48:
公式3.49:
吴恩达老师认为反向传播的推导是机器学习领域最难的数学推导之一,矩阵的导数要用链式法则来求,如果这章内容掌握不了也没大的关系,只要有这种直觉就可以了。还有一点,就是初始化你的神经网络的权重,不要都是0,而是随机初始化,下一章将详细介绍原因。
当你训练神经网络时,权重随机初始化是很重要的。对于逻辑回归,把权重初始化为0当然也是可以的。但是对于一个神经网络,如果你把权重或者参数都初始化为0,那么梯度下降将不会起作用。
让我们看看这是为什么。有两个输入特征,
因此与一个隐藏层相关的矩阵,或者说
但是如果你这样初始化这个神经网络,那么这两个隐含单元就会完全一样,因此他们完全对称,也就意味着计算同样的函数,并且肯定的是最终经过每次训练的迭代,这两个隐含单元仍然是同一个函数,令人困惑。
由此可以推导,如果你把权重都初始化为0,那么由于隐含单元开始计算同一个函数,所有的隐含单元就会对输出单元有同样的影响。一次迭代后同样的表达式结果仍然是相同的,即隐含单元仍是对称的。通过推导,两次、三次、无论多少次迭代,不管你训练网络多长时间,隐含单元仍然计算的是同样的函数。因此这种情况下超过1个隐含单元也没什么意义,因为他们计算同样的东西。当然更大的网络,比如你有3个特征,还有相当多的隐含单元。
如果你要初始化成0,由于所有的隐含单元都是对称的,无论你运行梯度下降多久,他们一直计算同样的函数。这没有任何帮助,因为你想要两个不同的隐含单元计算不同的函数,这个问题的解决方法就是随机初始化参数。你应该这么做:把
np.random.randn(2,2)
(生成高斯分布),通常再乘上一个小的数,比如0.01,这样把它初始化为很小的随机数。然后
你也许会疑惑,这个常数从哪里来,为什么是0.01,而不是100或者1000。我们通常倾向于初始化为很小的随机数。因为如果你用tanh或者sigmoid激活函数,或者说只在输出层有一个Sigmoid,如果(数值)波动太大,当你计算激活值时如果
回顾一下:如果
np.random.randn((1,2))
,我猜会是乘以0.01。
事实上有时有比0.01更好的常数,当你训练一个只有一层隐藏层的网络时(这是相对浅的神经网络,没有太多的隐藏层),设为0.01可能也可以。但当你训练一个非常非常深的神经网络,你可能要试试0.01以外的常数。下一节课我们会讨论怎么并且何时去选择一个不同于0.01的常数,但是无论如何它通常都会是个相对小的数。
好了,这就是这周的视频。你现在已经知道如何建立一个一层的神经网络了,初始化参数,用前向传播预测,还有计算导数,结合反向传播用在梯度下降中。
[1]
深度学习课程: https://mooc.study.163.com/university/deeplearning_ai
[2]黄海广: https://github.com/fengdu78
[3]github: https://github.com/fengdu78/deeplearning_ai_books
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。