续前一节 1.2 神经网络基础2
7. 计算图(Computation Graph)
神经网络的计算都是按照前向传播过程计算出神经网络的输出,紧接着用反向传播过程来计算出对应的梯度或者导数。计算图就解释了为什么神经网络是这样的一种组织形式。通过举例来阐释计算图,即计算过程。举一个比logistic回归更简单、非正式的例子来说明:计算J(a,b,c)=3(a+bc)
这个函数实际上有三个步骤:
第一步:u = bc
第二步:v = a + u
第三步:J = 3v
通过上述步骤,可以计算出J(a,b,c)的值,将这个计算过程反向执行,即为梯度(导数)计算过程。
8. 计算图的导数计算(Derivatives with a Computation Graph)
本节课主要介绍如何利用计算图进行函数J的导数计算。
在反向传播算法的术语中,如果你想计算最后输出变量的导数,这个变量就是你最关心的变量,在图2中可以看到,这个变量就是J,这个计算函数J关于变量v的导数的过程(dJ/dv=?
)就是一步反向传播的过程。在流程图中就体现为一个反向步。
那么,我们可以继续思考,如果对a增加一定数值,函数J的数值会发生什么变化呢?
修改a的值会根据计算流程图将改变值传递到最右边,即a的数值变化,最终会反应到函数J的结果中。这个计算过程可以理解为:a->v->J,这个微分传导的过程在微积分中称为链式法则(Chain rule)。
计算最终输出变量的导数就是计算d输出变量关于某个变量的导数。那么这个导数的公式在代码中应该用什么样的变量名来表示呢?Andrew给出了一种命名方案:根据函数关于哪个变量进行求导来命名,如:求最终输出变量J关于变量v的导数,在代码中我们可以用dv来表示,在本例中,dv=3;同理,求最终输出变量J关于变量a的导数,在代码中我们可以用da来表示,在本例中,da=3,其他情况以此类推。
本节课的核心要点是:当计算所有这些导数时,最有效的方法是根据计算流程图从右到左计算,如下图中的红色箭头的方向:
9. logistic回归中的梯度下降法(Logistic Regression Gradient Descent)
本节课主要介绍怎样计算偏导数来实现logistic回归的梯度下降法,它的核心关键点是用来实现logistic回归的梯度下降法中的几个重要公式。但在本节视频中,将使用计算流程图来计算导数。用计算流程图来推导logistic回归的梯度下降算法有点大材小用了,但为了后面能够更加深入的了解神经网络算法,这里采用了计算流程图的方式来分析logistic回归的梯度下降法执行过程。
要想计算损失函数L的偏导数,首先需要从图6中的计算流程图最右侧的节点往回退一步,计算最终结果损失函数L关于变量a的导数,得到结果da后,再回退一步,计算L关于z的导数dz,最后回退到初始变量,计算L关于w1的导数dw1、L关于w2的导数dw2和L关于b的导数b。
接下来根据梯度下降法算法,计算下一个能够使损失函数更小的w1、w2和b的组合,计算公式如下:
10. m个样本的梯度下降(Gradient Descent on m examples)
在本节课中,主要讲解了如何计算m个样本的训练集的整体成本函数J(w,b)的梯度下降计算过程,并使用Python伪代码进行说明。
在上一节课中,我们已经计算出了单个样本的损失函数的导数,而m个样本的训练集整体的成本函数J(w,b)的计算公式已经在上一篇文章第3节中给出,也就是说,成本函数J的导数就是所有样本损失函数L的导数的平均数,这个分析过程如图7所示:
根据上述分析,可以得出图8所示的Python伪代码:
从伪代码中可以看出,梯度下降法的一次迭代需要经过两层嵌套的循环计算才能完成,循环的时间复杂度为O(m*n)
,其中,m
代表训练集中样本个数,n
代表一个样本中特征的个数。
当实现深度学习算法时,在代码中显式的使用for循环会使算法非常低效,为了解决在深度学习算法中对于大量训练集的学习效率问题,引入了向量化技术,该技术可以避免在深度学习算法中使用for循环,进而提高运算效率。
注意:本节课中,每个样本的特征个数假设为两个,在实际应用过程中也可能是多个,每个特征都会对应一个变量w,变量b为每个样本对应一个。
11. 向量化(Vectorization)
本质上,向量化是消除代码中显示for循环语句的艺术。
训练集数据量越大,深度学习算法才能够更加优越。这就需要我们的深度学习算法运算速度足够快,因此,在深度学习领域,完成向量化的能力已经变成一个关键的技能。
本节课主要以两个1,000,000维矩阵相乘为例,在Python中用for循环和向量化的方法实现,比较两种方法的运行耗时,从而验证了使用向量化的方法要比显示的for循环的运算性能更好,下图为本人根据视频教程在Jupyter Notebook中做的实验截图:
深度学习一般是在GPU(图像处理单元,Graphics Processing Unit)中运行的,但在本次课程中的demo是运行在Jupyter Notebook中的,即运行在CPU中,这就说明GPU和CPU均有并行化的指令(也称为SIMD指令),也就是一条指令中可以同时处理多数据流。
我们可以通过numpy.functions来调用这些方法,避免Python代码中显式调用for循环,从而能够更好地利用CPU或者GPU的并行机制。
经验法则:只要有其他可能,就不要使用显示的for循环。
Whenever possible, avoid explicit for-loops. ——Andrew Ng
12. 向量化的更多例子(More Vectorization Examples)
用内置函数或者其他方法代替显式for循环。
本节课首先介绍了几个numpy库中常用的一些方法,如:矩阵的每个元素的指数计算、对数计算、绝对值计算等。具体的方法写法如下图所示:
利用numpy库中的内置方法对第10节中编写的m个样本的训练集的梯度下降法算法进行优化,最终,我们可以将两层嵌套的循环中的内层for循环优化掉,即将样本内特征向量的遍历被优化了。优化过程及结果如下图所示:
本节课优化完成后的算法效率得到了大大的提高,但仍然还有一层for循环用来遍历训练集中的样本,那么如何优化这个循环呢?我们将在第14节中来见证这个奇迹的时刻!
13. 向量化logistic回归(Vectorizing Logistic Regression)
本节课主要讲的内容是:向量化如何在logistic回归中应用,这样就能做到在一次计算过程中同时处理整个m个样本的训练集。那么在正向传播步骤的一次迭代的向量化实现,应该如何做呢?
- 首先,为了达成这个目的,我们需要将m个样本各自的特征向量x(i)作为一个个列向量合并成一个大的矩阵,记为X;
- 然后,将所有的z(i)也合并成一个行向量,记为Z,Z=[z(1) z(2) ... z(m)];
- 那么,计算m次z(i)的过程就可以转化为一次m维的行向量wT与nxm维矩阵的乘积与1m维行向量[b b ... b]之和,即:Z=wTX+[b b ... b];
- 同理,可以将m个预测结果a(i)整合为一个m维的行向量,记为A,A=[a(1) a(2) ... a(m)]=sigma(Z);
在Python中,m维的行向量+实数b将会被自动转化为m维的行向量+1*m维的行向量[b b ... b]。这个操作在Python中称为广播(Broadcasting)。
14. 向量化logistic回归的梯度输出(Vectorizing Logistic Regression's Gradient Computation)
本节课的主要内容是:运用向量化来计算m个样本的训练数据集的梯度。
首先,根据第13节中的讲解,我们可以将m个dz(i)=a(i)-y(i)合并到一次计算过程中:
dZ=A-Y=[a(1)-y(1) a(2)-y(2) ...]
这样我们就可以将第12节中的遍历m个样本的for循环进行向量化,从而去除另外一个显式for循环。
接下来,将第13节和本节内容结合起来,整体来看下logistic回归的梯度下降法一次迭代优化后的伪代码:
到此为止,我们已经对logistic回归的梯度下降法一次迭代的计算过程全部进行了向量化,但是,为了得到尽可能小的成本函数J,我们还是需要通过for循环来进行多次的梯度下降法的迭代,从而得到合适的w和b的组合。
15. Python中的广播(Broadcasting in Python)
本节课中主要讲解了Python中的广播(Broadcasting)是怎样运作的,这个技术同样也是为了能够提高代码的效能。
16. 关于Python/numpy向量的说明(A note on python/numpy vectors)
17. Jupyter/Ipython 笔记本的快速指南
本节课主要讲解了在Coursera中的IPython的一些常用的功能。其中,
- 灰色块表示代码块;
- 作业的代码需要写在代码开始和代码结束注释之间才算有效;
- 执行一个单元格内的代码有两种方式:一种是右键选中单元格,选择【Run Cells】;另一种方法是使用快捷键,在Windows操作系统中,默认快捷键为Shift+Enter;
- 双击文本单元格可以查看文本单元格的Markdown源码,运行单元格可以恢复文本预览模式;
- 如果出现断网或者其他错误导致内核(Kernel)宕机,可以通过工具栏中的重启功能进行重启操作;
- 要尽可能运行说明文档中的所有单元格,因为可能有部分变量是在上面的单元格中定义的,而我们在后续的单元格执行过程中需要用到这些变量。