计算图

可以说,一个神经网络的计算,都是按照前向或反向传播过程组织的。首先计算出一个新的网络的输出(前向过程),紧接着进行一个反向传输操作。后者用来计算出对应的梯度或导数。计算图解释了为什么用这种方式组织这些计算过程。在这个博客中,将举一个例子说明计算图是什么。让举一个比逻辑回归更加简单的,或者说不那么正式的神经网络的例子。

尝试计算函数\(J\),\(J\)是由三个变量\(a,b,c\)组成的函数,这个函数是\(\text{3(a}+\text{bc)}\) 。计算这个函数实际上有三个不同的步骤,首先是计算 \(b\) 乘以 \(c\),把它储存在变量\(u\)中,因此\({u}={bc}\);

然后计算\(v=a+u\);最后输出\(J=3v\),这就是要计算的函数\(J\)。可以把这三步画成如下的计算图,先在这画三个变量\(a,b,c\),第一步就是计算\(u=bc\),在这周围放个矩形框,它的输入是\(b,c\),接着第二步\(v=a+u\),最后一步\(J=3v\)。

举个例子: \(a=5,b=3,c=2\) ,\(u=bc\)就是6,\(v=a+u\) ,就是5+6=11。\(J\)是3倍的 ,因此。即\(3×(5+3×2)\)。如果把它算出来,实际上得到33就是\(J\)的值。

当有不同的或者一些特殊的输出变量时,例如本例中的\(J\)和逻辑回归中想优化的代价函数\(J\),因此计算图用来处理这些计算会很方便。从这个小例子中可以看出,通过一个从左向右的过程,可以计算出\(J\)的值。为了计算导数,从右到左(红色箭头,和蓝色箭头的过程相反)的过程是用于计算导数最自然的方式。

概括一下:计算图组织计算的形式是用蓝色箭头从左到右的计算,让看看下一个博客中如何进行反向红色箭头(也就是从右到左)的导数计算。

使用计算图求导数(Derivatives with a Computation Graph)

在上一个博客中,看了一个例子使用流程计算图来计算函数J。现在清理一下流程图的描述,看看如何利用它计算出函数\(J\)的导数。

下面用到的公式:

\(\frac{dJ}{du}=\frac{dJ}{dv}\frac{dv}{du}\) , \(\frac{dJ}{db}=\frac{dJ}{du}\frac{du}{db}\) , \(\frac{dJ}{da}=\frac{dJ}{du}\frac{du}{da}\)

这是一个流程图:

假设要计算\(\frac{{dJ}}{{dv}}\),那要怎么算呢?好,比如说,要把这个\(v\)值拿过来,改变一下,那么\(J\)的值会怎么变呢?

所以定义上\(J = 3v\),现在\(v=11\),所以如果让\(v\)增加一点点,比如到11.001,那么\(J =3v =33.003\),所以这里\(v\)增加了0.001,然后最终结果是\(J\)上升到原来的3倍,所以\(\frac{{dJ}}{{dv}}=3\),因为对于任何 \(v\) 的增量\(J\)都会有3倍增量,而且这类似于在上一个博客中的例子,有\(f(a)=3a\),然后推导出\(\frac{{df}(a)}{{da}}= 3\),所以这里有\(J=3v\),所以\(\frac{{dJ}}{{dv}} =3\),这里\(J\)扮演了\(f\)的角色,在之前的博客里的例子。

在反向传播算法中的术语,看到,如果想计算最后输出变量的导数,使用最关心的变量对\(v\)的导数,那么就做完了一步反向传播,在这个流程图中是一个反向步骤。

来看另一个例子,\(\frac{{dJ}}{da}\)是多少呢?换句话说,如果提高\(a\)的数值,对\(J\)的数值有什么影响?

好,看看这个例子。变量\(a=5\),让它增加到5.001,那么对v的影响就是\(a+u\),之前\(v=11\),现在变成11.001,从上面看到现在\(J\) 就变成33.003了,所以看到的是,如果让\(a\)增加0.001,\(J\)增加0.003。那么增加\(a\),是说如果把这个5换成某个新值,那么\(a\)的改变量就会传播到流程图的最右,所以\(J\)最后是33.003。所以J的增量是3乘以\(a\)的增量,意味着这个导数是3。

要解释这个计算过程,其中一种方式是:如果改变了\(a\),那么也会改变\(v\),通过改变\(v\),也会改变\(J\),所以\(J\)值的净变化量,当提升这个值(0.001),当把\(a\)值提高一点点,这就是\(J\)的变化量(0.003)。

首先a增加了,\(v\)也会增加,\(v\)增加多少呢?这取决于\(\frac{{dv}}{da}\),然后\(v\)的变化导致\(J\)也在增加,所以这在微积分里实际上叫链式法则,如果\(a\)影响到\(v\),\(v\)影响到\(J\),那么当让\(a\)变大时,\(J\)的变化量就是当改变\(a\)时,\(v\)的变化量乘以改变\(v\)时\(J\)的变化量,在微积分里这叫链式法则。

从这个计算中看到,如果让\(a\)增加0.001,\(v\)也会变化相同的大小,所以\(\frac{{dv}}{da}= 1\)。事实上,如果代入进去,之前算过\(\frac{{dJ}}{{dv}} =3\),\(\frac{{dv}}{da} =1\),所以这个乘积3×1,实际上就给出了正确答案,\(\frac{{dJ}}{da} = 3\)。

这张小图表示了如何计算,\(\frac{{dJ}}{{dv}}\)就是\(J\)对变量\(v\)的导数,它可以帮助计算\(\frac{{dJ}}{da}\),所以这是另一步反向传播计算。

现在想介绍一个新的符号约定,当编程实现反向传播时,通常会有一个最终输出值是要关心的,最终的输出变量,真正想要关心或者说优化的。在这种情况下最终的输出变量是J,就是流程图里最后一个符号,所以有很多计算尝试计算输出变量的导数,所以输出变量对某个变量的导数,就用\(dvar\)命名,所以在很多计算中需要计算最终输出结果的导数,在这个例子里是\(J\),还有各种中间变量,比如\(a、b、c、u、v\),当在软件里实现的时候,变量名叫什么?可以做的一件事是,在python中,可以写一个很长的变量名,比如\({dFinalOutputvar}\_{dvar}\),但这个变量名有点长,就用\(dJ\_dvar\),但因为一直对\(dJ\)求导,对这个最终输出变量求导。这里要介绍一个新符号,在程序里,当编程的时候,在代码里,就使用变量名\(dvar\),来表示那个量。

好,所以在程序里是\(dvar\)表示导数,关心的最终变量\(J\)的导数,有时最后是\(L\),对代码中各种中间量的导数,所以代码里这个东西,用\(dv\)表示这个值,所以\(dv=3\),的代码表示就是\(da=3\)。

好,所以通过这个流程图完成部分的后向传播算法。

清理出一张新的流程图,回顾一下,到目前为止,一直在往回传播,并计算\(dv=3\),再次,\(dv\)是代码里的变量名,其真正的定义是\(\frac{{dJ}}{{dv}}\)。发现\(da=3\),再次,\(da\)是代码里的变量名,其实代表\(\frac{{dJ}}{da}\)的值。

大概手算了一下,两条直线怎么计算反向传播。

好,继续计算导数,看看这个值\(u\),那么\(\frac{dJ}{du}\)是多少呢?通过和之前类似的计算,现在从\(u=6\)出发,如果令\(u\)增加到6.001,那么\(v\)之前是11,现在变成11.001了,\(J\) 就从33变成33.003,所以\(J\) 增量是3倍,所以\(\frac{{dJ}}{du}= 3\)。对\(u\)的分析很类似对a的分析,实际上这计算起来就是\(\frac{{dJ}}{dv}\cdot \frac{{dv}}{du}\),有了这个,可以算出\(\frac{{dJ}}{dv} =3\),\(\frac{{dv}}{du} = 1\),最终算出结果是\(3×1=3\)。

所以还有一步反向传播,最终计算出\(du=3\),这里的\(du\)当然了,就是\(\frac{{dJ}}{du}\)。

现在,仔细看看最后一个例子,那么\(\frac{{dJ}}{db}\)呢?想象一下,如果改变了\(b\)的值,想要然后变化一点,让\(J\) 值到达最大或最小,那么导数是什么呢?这个\(J\)函数的斜率,当稍微改变\(b\)值之后。事实上,使用微积分链式法则,这可以写成两者的乘积,就是\(\frac{{dJ}}{du}\cdot \frac{{du}}{db}\),理由是,如果改变\(b\)一点点,所以\(b\)变化比如说3.001,它影响J的方式是,首先会影响\(u\),它对\(u\)的影响有多大?好,\(u\)的定义是\(b\cdot c\),所以\(b=3\)时这是6,现在就变成6.002了,对吧,因为在的例子中\(c=2\),所以这告诉\(\frac{{du}}{db}= 2\)当让\(b\)增加0.001时,\(u\)就增加两倍。所以\(\frac{{du}}{db} =2\),现在想\(u\)的增加量已经是\(b\)的两倍,那么\(\frac{{dJ}}{du}\)是多少呢?已经弄清楚了,这等于3,所以让这两部分相乘,发现\(\frac{{dJ}}{db}= 6\)。

好,这就是第二部分的推导,其中想知道 \(u\) 增加0.002,会对\(J\) 有什么影响。实际上\(\frac{{dJ}}{du}=3\),这告诉u增加0.002之后,\(J\)上升了3倍,那么\(J\) 应该上升0.006,对吧。这可以从\(\frac{{dJ}}{du}= 3\)推导出来。

如果仔细看看这些数学内容,会发现,如果\(b\)变成3.001,那么\(u\)就变成6.002,\(v\)变成11.002,然后\(J=3v=33.006\),对吧?这就是如何得到\(\frac{{dJ}}{db}= 6\)。

为了填进去,如果反向走的话,\(db=6\),而\(db\)其实是Python代码中的变量名,表示\(\frac{{dJ}}{db}\)。

不会很详细地介绍最后一个例子,但事实上,如果计算\(\frac{{dJ}}{dc} =\frac{{dJ}}{du}\cdot \frac{{du}}{dc} = 3 \times 3\),这个结果是9。

不会详细说明这个例子,在最后一步,可以推出\(dc=9\)。

所以这个博客的要点是,对于那个例子,当计算所有这些导数时,最有效率的办法是从右到左计算,跟着这个红色箭头走。特别是当第一次计算对\(v\)的导数时,之后在计算对\(a\)导数就可以用到。然后对\(u\)的导数,比如说这个项和这里这个项:

可以帮助计算对\(b\)的导数,然后对\(c\)的导数。

所以这是一个计算流程图,就是正向或者说从左到右的计算来计算成本函数J,可能需要优化的函数,然后反向从右到左计算导数。如果不熟悉微积分或链式法则,知道这里有些细节讲的很快,但如果没有跟上所有细节,也不用怕。在下一个博客中,会再过一遍。在逻辑回归的背景下过一遍,并给介绍需要做什么才能编写代码,实现逻辑回归模型中的导数计算。

神经网络基础篇:史上最详细_详解计算图(Computation Graph)的更多相关文章

  1. Java泛型详解,史上最全图文详解!

    泛型在java中有很重要的地位,无论是开源框架还是JDK源码都能看到它. 毫不夸张的说,泛型是通用设计上必不可少的元素,所以真正理解与正确使用泛型,是一门必修课. 一:泛型本质 Java 泛型(gen ...

  2. 史上最全webview详解

    本文来自:http://www.jianshu.com/users/320f9e8f7fc9/latest_articles WebView在现在的项目中使用的频率应该还是非常高的. 我个人总觉得HT ...

  3. RocketMQ4.3.x 史上配置最全详解,没有之一

    最近整理了RocketMQ的配置参数一部分参考rocketmq技术内幕,一部分自己看源码猜测,有表述不清楚或不正确请广大网友指正 这里应该是最全的配置解析了,搞了2天.以后查询就好办了,仅此贡献给广大 ...

  4. C++入门教程:大白话讲解,新手基础篇⭐⭐⭐(附源码及详解、视频课程资料推荐)

    目录 C++教程 前言 视频教程 文字教程 集成开发环境(IDE) 编译器 工作原理 学习指南 入门书籍 进阶书籍 算法.竞赛书籍 教程 标准构建 程序解释 第一个C++程序--"hello ...

  5. PHP 基础篇 - PHP 中 DES 加解密详解

    一.简介 DES 是对称性加密里面常见一种,全称为 Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法.密钥长度是64位(bit),超过位数密钥被忽略.所谓对 ...

  6. Vue.js 源码分析(八) 基础篇 依赖注入 provide/inject组合详解

    先来看看官网的介绍: 简单的说,当组件的引入层次过多,我们的子孙组件想要获取祖先组件的资源,那么怎么办呢,总不能一直取父级往上吧,而且这样代码结构容易混乱.这个就是这对选项要干的事情 provide和 ...

  7. Vue.js 源码分析(七) 基础篇 侦听器 watch属性详解

    先来看看官网的介绍: 官网介绍的很好理解了,也就是监听一个数据的变化,当该数据变化时执行我们的watch方法,watch选项是一个对象,键为需要观察的数据名,值为一个表达式(函数),还可以是一个对象, ...

  8. PCIe基础篇(二)、协议详解

    一个完整的PCIe协议体系结构包括应用层.事务层(Transaction Layer).数据链路层(Data Link Layer)和物理层(Physical Layer).其中,应用层由用户需要自行 ...

  9. 史上最详细“截图”搭建Hexo博客并部署到Github

    http://jingyan.baidu.com/article/d8072ac47aca0fec95cefd2d.html 大家也搭建过博客,很多时候,按着教程来做就可以了,但是我当时为了搭建Hex ...

  10. 转 史上最详细的Hadoop环境搭建

    GitChat 作者:鸣宇淳 原文:史上最详细的Hadoop环境搭建 关注公众号:GitChat 技术杂谈,一本正经的讲技术 [不要错过文末活动哦] 前言 Hadoop在大数据技术体系中的地位至关重要 ...

随机推荐

  1. 记一次基于 PowerShell 的 Git 自动化部署 Java 多服务实践

    前言 有这么一个自动化部署的需求,凑巧 git 还直接建立在测试服务器上,部署后可以直接在测试服务器上演示 步骤 建立 Git 仓库 与一般的 Git 部署一样,区别是需要添加 --bare 开关,这 ...

  2. CompletableFuture异步优化代码

    CompletableFuture异步编排优化代码 我们在项目开发中,有可能遇到一个接口需要调用N个服务的接口.比如用户请求获取订单信息,需要调用用户信息.商品信息.物流信息等接口,最后再汇总数据统一 ...

  3. 一文搞懂深度信念网络!DBN概念介绍与Pytorch实战

    本文深入探讨了深度信念网络DBN的核心概念.结构.Pytorch实战,分析其在深度学习网络中的定位.潜力与应用场景. 关注TechLead,分享AI与云服务技术的全维度知识.作者拥有10+年互联网服务 ...

  4. CF B. Gardener and the Array

    B. Gardener and the Array 思路:只要找到一个c他的每一位均在除了它的集合中出现过即可 这题T了2发,用来multiset,注意multiset大的时间复杂度是O(K + lo ...

  5. JavaScript:用户代理检测:通过浏览器识别平台、操作系统等(Windows, Mac, iOS,iPad等)

    客户端检测经常用的方法:能力检测.怪癖检测和用户代理检测. 能力检测:在写代码前先检测浏览器的能力. 怪癖检测:实际上是浏览器现存的bug. 用户代理检测:通过检测用户代理字符串来识别浏览器. 一般优 ...

  6. QT(5)-QHeaderView

    @ 目录 1 说明 2 函数 2.1 级联调整大小 2.2 默认对齐方式 2.3 count() 2.4 表头默认单元格大小 2.5 hiddenSectionCount() 2.6 分区显示和隐藏 ...

  7. Visual Studio vs2010到2022各个版本的的永久激活密钥

    前言 以下密钥均收集于网络,但均可以正常激活 VS2022专业版和企业版的密钥 Visual Studio 2022 Pro(专业版) TD244-P4NB7-YQ6XK-Y8MMM-YWV2J Vi ...

  8. 彻底搞懂CAP理论(电商系统)

    1.理解CAP CAP是 Consistency.Availability.Partition tolerance三个词语的缩写,分别表示一致性.可用性.分区容忍性. 下边我们分别来解释: 为了方便对 ...

  9. 开发现代化的.NetCore控制台程序:(3)将nuget包发布到GitHubPackages

    前言 上一篇文章已经把项目模板的nuget包发布到了 nuget 的官方源了,其实还可以发布到其他源,比如 GitHub ,本文记录一下发布到 GitHub Packages 的过程. 注意:本文建立 ...

  10. 【.NET】多线程:自动重置事件与手动重置事件的区别

    在多线程编程中,如果每个线程的运行不是完全独立的.那么,一个线程执行到某个时刻需要知道其他线程发生了什么.嗯,这就是所谓线程同步.同步事件对象(XXXEvent)有两种行为: 1.等待.线程在此时会暂 ...