吴恩达深度学习

第一课:欢迎

1.神经网络基础
2.构建神经网络
3.构建机器学习工程
4.卷及神经网络CNN
5.序列模型

深度学习介绍

什么是神经网络?

ReLU函数:线性整流函数

通过堆叠一些单一神经元,以及堆叠简单预测期,我们可以得到一个稍微大些的神经网络。

你如何管理神经网络呢?

你有一个有四个输入的神经网络,所以输入特征可能是房屋大小、卧室数量、邮政编码以及居住地的富裕程度。给定这些输入特征,神经网络的工作就是预测价格y,每个小圆圈都叫做神经网络中的隐藏神经元,其中每个神经元都将所有的四个特征当作输入(即使它只与两个输入特征相关,让神经网络自己来决定这些网络节点是什么)。

神经网络最重要的一点是只要给定足够多的训练示例x和y,神经网络就能很好地拟合出一个函数来建立x和y之间的映射关系。

实际上,当你建立了自己的神经网络系统以后,你可能发现它们在监督学习中是最有用、最强大的(所谓监督学习,就是需要把一个输入x和一个输出y相对应起来)。

第四课:用神经网络进行监督学习

在监督学习中,那你有一个输入特征x,并且你想通过x学习到一个函数,这个函数能够将x映射到输出y。

很多有价值的发明都是神经网络在特定问题下来巧妙地建立x对应y的函数映射关系,并且通过监督学习拟合数据,成为某个复杂系统的一部分。

事实证明(结构)稍有不同的神经网络在不同的应用领域都非常的有用。

结构化数据和非结构化数据:
结构化数据是基于数据库的数据,每一种特征都有明确的意义。
非结构化数据是类似于原始音频、照片或者文本,这里特征也许是图片中的像素值或一段文本中的独立单词。
历史上对非结构化数据的学习要比对结构化数据困难的多。

但由于人类可以很好地解释这种非结构化的数据,在神经网络崛起后,最令人兴奋的事情之一就是它带来的深度学习使得计算机能够比前些年更好地解释非结构化数据。语音识别、图像识别,在文本上的自然语言处理技术。但短期,神经网络带来的价值还是集中体现在结构化数据上。在海量的数据库上有更好的处理数据的能力。

神经网络已经变革了监督学习的方式,并且正在创造出巨大的经济价值,神经网络背后的基础原理也发展了十几年,为什么精神网络直到现在表现得如此之好?

第五课:为什么深度学习会起飞?

为什么深度学习和神经网络最近才风靡起来?

事实上今天要想达到高性能的最可靠的方法之一,要么是训练一个大网络,要么放更多的数据。

不同算法的性能的排名是不固定的,更多的是由你提取特征的能力和算法的细节决定的。只有在很大的数据集的区域里,我们经常看到很大的神经网络超过了其它方法。

大数据

计算能力的大幅度上升(深度学习硬件的发展:GPU、高速网络或其他硬件)

算法的更新:
signmoid函数到ReLu函数的转换,增快学习速度(添加修正线性单元)。

其次你训练一个神经网络的过程是一个循环,你有一个网络架构的想法,你去用代码实现,之后让你的实验结果告诉你你的网络表现得怎么样,这样就可以回过头去修改网络里面的细节,然后重复这个循环。

这些都是使得深度学习不断发展的动力。

第六课:二元分类

编程技巧:
比如你有一个含有m个训样本的训练集,你可能用关于用一个for循环来处理这m个训练样本。但当你用神经网络的时候,你一般想训练整个训练集,但不显式使用for循环来遍历整个训练集。

为什么计算可以被正向转播组织为一次前向传播过程以及一次反向传播过程?

逻辑回归是一个二元分类算法。

一张图像中包含像素数表示输入特征向量x的维度,在二元分类问题中,我们的目标是学习到这样一个分类器:

我们输入一幅以特征向量x表示的图像,然后预测对应的输出y是1还是0,

如何组织训练样本的输入x到矩阵X:
如何组织输出标签Y:
得到一个X是一个n(x)乘m维的矩阵;Y是一个1xm大小的矩阵

以上就是我们之后在回归算法和神经网络计算中使用到的一些符号,如果你忘记了某个符号的意义,可以查找符号指南。

接下来着手实现逻辑回归算法。

第七课:逻辑回归

本节课:我们复习一下逻辑回归
使用这种学习算法会得到的输出标签y,y在监督学习问题中全是0或者1,因此这是一种针对二元分类的算法。

给定的输入特征向量x和一副图片对应,我们希望它输出一个y值,与是不是猫对应,我们称之为y帽(代表对真实标签y的估计)。

输入x的一个线性函数输出:
我们希望y输出是一个0到1的数字,但是因为w.T*x + b可能会得到比1大很多或者是一个负数,这对于概率就失去了意义。

所以要让逻辑回归变成等于对这个值应用sigmoid函数的结果:

因此,当你使用逻辑回归时,你的目标是尽力学到参数w和b。因此yhat就能很好地估计y等于1的概率。

此外,当运用神经网络进行编程时,我们通常会将参数w和参数b分开看待,这里的b对应一个偏置量。

当实现神经网路时,将b和w当做相互独立的参数会更加简单。

接下来为了改变参数w和b,需要定义一个代价函数。

第八课:逻辑回归代价函数

为了优化逻辑回归模型的参数W和b,我们需要定义一个代价函数。

目的是在获得优化集合和输出值时,对于优化集合的假定,我们只提出y(i)将接近从优化集合中获得的实标yi。

标记法则:上标括号指的是数据;X Y Z以及其他字母与优化示例相关联

函数L被称为损失函数,需要进行设定,才能在实标为y时对输出值y^进行检测。

为什么要使用平方:
因为如果使用一个或者半个差值,优化问题会产生多个局部最优解,梯度下降算法也无法找到全局最优解。平方误差会产生一个非凸函数,这将使之后的优化变得更容易。

目前有很多函数有拉裴拉效应,也就是如果y等于1,y^ 值要变大;如果y等于0,y^值要变小。

这就解释了为什么在逻辑回归中,这个特定函数更适用。

最后这个损失函数被单一的优化示例所定义,它被检测单一优化示例的运行情况。接下来定义代价函数,来检测优化组的整体运行情况。

即损失函数适用于像这样单一的优化示例,损失函数反应的是你的参数成本。所以在你优化你的逻辑回归模型时,我们要试着去找参数W和b,一次来缩小J的整体成本。

设置逻辑回归算法优化示例的损失函数以及算法参数的总体损失函数。逻辑回归可被视为一个非常小的神经网络。

损失函数计算单个训练示例的误差; 代价函数是整个训练集的成本函数的平均值。

第九课:梯度下降

用损失函数界定你的模型对单一样本的训练效果,对每一个训练样例都输出y^(i)。代价函数可以用来衡量参数w和b在你设计的整个模型中的作用效果。

如何是用梯度下降模型去训练或者去学习,来调整你的训练集中的参数w和b?

所以代价函数可以用来衡量参数w和b在训练集上的效果,要使得参数w和b设置变得合理,自然地想到去找到使得代价函数J(w,b)尽可能小所对应的w和b。

定义w和b都是单一实数。代价函数J是一个凸函数。为了找到最小值,我们将会使用一些初始值来初始化w和b。对于逻辑回归几乎所有的初始化方法都有效。通常用0来初始化,随机初始化也有效,但对于逻辑回归我们通常不这么做。

细节(对w和b进行不断迭代更新):

第十课:导数

更直观的理解微积分和导数

第十一课:导数二

函数的斜率在这个函数的不同地方取值不同。

函数的导数就是函数的斜率,函数的斜率在函数的不同位置取值可能不同
如果你想要找一个函数的导数,你可以打开微积分教材或者谷歌搜索

第十二课:流程图

你已经学过神经网络的计算过程,由正向传播来进行前向计算来计算神经网络的输出,以及反向传播计算来计算梯度或微分。计算图解释了为什么以这种方式来组织?

以一个简单的逻辑回归或单层神经网络为例:

当有一些特殊的输出变量时,流程图用起来很方便。

反向计算就是计算导数最自然的方式。

流程图使用蓝色箭头画出来的,从左向右的计算。

反向红色箭头,从右到左的导数计算是什么样的呢?

第十三课:用流程图求导

我们看了一个使用流程图计算函数J的例子。如何利用流程图计算函数J的导数?

用反向传播这个术语来解释:
如果你想要计算最终输出变量对v的导数,而这也是你通常最关心的变量,这就是一步反向传输。

在微积分中存在链式法则。如果通过计算dJ/dv,即J关于v的导数来帮助你计算dJ/da,这是反向传播的另一步。

当你写反向传播代码的时候,那些你真正关心的或者你想优化的最终输出变量,一般是流程图中的最后一个节点,你会做很多最终输出变量的导数运算,记这个最终输出变量对于其他变量导数的运算,dvar,这回牵涉到很多中间变量。当你在程序中实现的时候,你给这些变量取什么名字呢?在Python中你可以输入一个很长的名字,但因为导数都是关于最终输出变量J的,引入一个新符号,当你在代码中计算这个导数的时候,我们就用变量名dvar来代表这个值。所以dvar在你的代码中就代表最终输出变量,比如J对它的导数。dv;da。

这个例子中最重要的东西是:当在计算导数的时候,最有效率的方式是按红色箭头方向从右往左,特别的,我们先计算对v的导数,计算的结果对于计算J对a的导数和J对u的导数很有用...。

这就是流程图以及前向计算代价函数,以及如何反向或从右往左计算导数。

第十四课:Logistic回归梯度下降

在实现逻辑回归时,如何计算导数来实现梯度下降?
重点在于逻辑回归中梯度下降的关键方程。使用流程图对于逻辑回归的梯度下降有些大材小用。但对于熟悉神经网络有所帮助。

a是逻辑回归的输出
y是真实值

在逻辑回归中我们要做的就是修改参数w和b来减少损失函数。如何计算单个样本的损失函数之前的视频中已经讲过。接下来如何反向计算导数?

..

通过链式反则进行反向求导,反向传输的最后一步是反向算出你需要改变w和b多少?

所以如果你需要对一个例子进行梯度下降,你需要做如下事情:
用公式算出dz
然后用公式算出dw1 dw2和db
然后进行更新:w1 = w1 - αdw1(α表示学习速率)
w2 = w2 - α
dw2
b = b - α*db

当然这是个简单的例子,一步梯度的情况。
对于一个单一的训练样本如何计算导数和执行逻辑回归的梯度下降,但训练一个逻辑回归模型,你不止有一个样本,而是有m个,如何把梯度下降算法和执行逻辑回归应用到多个样本?

第十五课:在m个样本上进行Logistic回归梯度下降

m个训练样本的情况下 vs 只有一个训练样本:

在梯度下降法中有很多细节,但让我们把这些装进一个具体地算法,你需要实现的就是使逻辑回归和其中的梯度下降法生效。

细节:我们使用dw1,dw2和db作为累加器,所以计算完成后,dw1就等于你全局代价函数对w1的导数,dw2和db也是一样。注意dw'1和dw2没有上标i,是因为我们在这代码中把它们当做累加器去求取整个训练集上的和。然而dz(i)是对对应于单个仰恩的dz,这就是为什么dz会有上标i,它指代对应的第i个训练样本。

完成这些计算后实现一步梯度下降来更新w1,w2和b,最终J也会变成你代价函数的正确值。

幻灯片上的计算只实现了一步梯度下降,因此你需要重复以上内容很多次。

但它表明计算中有缺点:
逻辑回归时,你需要两个for循环,第一个for循环是一个小循环用于遍历m个训练样本,第二个for循环是一个遍历所有特征的for循环。当你实现深度学习算法时,你会发现在代码中显式的使用for循环会使你的算法不够高效。在深度学习时代会有越来越大的数据集,所以不适用显式的for循环来实现算法是非常重要的而且会帮你适用于更大的数据集。
所以这里有一些技术叫做矢量化技术,它可以帮助你的代码摆脱这些显式的for循环,我想在前深度学习的时代(兴起之前),矢量化是有两面性的,有时候能加速你的代码,有时候也未必。但在深度学习时代,矢量化,也就是摆脱for循环已经变得相当重要。因为我们越来越多地训练非常大的数据集因此你需要你的代码变得非常高效。

如何适量化以及是如何实现这些的同时不用一个for循环。

第十六课:向量化

向量化是一项能让你的代码变得更高效的艺术。

在深度学习领域,我认为实现向量化的能力已经变成一个关键的技巧。

例子:Python程序(略)

非向量化的版本比向量化的版本多花了300倍的时间。

大规模的深度学习使用了GPU或者图像处理单元实现。GPU和CPU都有并行化的指令:SIMD指令,它代表了一个单独指令多维数据。即Python中的numpy充分利用并行化去更快的计算。

第十六课:向量化(二)

上节课谈到了避免使用显式的for循环来实现向量化,这可以有效的提高代码的运行速度。

经验之谈:当你在编写神经网络或逻辑回归时,都要尽可能避免使用显式的for循环,虽然有时候不能完全避免,但如果你能使用内置函数或者找到其他方式来计算你想要的答案,这通常会比直接使用for循环更快。

实际上,numpy中有很多支持向量值的函数,比如对向量中每个元素进行对数运算,计算绝对值,将向量中的元素与0相比求最大值,计算向量中每个元素的平方,元素倒数...

接下来,我们将这些知识运用到逻辑回归的梯度下降算法实现:
看看我们能否可以至少摆脱两个for循环中的一个。

消灭第二个for循环:

进一步讨论如何对逻辑回归进行向量化?
没有for循环,你的算法也可以几乎同时处理所有数据集。

第十七课:矢量化Logistic回归

逻辑回归的向量化实现。使得它们可以被用于处理整个训练集,也就是说,可以用梯度下降法的一次迭代来处理整个训练集,甚至不需要使用任何一个for循环。

首先看看逻辑回归的前向传播:

这里有一个Python比较精妙的地方,后面加上的b是一个实数,或者说是一个11的矩阵,如果当你把这个实数b加上向量的时候,Python会自动的把这个实数b扩展为一个1m的行向量。这个在Python中叫做广播。

你可以使用一行代码计算Z,其中Z是一个包含z(1)、z(1)...z(m)的1*m矩阵。

如何实现一个(输入输出为)向量值的sigmoid函数?所以将这个Z作为sigmoid函数的输入值会非常高效的得到A。

总结:我们不需要遍历m个训练样本来一次一次计算z和a,你可以用一行代码来实现同时计算所有的z,利用sigma函数的恰当实现来同时计算所有的a。

这就是你如何通过向量化同时实现所有m个训练样本的前向传播。

如何使用向量化高效计算反向传播?

第十八课:矢量化Logistic回归的梯度输出

向量化计算同时计算出整个训练集的激活值a,如何使用向量化计算全部m个训练样本的梯度?如何高效的实现逻辑回归?

总结一下,到底应该如何实现逻辑回归?
结合这几节课的代码,进行前向传播和反向传播计算(对m个训练样本进行预测和求导),然后更新梯度下降:

至此就实现了逻辑回归梯度下降的一次迭代。
如果需要实现梯度下降的多次迭代,仍然需要使用for循环,去迭代指定的个次数!

现在你得到了一个高度向量化且非常高效的逻辑回归的梯度下降法,下节课:广播技术。

广播是Python和Numpy提供的一种能够使特定代码更加高效的技术。

第十九课:Python广播技术

深入研究Python中广播的运行机制:

假设你的目标是计算每种食物的热量中,来自碳水化合物、蛋白质和脂肪的比例?
问题在于:你能不用显式的for循环来完成这一操作么?

cal = A.sum(axis = 0)    #沿垂直方向(列)求和
percentage = 100 *  A/cal.reshape(1, 4)    #用矩阵A除以一个1*4的矩阵,从而得到了百分比矩阵

reshape()消耗常量的时间是一个0(1)操作,调用成本很低,所以不要害怕用reshape来确保矩阵是你想要的尺寸。

怎么能用3乘4矩阵除以1乘4的矩阵呢?

例子:
如果你有一个4乘1的向量,让它加一个数字,Python会自动将这个数字扩展成一个4乘1的向量。

这种广播适用于行向量和列向量。之前在逻辑回归中的b就相当于我们这里为向量加上的常量。

如果你让一个mn的矩阵,加上一个1n的矩阵,Python会将后者复制m次,使其变成一个m乘n的矩阵,然后相加。

假如你有一个m乘n的矩阵,让它加上一个m乘1的向量,或者说m乘1的矩阵,后者会在水平方向赋值n次,得到一个m乘n的矩阵,然后相加。

以下是Python广播的一些通用规则:

阅读numpy官方文档...

第二十课:关于python / numpy向量的注释

Python和numpy带来了极佳的灵活性,我认为这既是Python作为一门编程语言的优势也是它的劣势。其优势在于增加了语言的表达性,凭借其强大的灵活性,你只用仅仅一行代码就能完成大量的工作。但也带来了一些弱点,因为广播和这种灵活性很大,如果你不熟悉广播的复杂性和广播工作的功能,你有时可能会引入非常微妙的错误或非常奇怪的错误。例如,如果您采用列向量并将其添加到行向量,您可能会发现它会引发维度不匹配或键入错误等。但实际上,您可能会将矩阵作为行向量和列向量的总和。

因此,Python的这些奇怪效果有一个内部逻辑。但如果你不熟悉Python,我发现有些学生很奇怪,很难找到bug。所以我想在这个视频中做的是与你分享一些技巧和技巧,这些技巧和技巧对我来说非常有用,可以消除或简化并消除我自己的代码中所有奇怪的错误。我希望通过这些提示和技巧,您还可以更轻松地编写无bug的python和numpy代码。

我建议你在编写神经网络时,不要使用这种数据结构,即形如(5)或者(n)这样的秩为1的数组,而是令a的形状为(5,1),这会使a成为一个5乘1的列向量。

秩为1的数组 VS 真正的1乘5的矩阵

!不要使用秩为1的数组,而是创建5乘1的向量,或者确保它是一个行向量,那么这些向量的行为更容易理解。

当我不太确定某一个向量的维度,我通常会将其放入断言语句中。执行断言语句的成本很低,还能充当代码的文档,所以当你觉得需要的时候,就使用断言语句。

最后,如果出于某些原因,你得到了一个秩为1的数组,你可以用reshape来改变它的形状

a = a.reshape((5, 1))

这样它就会始终表现为列向量或者行向量。我有时会见到学生因为这些秩为1的数组的不直观的行为出现一些很难找出的bug。通过在旧代码中消除秩为1的矩阵,我觉得我的代码变得更简单了,而且我不觉得这样写会限制代码的表达。

为了简化代码,不要使用秩为1的数组,始终使用n乘1的矩阵,本质上是列向量,或者使用1乘n的矩阵,本质上是行向量。自由使用断言语句,来复查矩阵和数组的维度。还有,不要怕使用reshape操作来确保矩阵和向量是你所需要的维度。

第二十一课:快速介绍Jupyter / iPython笔记本电脑

有了你所学到的一切,你就可以准备好解决你的第一个编程任务了。在您这样做之前,让我快速介绍一下Coursera中的iPython Notebook。

有几个提示。当你执行这样的代码时,它实际上运行在内核上,运行在服务器上的一段代码上。如果你的工作量太大,或者你离开计算机很长时间或出现问题,你的互联网连接什么的话,后端的内核很可能会死掉,在这种情况下,只需单击Kernel然后重新启动内核。并希望,这将重新启动内核并使其再次工作。

所以如果你只是运行相对较小的工作并且你刚刚启动iPython笔记本电脑那么这应该不会发生。如果您看到内核已经死亡的错误消息,则可以尝试内核,重启。

最后,在这样的iPython笔记本中,可能存在多个代码块。因此,即使较早的代码块在代码中没有任何创建,也要确保执行此代码块,因为在此示例中,它将numpy导入为np,依此类推,并设置一些可能的变量需要为了执行更低的代码块。因此,即使您没有被要求在其中编写任何代码,也要确保执行上面的代码。

我发现iPython笔记本的交互式命令shell性质对于快速学习,实现几行代码,查看结果,学习和添加非常快速非常有用。所以我希望通过Coursera中的练习,Jupyter iPython笔记本将帮助您快速学习和实验,并了解如何实现这些算法。

此后还有一个视频。这是一个可选视频,讨论了逻辑回归的成本函数。

第二十二课:逻辑回归成本函数的解释(可选)

在这个可选视频中,我想快速说明为什么我们喜欢使用该成本函数进行逻辑回归。

明天继续...溜

推荐阅读更多精彩内容