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

尝试计算函数\(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)的更多相关文章
- Java泛型详解,史上最全图文详解!
泛型在java中有很重要的地位,无论是开源框架还是JDK源码都能看到它. 毫不夸张的说,泛型是通用设计上必不可少的元素,所以真正理解与正确使用泛型,是一门必修课. 一:泛型本质 Java 泛型(gen ...
- 史上最全webview详解
本文来自:http://www.jianshu.com/users/320f9e8f7fc9/latest_articles WebView在现在的项目中使用的频率应该还是非常高的. 我个人总觉得HT ...
- RocketMQ4.3.x 史上配置最全详解,没有之一
最近整理了RocketMQ的配置参数一部分参考rocketmq技术内幕,一部分自己看源码猜测,有表述不清楚或不正确请广大网友指正 这里应该是最全的配置解析了,搞了2天.以后查询就好办了,仅此贡献给广大 ...
- C++入门教程:大白话讲解,新手基础篇⭐⭐⭐(附源码及详解、视频课程资料推荐)
目录 C++教程 前言 视频教程 文字教程 集成开发环境(IDE) 编译器 工作原理 学习指南 入门书籍 进阶书籍 算法.竞赛书籍 教程 标准构建 程序解释 第一个C++程序--"hello ...
- PHP 基础篇 - PHP 中 DES 加解密详解
一.简介 DES 是对称性加密里面常见一种,全称为 Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法.密钥长度是64位(bit),超过位数密钥被忽略.所谓对 ...
- Vue.js 源码分析(八) 基础篇 依赖注入 provide/inject组合详解
先来看看官网的介绍: 简单的说,当组件的引入层次过多,我们的子孙组件想要获取祖先组件的资源,那么怎么办呢,总不能一直取父级往上吧,而且这样代码结构容易混乱.这个就是这对选项要干的事情 provide和 ...
- Vue.js 源码分析(七) 基础篇 侦听器 watch属性详解
先来看看官网的介绍: 官网介绍的很好理解了,也就是监听一个数据的变化,当该数据变化时执行我们的watch方法,watch选项是一个对象,键为需要观察的数据名,值为一个表达式(函数),还可以是一个对象, ...
- PCIe基础篇(二)、协议详解
一个完整的PCIe协议体系结构包括应用层.事务层(Transaction Layer).数据链路层(Data Link Layer)和物理层(Physical Layer).其中,应用层由用户需要自行 ...
- 史上最详细“截图”搭建Hexo博客并部署到Github
http://jingyan.baidu.com/article/d8072ac47aca0fec95cefd2d.html 大家也搭建过博客,很多时候,按着教程来做就可以了,但是我当时为了搭建Hex ...
- 转 史上最详细的Hadoop环境搭建
GitChat 作者:鸣宇淳 原文:史上最详细的Hadoop环境搭建 关注公众号:GitChat 技术杂谈,一本正经的讲技术 [不要错过文末活动哦] 前言 Hadoop在大数据技术体系中的地位至关重要 ...
随机推荐
- MySQL8.0默认加密连接方式
Mysql8.0开始默认采用新的caching_sha2_password的身份验证方式,常规老接口会因此无法连接数据库. 为继续使用老的身份验证方式,需显式指定身份验证方式为 mysql_nativ ...
- nginx配置解决跨域访问
场景:前后的分离项目,前端vue框架,打包后放在Tomcat里访问,端口是8080,后端服务端口8058.访问前端项目时,调用后端接口报跨域. 后端环境 正常访问端口8058 经过nginx配置(文末 ...
- H5-geolocation学习
geolocation--定位 PC--IP地址 精度比较低 IP库 Chrome -> Google 手机--GPS window.navigator.geolocation 单次 getCu ...
- mybatis-plus使用心得
mybatis-plus是一款基于mybatis的持久层框架,在mybatis上只做增强不做改变.基本使用流程: 导入依赖坐标: <dependency> <groupId>c ...
- nginx虚拟机及热部署(在线升级)
实现热部署(在线升级): 热部署方案一 (有弊端,不利于回滚) 查看nginx版本及源编译差数: /usr/local/nginx/sbin/nginx -V 预编译/ 编译/ 安装:在预编译之前,先 ...
- P1144 最短路计数 题解
Problem 考察算法:拓扑排序 + \(DP\) + \(Dijkstra\). 题目简述 给出一个无向无权图,问从顶点 \(1\) 开始,到其他每个点的最短路有几条. 思路 先求出 \(1\) ...
- P9580 「Cfz Round 1」Wqs Game 题解
题目链接 挺好的博弈论题,这是一个跟官方题解不太一样的做法. 遇到这种组合游戏可以先考虑逆推胜负,把握一下规律,我们先从一个区间的胜负判断开始入手. 考察区间中最后一个数字的从属关系,如果它属于弈,因 ...
- OpenWrt主题在菜单中不显示
问题: 路径中有对应的主题,但是make menuconfig中不显示 原因: 需要建立软连接 1. 在路径 SDK-DR232-20221220/package/feeds/luci 中运行 ls ...
- 关于Linux性能监控之CPU篇详解
http://news.chinaunix.net/opensource/2013/0228/2654519.shtml # vmstat 1 procs -----------memory----- ...
- vivo 网络端口安全建设技术实践
作者:vivo 互联网安全团队 - Peng Qiankun 随着互联网业务的快速发展,网络攻击的频率和威胁性也在不断增加,端口是应用通信中的门户,它是数据进出应用的必经之路,因此端口安全也逐渐成为了 ...