第二周:神经网络的编程基础(Basics of Neural Network programming)
2.1 二分类(Binary Classification)
2.3 逻辑回归的代价函数(Logistic Regression Cost Function)
2.6 更多的导数例子(More Derivative Examples)
2.8 使用计算图求导数(Derivatives with a Computation Graph)
2.9 逻辑回归中的梯度下降(Logistic Regression Gradient Descent)
2.10 m 个样本的梯度下降(Gradient Descent on m Examples)
2.12 向量化的更多例子(More Examples of Vectorization)
2.13 向量化逻辑回归(Vectorizing Logistic Regression)
2.14 向量化 logistic 回归的梯度输出(Vectorizing Logistic Regression's Gradient)
2.15 Python 中的广播(Broadcasting in Python)
2.16 关于 python _ numpy 向量的说明(A note on python or numpy vectors)
参考视频:2.17 Jupyter/iPython Notebooks快速入门(Quick tour of Jupyter/iPython Notebooks)
2.18 (选修)logistic 损失函数的解释(Explanation of logistic regression cost function)
2.1 二分类(Binary Classification)
我们来看看一张图片在计算机中是如何表示的,为了保存一张图片,需要保存三个矩阵,它们分别对应图片中的红、绿、蓝三种颜色通道,如果你的图片大小为64x64像素,那么你就有三个规模为64x64的矩阵,分别对应图片中红、绿、蓝三种像素的强度值。为了便于表示,这里我画了三个很小的矩阵,注意它们的规模为5x4 而不是64x64,如下图所示:
接下来我们说明一些在余下课程中,需要用到的一些符号。
符号定义 :
2.2 逻辑回归(Logistic Regression)
在这个视频中,我们会重温逻辑回归学习算法,该算法适用于二分类问题,本节将主要介绍逻辑回归的Hypothesis Function(假设函数)。
2.3 逻辑回归的代价函数(Logistic Regression Cost Function)
在上个视频中,我们讲了逻辑回归模型,这个视频里,我们讲逻辑回归的代价函数(也翻译作成本函数)。
为什么需要代价函数:
损失函数:
2.4 梯度下降法(Gradient Descent)
梯度下降法可以做什么?
梯度下降法的形象化说明
2. 朝最陡的下坡方向走一步,不断地迭代
我们朝最陡的下坡方向走一步,如图,走到了如图中第二个小红点处。
我们可能停在这里也有可能继续朝最陡的下坡方向再走一步,如图,经过两次迭代走到第三个小红点处。
3.直到走到全局最优解或者接近全局最优解的地方
整个梯度下降法的迭代过程就是不断地向左走,直至逼近最小值点。
2.5 导数(Derivatives)
这个视频我主要是想帮你获得对微积分和导数直观的理解。或许你认为自从大学毕以后你再也没有接触微积分。这取决于你什么时候毕业,也许有一段时间了,如果你顾虑这点,请不要担心。为了高效应用神经网络和深度学习,你并不需要非常深入理解微积分。因此如果你观看这个视频或者以后的视频时心想:“哇哦,这些知识、这些运算对我来说很复杂。”我给你的建议是:坚持学习视频,最好下课后做作业,成功的完成编程作业,然后你就可以使用深度学习了。在第四周之后的学习中,你会看到定义的很多种类的函数,通过微积分他们能够帮助你把所有的知识结合起来,其中有的叫做前向函数和反向函数,因此你不需要了解所有你使用的那些微积分中的函数。所以你不用担心他们,除此之外在对深度学习的尝试中,这周我们要进一步深入了解微积分的细节。所有你只需要直观地认识微积分,用来构建和成功的应用这些算法。最后,如果你是精通微积分的那一小部分人群,你对微积分非常熟悉,你可以跳过这部分视频。其他同学让我们开始深入学习导数。
2.6 更多的导数例子(More Derivative Examples)
在这个视频中我将给出一个更加复杂的例子,在这个例子中,函数在不同点处的斜率是不一样的,先来举个例子:
为了总结这堂课所学的知识,我们再来看看几个例子:
在这个视频中,你只需要记住两点:
2.7 计算图(Computation Graph)
可以说,一个神经网络的计算,都是按照前向或反向传播过程组织的。首先我们计算出一个新的网络的输出(前向过程),紧接着进行一个反向传输操作。后者我们用来计算出对应的梯度或导数。计算图解释了为什么我们用这种方式组织这些计算过程。在这个视频中,我们将举一个例子说明计算图是什么。让我们举一个比逻辑回归更加简单的,或者说不那么正式的神经网络的例子。
2.8 使用计算图求导数(Derivatives with a Computation Graph)
在上一个视频中,我们看了一个例子使用流程计算图来计算函数J。现在我们清理一下流程图的描述,看看你如何利用它计算出函数的导数。
下面用到的公式:
2.9 逻辑回归中的梯度下降(Logistic Regression Gradient Descent)
本节我们讨论怎样通过计算偏导数来实现逻辑回归的梯度下降算法。它的关键点是几个重要公式,其作用是用来实现逻辑回归中梯度下降算法。但是在本节视频中,我将使用计算图对梯度下降算法进行计算。我必须要承认的是,使用计算图来计算逻辑回归的梯度下降算法有点大材小小用了。但是,我认为以这个例子作为开始来讲解,可以使你更好的理解背后的思想。从而在讨论神经网络时,你可以更深刻而全面地理解神经网络。接下来让我们开始学习逻辑回归的梯度下降算法。
现在你已经知道了怎样计算导数,并且实现针对单个训练样本的逻辑回归的梯度下降算法。但是,训练逻辑回归模型不仅仅只有一个训练样本,而是有m个训练样本的整个训练集。因此在下一节视频中,我们将这些思想应用到整个训练样本集中,而不仅仅只是单个样本上。
2.10 m 个样本的梯度下降(Gradient Descent on m Examples)
在之前的视频中,你已经看到如何计算导数,以及应用梯度下降在逻辑回归的一个训练样本上。现在我们想要把它应用在
个训练样本上。
但之前我们已经演示了如何计算这项,即之前幻灯中演示的如何对单个训练样本进行计算。所以你真正需要做的是计算这些微分,如我们在之前的训练样本上做的。并且求平均,这会给你全局梯度值,你能够把它直接应用到梯度下降算法中。
所以这里有很多细节,但让我们把这些装进一个具体的算法。同时你需要一起应用的就是逻辑回归和梯度下降。
J=0;dw1=0;dw2=0;db=0;
for i = 1 to m
z(i) = wx(i)+b;
a(i) = sigmoid(z(i));
J += -[y(i)log(a(i))+(1-y(i))log(1-a(i));
dz(i) = a(i)-y(i);
dw1 += x1(i)dz(i);
dw2 += x2(i)dz(i);
db += dz(i);
J/= m;
dw1/= m;
dw2/= m;
db/= m;
w=w-alpha*dw
b=b-alpha*db
2.11 向量化(Vectorization)
参考视频: 2.11 向量化
向量化是非常基础的去除代码中for循环的艺术,在深度学习安全领域、深度学习实践中,你会经常发现自己训练大数据集,因为深度学习算法处理大数据集效果很棒,所以你的代码运行速度非常重要,否则如果在大数据集上,你的代码可能花费很长时间去运行,你将要等待非常长的时间去得到结果。所以在深度学习领域,运行向量化是一个关键的技巧,让我们举个栗子说明什么是向量化。
z=0
for i in range(n_x)
z+=w[i]*x[i]
z+=b
让我们用一个小例子说明一下,在我的我将会写一些代码(以下为教授在他的Jupyter notebook上写的Python代码,)
import numpy as np #导入numpy库
a = np.array([1,2,3,4]) #创建一个数据a
print(a)
# [1 2 3 4]
import time #导入时间库
a = np.random.rand(1000000)
b = np.random.rand(1000000) #通过round随机得到两个一百万维度的数组
tic = time.time() #现在测量一下当前时间
#向量化的版本
c = np.dot(a,b)
toc = time.time()
print(“Vectorized version:” + str(1000*(toc-tic)) +”ms”) #打印一下向量化的版本的时间
#继续增加非向量化的版本
c = 0
tic = time.time()
for i in range(1000000):
c += a[i]*b[i]
toc = time.time()
print(c)
print(“For loop:” + str(1000*(toc-tic)) + “ms”)#打印for循环的版本的时间
返回值见图。
在两个方法中,向量化和非向量化计算了相同的值,如你所见,向量化版本花费了1.5毫秒,非向量化版本的for循环花费了大约几乎500毫秒,非向量化版本多花费了300倍时间。所以在这个例子中,仅仅是向量化你的代码,就会运行300倍快。这意味着如果向量化方法需要花费一分钟去运行的数据,for循环将会花费5个小时去运行。
一句话总结,以上都是再说和for循环相比,向量化可以快速得到结果。
你可能听过很多类似如下的话,“大规模的深度学习使用了GPU或者图像处理单元实现”,但是我做的所有的案例都是在jupyter notebook上面实现,这里只有CPU,CPU和GPU都有并行化的指令,他们有时候会叫做SIMD指令,这个代表了一个单独指令多维数据,这个的基础意义是,如果你使用了built-in函数,像np.function
或者并不要求你实现循环的函数,它可以让python的充分利用并行化计算,这是事实在GPU和CPU上面计算,GPU更加擅长SIMD计算,但是CPU事实上也不是太差,可能没有GPU那么擅长吧。接下来的视频中,你将看到向量化怎么能够加速你的代码,经验法则是,无论什么时候,避免使用明确的for循环。
以下代码及运行结果截图:
2.12 向量化的更多例子(More Examples of Vectorization)
希望这个视频给了你一点向量化感觉,减少一层循环使你代码更快,但事实证明我们能做得更好。所以在下个视频,我们将进一步的讲解逻辑回归,你将会看到更好的监督学习结果。在训练中不需要使用任何 for 循环,你也可以写出代码去运行整个训练集。到此为止一切都好,让我们看下一个视频。
2.13 向量化逻辑回归(Vectorizing Logistic Regression)
我们已经讨论过向量化是如何显著加速你的代码,在本次视频中我们将讨论如何实现逻辑回归的向量化计算。这样就能处理整个数据集,甚至不会用一个明确的for循环就能实现对于整个数据集梯度下降算法的优化。我对这项技术感到非常激动,并且当我们后面谈到神经网络时同样也不会用到一个明确的 for 循环。
2.14 向量化 logistic 回归的梯度输出(Vectorizing Logistic Regression's Gradient)
注:本节中大写字母代表向量,小写字母代表元素
我们的目标是不使用for循环,而是向量,我们可以这么做:
现在我们利用前五个公式完成了前向和后向传播,也实现了对所有训练样本进行预测和求导,再利用后两个公式,梯度下降更新参数。我们的目的是不使用for循环,所以我们就通过一次迭代实现一次梯度下降,但如果你希望多次迭代进行梯度下降,那么仍然需要for循环,放在最外层。不过我们还是觉得一次迭代就进行一次梯度下降,避免使用任何循环比较舒服一些。
最后,我们得到了一个高度向量化的、非常高效的逻辑回归的梯度下降算法,我们将在下次视频中讨论Python中的Broadcasting技术。
2.15 Python 中的广播(Broadcasting in Python)
这是一个不同食物(每100g)中不同营养成分的卡路里含量表格,表格为3行4列,列表示不同的食物种类,从左至右依次为苹果,牛肉,鸡蛋,土豆。行表示不同的营养成分,从上到下依次为碳水化合物,蛋白质,脂肪。
那么,我们现在想要计算不同食物中不同营养成分中的卡路里百分比。
现在计算苹果中的碳水化合物卡路里百分比含量,首先计算苹果(100g)中三种营养成分卡路里总和56+1.2+1.8 = 59,然后用56/59 = 94.9%算出结果。
可以看出苹果中的卡路里大部分来自于碳水化合物,而牛肉则不同。
对于其他食物,计算方法类似。首先,按列求和,计算每种食物中(100g)三种营养成分总和,然后分别用不用营养成分的卡路里数量除以总和,计算百分比。
那么,能否不使用for循环完成这样的一个计算过程呢?
下面使用如下代码计算每列的和,可以看到输出是每种食物(100g)的卡路里总和。
这里我先说一下我本人对numpy广播机制的理解,再解释上面这张PPT。
首先是numpy广播机制
如果两个数组的后缘维度的轴长度相符或其中一方的轴长度为1,则认为它们是广播兼容的。广播会在缺失维度和轴长度为1的维度上进行。
后缘维度的轴长度:A.shape[-1]
即矩阵维度元组中的最后一个位置的值
2.16 关于 python _ numpy 向量的说明(A note on python or numpy vectors)参考视频:
本节主要讲Python中的numpy一维数组的特性,以及与行向量或列向量的区别。并介绍了老师在实际应用中的一些小技巧,去避免在coding中由于这些特性而导致的bug。
Python的特性允许你使用广播(broadcasting)功能,这是Python的numpy程序语言库中最灵活的地方。而我认为这是程序语言的优点,也是缺点。优点的原因在于它们创造出语言的表达性,Python语言巨大的灵活性使得你仅仅通过一行代码就能做很多事情。但是这也是缺点,由于广播巨大的灵活性,有时候你对于广播的特点以及广播的工作原理这些细节不熟悉的话,你可能会产生很细微或者看起来很奇怪的bug。例如,如果你将一个列向量添加到一个行向量中,你会以为它报出维度不匹配或类型错误之类的错误,但是实际上你会得到一个行向量和列向量的求和。
在Python的这些奇怪的影响之中,其实是有一个内在的逻辑关系的。但是如果对Python不熟悉的话,我就曾经见过的一些学生非常生硬、非常艰难地去寻找bug。所以我在这里想做的就是分享给你们一些技巧,这些技巧对我非常有用,它们能消除或者简化我的代码中所有看起来很奇怪的bug。同时我也希望通过这些技巧,你也能更容易地写没有bug的Python和numpy代码。
2.17 Jupyter/iPython Notebooks快速入门(Quick tour of Jupyter/iPython Notebooks)
学到现在,你即将要开始处理你的第一个编程作业。但在那之前,让我快速地给你介绍一下在Coursera上的iPython Notebooks工具。
这就是Jupyter iPython Notebooks的界面,你可以通过它连接到Coursera。让我快速地讲解下它的一些特性。关于它的说明已经被写入这个Notebook中。
这里有一些空白区域的代码块,你可以在这里编写代码。有时,你也会看到一些函数块。而关于这些的说明都已经在iPython Notebook的文本中。在iPython Notebook中,在这些较长的灰色的区域就是代码块。
有时,你会看到代码块中有像这样的开始代码和结束代码。在进行编程练习时,请确保你的代码写在开始代码和结束代码之间。
比如,编写打印输出Hello World的代码,然后执行这一代码块(你可以按shift +enter来执行这一代码块)。最终,它就会输出我们想要的Hello World。
在运行一个单元格cell时,你也可以选择运行其中的一块代码区域。通过点击Cell菜单的Run Cells执行这部分代码。
也许,在你的计算机上,运行cell的键盘快捷方式可能并非是shift enter。但是,Mac应该和我的个人电脑一样,可以使用shift + enter来运行cell。
当你正在阅读指南时,如果不小心双击了它,点中的区域就会变成markdown语言形式。如果你不小心使其变成了这样的文本框,只要运行下单元格cell,就可以回到原来的形式。所以,点击cell菜单的Run Cells或者使用shift + enter,就可以使得它变回原样。
这里还有一些其他的小技巧。比如当你执行上面所使用的代码时,它实际上会使用一个内核在服务器上运行这段代码。如果你正在运行超负荷的进程,或者电脑运行了很长一段时间,或者在运行中出了错,又或者网络连接失败,这里依然有机会让Kernel重新工作。你只要点击Kernel,选择Restart,它会重新运行Kernel使程序继续工作。
所以,如果你只是运行相对较小的工作并且才刚刚启动你的ipad或笔记本电脑,这种情况应该是不会发生的。但是,如果你看见错误信息,比如Kernel已经中断或者其他信息,你可以试着重启Kernel。
当我使用iPython Notebook时会有多个代码区域块。尽管我并没有在前面的代码块中添加自己的代码,但还是要确保先执行这块代码。因为在这个例子,它导入了numpy包并另命名为np等,并声明了一些你可能需要的变量。为了能顺利地执行下面的代码,就必须确保先执行上面的代码,即使不要求你去写其他的代码。
最后,当你完成作业后,可以通过点击右上方蓝色的Submit Assignment按钮提交你的作业。
我发现这种交互式的shell命令,在iPython Notebooks是非常有用的,能使你快速地实现代码并且查看输出结果,便于学习。所以我希望这些练习和Jupyter iPython Notebooks会帮助你更快地学习和实践,并且帮助你了解如何去实现这些学习算法。后面一个视频是一个选学视频,它主要是讲解逻辑回归中的代价函数。你可以选择是否观看。不管怎样,都祝愿你能通过这两次编程作业。我会在新一周的课程里等待着你。
2.18 (选修)logistic 损失函数的解释(Explanation of logistic regression cost function)
在前面的视频中,我们已经分析了逻辑回归的损失函数表达式,在这节选修视频中,我将给出一个简洁的证明来说明逻辑回归的损失函数为什么是这种形式。
在m个训练样本的整个训练集中又该如何表示呢,让我们一起来探讨一下。
让我们一起来探讨一下,整个训练集中标签的概率,更正式地来写一下。假设所有的训练样本服从同一分布且相互独立,也即独立同分布的,所有这些样本的联合概率就是每个样本概率的乘积: