深度学习入门笔记(三):求导和计算图

欢迎关注WX公众号:【程序员管小亮】

专栏——深度学习入门笔记

声明

1)该文章整理自网上的大牛和机器学习专家无私奉献的资料,具体引用的资料请看参考文献。
2)本文仅供学术交流,非商用。因此每一部分具体的参考资料并无详细对应。若是某部分不当心侵犯了你们的利益,还望海涵,并联系博主删除。
3)博主才疏学浅,文中若有不当之处,请各位指出,共同进步,谢谢。
4)此属于初版本,如有错误,还需继续修正与增删。还望你们多多指点。你们都共享一点点,一块儿为祖国科研的推动添砖加瓦。html

深度学习入门笔记(三):求导和计算图

0、写在前面

这一次主要是想对微积分和导数直观理解一下。不少人在想或许自从大学毕之后,再也没有接触微积分。不要担忧,为了高效应用神经网络和深度学习,其实 并不须要很是深刻理解微积分程序员

若是你是精通微积分的那一小部分人群,对微积分很是熟悉,能够跳过这个笔记。web

一、导数

导数,也叫导函数值,又名微商,是微积分中的重要基础概念,可是其实理解起来并无那么难。来看一个例子:
在这里插入图片描述
一个函数 f ( a ) = 3 a f(a)=3a ,如图能够看出它是一条直线,这个别说你不会,xD。那么什么是导数,简单理解一下:编程

看看函数中几个点,假定 a = 2 a=2 ,那么 f ( a ) = 3 a f(a)=3a a a 的 3 倍,也就是 3 * 2 = 6,即若 a = 2 a=2 ,那么函数 f ( a ) = 6 f(a)=6 ,第一个点就是 a f ( a ) = 2 6 (a,f(a))=(2,6) 网络

若是假定稍微改变一点点 a a 的值,只增长一点,变为 2.001(只增长了 0.001),这时 a a 将向右作微小的移动。0.001 的差异实在是过小了, 1 0 3 10^{-3} 数量级的移动,不能在图中很明显地看出来,这里稍稍夸张了一下,意思到位就ok。如今 f ( a ) = 3 a f(a)=3a 等于 a a 的 3 倍是 2.001 * 3 = 6.003app

请看这个绿色小清新的三角形!!!根据刚才的结果,若是向右移动 0.001,那么 f ( a ) f(a) 增长 6.003 - 6 = 0.003 f ( a ) f(a) 的值增长 3 倍于右移的 a a 0.003 / 0.001 = 3,所以咱们说函数 f ( a ) f(a) a = 2 a=2 点的导数就是在这个点的斜率,而这个点的斜率是 3,那么斜率是什么?
在这里插入图片描述
已知一个图如上,斜率 K 计算公式以下:
在这里插入图片描述
导数这个概念意味着斜率!!!导数 这个词,听起来就是一个很可怕、很使人惊恐的词,可是 斜率 以一种很友好的方式来描述导数这个概念。因此提到导数,不严格的说,就把它看成函数的斜率就行了。经过一个例子来体会一下斜率的定义,在上图的绿色三角形中,用三角形的高除以三角形的宽,即斜率等于 0.003 / 0.001 = 3,等于3,或者说导数等于 3。这意味着什么呢?这意味着当你将 a a 右移 0.001时, f ( a ) f(a) 的值增长 3 倍水平方向的量。框架

若是换个数呢?如今假设 a = 5 a=5 也是同样的,此时 f ( a ) = 3 a = 15 f(a)=3a=15 。把 a a 右移一个很小的幅度,增长到 5.001,根据 f ( a ) = 3 a f(a) = 3a 能够获得 3 * 5.001 = 15.003。即在 a = 5 a=5 时,斜率是 3。这就表示,当变量 a a 的值发生微小改变时, d f ( a ) d a = 3 \frac{df(a)}{da}=3 。一个等价的导数表达式还能够这样写 d d a f ( a ) \frac{d}{da}f(a) ,即 f ( a ) f(a) 放在上面或者放在右边都没有关系,是同样的。机器学习

那就是导数的正式定义!!!数学上导数用 f ( a ) = d f ( a ) d a f'(a) = \frac{df(a)}{da} 表示。svg

导数的一个特性是:这个例子中的这个函数在任何地方的斜率老是等于 3,无论 a = 2 a=2 a = 5 a=5 ,这个函数的斜率总等于3,也就是说导数总等于 3。那么全部的函数斜率都是不变的嘛?固然不是,下面这个例子中函数在不一样点的斜率是可变的。函数

二、深刻理解导数

下面来看一个更加复杂的例子,有多复杂?在这个例子中,函数在不一样点处的斜率是不同的,别慌,先来举个例子:
在这里插入图片描述
这里有一个不同的函数, f ( a ) = a 2 f(a)={{\text{a}}^{\text{2}}} ,直观上看,是个曲线,眉头一皱,感受事情不太对劲。如今若是假设 a = 2 a=\text{2} 的话,那么 f ( a ) = a 2 f(a)={{\text{a}}^{\text{2}}} 能够获得 f ( 2 ) = 2 2 = 4 f(2) = 2^2 = 4 。仍是稍稍往右推动一点点,如今 a = 2 . 001 a=\text{2}.\text{001} ,则 f ( a ) 4.004 f(a)\approx 4.004 (为何要约等于?若是你用计算器算的话,就会发现这个准确的值应该为4.004001,只是为了简便起见,省略了后面的部分)。

在这里插入图片描述
仍是画图的方法进行理解,获得一个小三角形,若是细心的话你就会发现,此次严格意义上并非三角形。若是把 a a 往右移动 0.001,那么 f ( a ) f(a) 将增大四倍,即增大 4.004 - 4 = 0.004,而 0.004 / 0.001 = 4

在微积分中,把这个三角形斜边的斜率,称为 f ( a ) f(a) 在点 a = 2 a=\text{2} 处的导数(即为 4 );或者写成微积分的正式定义形式,当 a = 2 a=\text{2} 的时候, d d a f ( a ) = 4 \frac{d}{da}f(a)=4 。由此可知,函数 f ( a ) = a 2 f(a)={{a}^{{2}}} ,在 a a 取不一样值的时候,它的斜率是不一样的,这和上面的例子显然是不一样的。

若是你仍是不太理解的话,这里有种直观的方法能够解释,就是画图法。为何一个点的斜率,在不一样位置会不一样若是?咱们能够在曲线上的不一样位置,画一些小小的三角形你就会发现,三角形高和宽的比值,即斜率,在曲线上不一样的地方是不一样的。因此当 a = 2 a=2 时,斜率为 4;而当 a = 5 a=5 时,斜率为 10。

若是严谨地说,能够百度导数表。你会发现,函数 f ( a ) = a 2 f(a)={{a}^{{2}}} 的斜率(即导数)为 2 a 2a ,而函数 f ( a ) = 3 a f(a)=3a 的斜率(即导数)为3。
在这里插入图片描述
这意味着什么?这么说,若是任意给定一点 a a ,稍微将 a a 增大 0.001,两个函数增大的彻底不同。一个是和 a a 有关的,而另外一个则是常数。

来小结一下:

  1. 导数就是斜率,而函数的斜率在不一样的点多是不一样的。在 f ( a ) = 3 a f(a)=\text{3}a 时,在任何点它的斜率都是相同的,均为3。但对 f ( a ) = a 2 f(a)={{\text{a}}^{\text{2}}} ,斜率是变化的,因此它们的导数或者斜率,在曲线上不一样的点处是不一样的。

  2. 若是想知道一个函数的导数,可参考导数表,而后应该就能找到这些函数的导数公式,直接带数就完事了。

三、计算图

一个神经网络的计算大致上能够当作是,前向或反向传播组合而成的。只有公式描述,确实有一些晦涩,这个时候咱们想到了计算图。计算图是什么?

计算图是一种描述方程的语言,既然是图,则有 节点(变量)边(操做)

在这里插入图片描述
这么说太官方了,来举一个比逻辑回归更加简单的,或者说不那么正式的神经网络的例子。

咱们的目的是计算函数 J J ,函数 J J 的组成是什么呢?是由三个变量 a , b , c a,b,c 组成的函数,这个函数是 3(a + bc) \text{3(a}+\text{bc)} 。计算这个函数实际上有三个不一样的步骤,也就是拆分一下,用复合函数的思想去理解。

首先是计算 b b 乘以 c c ,用一个函数 u = b c {u}={bc} 来表示;而后计算另外一个函数 v = a + u v=a+u ;最后输出 J = 3 v J=3v ,这就是要计算的函数 J J 。这三步能够画成以下的计算图:在这里插入图片描述
先画三个变量 a , b , c a,b,c ,第一步就是计算 u = b c u=bc ,放个矩形框,它的输入是 b , c b,c ;接着仍是放个矩形框,进行第二步 v = a + u v=a+u ;最后一步仍是个矩形框,进行 J = 3 v J=3v

举个例子: a = 5 , b = 3 , c = 2 a=5, b=3, c=2 u = b c u=bc 就是 3 * 2 = 6;而 v = a + u v=a+u ,就是 5+6=11 J J 是 3 倍的 v v ,所以, J J = 3 × (5 + 3 × 2)。若是把它算出来,就获得33,实际上就是 J J 的值。

计算图的一个大优点是:当有不一样的或者一些特殊的输出变量时,例如上面例子中的 J J 和逻辑回归中准备优化的代价函数 J J ,用计算图来处理会很方便。从这个小例子中能够看出,经过一个从左向右(蓝色箭头)的过程,能够计算出 J J 的值。而为了计算导数,从右到左(红色箭头,和蓝色箭头的过程相反)的过程是用于计算导数最天然、最直观的方式。

四、使用计算图求导数

如何利用计算图来计算函数 J J 的导数呢?

先不急,来看个例子,下面用到的公式:

d J d u = d J d v d v d u \frac{dJ}{du}=\frac{dJ}{dv}\frac{dv}{du}

d J d b = d J d u d u d b \frac{dJ}{db}=\frac{dJ}{du}\frac{du}{db}

d J d a = d J d u d u d a \frac{dJ}{da}=\frac{dJ}{du}\frac{du}{da}

这是一个计算图,记录了整个流程:
在这里插入图片描述


假设计算 d J d v \frac{{dJ}}{{dv}} ,那要怎么算呢?若是你会微积分的话,就好说了,直接求导数没啥好说的;那么不会的话呢,也不用着急!这么看,好比要把这个 v v 值拿过来,改变一下,那么 J J 的值会怎么变呢?(是否是用上了上面提到的导数讲解 😃)

首先 J = 3 v J = 3v v = 11 v=11 J = 33 J=33 ,这是已知条件。若是让 v v 增长一点点,好比到11.001,那么 J = 3 v = 33.003 J = 3v = 33.003 ,这里 v v 增长了 0.001,而最终结果是 J J 上升了 0.003,也就是原来的 3 倍,因此 d J d v = 3 \frac{{dJ}}{{dv}}=3

为啥这么说?固然是由于对于任何 v v 的增量, J J 都会有 3 倍增量。因此有 J = 3 v J=3v ,推出 d J d v = 3 \frac{{dJ}}{{dv}} =3

吴恩达老师的手稿以下:
在这里插入图片描述


看另外一个例子, d J d a \frac{{dJ}}{da} 是多少呢?换句话说,若是提升 a a 的值, J J 的数值有什么影响?

变量 a = 5 a=5 ,增长到了 5.001,那么对 v v 的影响就是 a + u a+u ,以前 v = 11 v=11 ,如今变成 5.001 - 5 + 11 = 11.001 J J 就变成11.001 * 3 = 33.003,因此 a a 增长 0.001, J J 增长 0.003。那么增长 a a a a 的改变量会传播到计算图的最右边,因此 J J 最后是 33.003。因此 J J 的增量是 3 乘以 a a 的增量,也就意味着导数是 3,即 d J d a = 3 \frac{{dJ}}{da}=3

吴恩达老师的手稿以下:
在这里插入图片描述
要解释清楚这个计算过程,就会牵扯出链式法则,名字虽然挺厉害的,其实很简单。

首先 a a 增长了, v v 也会增长; v v 增长多少呢?这取决于 d v d a \frac{{dv}}{da} ;而后 v v 的增长致使 J J 也会增长。因此这在微积分里实际上叫链式法则,顾名思义,互相之间被链住了,一个变化都会变化。

那么怎么计算一个链式法则的求导呢?

其实不难,前面给了三个公式,这就是答案。经过分解的方法,把整个链式法则分解为几个小的链子,分别求导再相乘,就解出正确答案了。

经过改变一个变量来看另外一个变量的变化关系这种方法,咱们获得了 d J d v = 3 \frac{{dJ}}{{dv}} =3 d v d a = 1 \frac{{dv}}{da} =1 ,因此 d J d a = d J d v d v d a = 3 1 = 3 \frac{{dJ}}{da}=\frac{{dJ}}{{dv}} \frac{{dv}}{da}=3 * 1=3 ,即为所求。

下图表示了整个计算过程:
在这里插入图片描述


继续计算另外一条线的导数,也就是这个 u u ,那么 d J d u \frac{dJ}{du} 是多少呢?

经过和以前相似的计算,这里简单说一下。从 u = 6 u=6 出发,令 u u 增长到 6.001, v v 以前是 11,如今变成 6.001 - 6 + 11 = 11.001 J J 从 33 变成 33 * 3 = 33.003,因此 d J d u = 3 \frac{{dJ}}{du}= 3

u u 的分析很相似对 a 的分析,为啥这么说呢?实际上仍是计算, d J d u = d J d v d v d u \frac{{dJ}}{du}=\frac{{dJ}}{dv}\cdot \frac{{dv}}{du} ,又由于有 d J d v = 3 \frac{{dJ}}{dv} =3 d v d u = 1 \frac{{dv}}{du} = 1 ,最终算出的结果是 3 × 1 = 3 3×1=3 ,因此能够看出对 u u 的分析相似对 a 的分析。

吴恩达老师的手稿以下:
在这里插入图片描述


如今,来看最后一个例子,那么 d J d b \frac{{dJ}}{db} 呢?

事实上,使用微积分链式法则,这也能够写成乘积的形式,就是 d J d b = d J d u d u d b \frac{{dJ}}{db}=\frac{{dJ}}{du}\cdot \frac{{du}}{db}

b b 增长 0.001 变成 3.001 时, u = b c u=bc 就变成 3.001 * 2 = 6.002 u u 增长了 6.002 - 6 = 0.002,也就是 b b 的增长量的二倍,因此 d u d b = 2 \frac{{du}}{db} =2 。那么 d J d u \frac{{dJ}}{du} 是多少呢?在前面咱们已经弄清楚了,等于 3,因此这两部分相乘,可得 d J d b = 6 \frac{{dJ}}{db}= 6


其实还有另外一个例子,不过 c c b b 是比较类似的。通过计算你会发现 d J d c = d J d u d u d c = 3 × 3 \frac{{dJ}}{dc} =\frac{{dJ}}{du}\cdot \frac{{du}}{dc} = 3 \times 3 ,这个结果是 9。

吴恩达老师的手稿以下:
在这里插入图片描述
因此当计算全部这些导数时,最有效率的办法是从右到左计算,跟着这个红色箭头走,充分利用计算图的优点。特别是当第一次计算对 v v 的导数时,以后在计算对 a a 导数时,而后对 u u 的导数,最后是对 b b c c 的导数。

到这里,计算图求导数就完事了。这是一个计算图,也是一个流程图。是否是简单了好多,尤为是对 b b c c 的导数!!!

推荐阅读

参考文章

  • 吴恩达——《神经网络和深度学习》视频课程