Theano入门笔记1:Theano中的Graph Structure
译自:http://deeplearning.net/software/theano/extending/graphstructures.html#graphstructures
理解Theano计算原理的关键
建议阅读时间:10分钟
如果不明白内在运行机制,Theano代码的调试工作并非易事。本章就简单介绍了Theano的内部工作机理。
编写Theano code的第一步便是用符号占位符(或符号变量)书写数学表达式。表达式中的操作符包括+,-,**,sum(),tanh()等。所有这些操作符都有内部的ops。一个op表示在某种类型输入上的某种计算产生某种类型的输出,可以理解为常见编程语言中的函数定义。
Theano将符号的数学运算表示为图(Graphs)。这些图是由连接点构成,连接点(interconnected nodes)包括:Apply Node, Variable Node, 以及 Op Node。Apply Node表示将一个op应用到某些variable上。很重要的一点是,能够区分用op表示的计算的定义及其用apply表示的在实际数据上的应用。数据类型用Type的实例表示。以下是一段代码及其对应的图来展示这段代码的结构。从而可以更好的将这些细节联系在一起。


箭头表示对所指向的Python对象的引用。蓝色矩形框表示Apply /node,红色圆角矩形表示Variable Node,绿色圈表示Ops,紫色框表示类型。我们创建Variables,然后应用Apply ops到这些变量,从而得到更多Variables,我们构建二部有向无环图。Variables指向Apply Nodes,这表示函数应用,即通过变量的owner域来产生这些变量。这些Apply Node通过他们的input和output域,轮流指向他们的输入和输出Variables。Apply实例也包含outputs的引用列表,但是本文中的这幅图并没有考虑。
由于x与y两个输入的符号变量并不是其他运算的结果,所以他们的owner域都指向的是None。如果有些符号变量是其他一些运算的结果,则它的ownerfield应该像z一样指向的是另外一个蓝色框。值得注意的是,Apply实例的output域指向的是z,z的owner域指向的是Apply实例,所以是一个双向箭头。
遍历图(Traversing the Graph)
使用owner域,从输出(计算的结果)开始遍历到输入。以下面的code为例来说明:

若输入:type(y.owner),得到结果:<class 'theano.gof.graph.Apply'>,也就是说它是Apply Node,连接了op变量和输入来得到这个output。我们可以打印这个用于得到y的op的名称:

从而可知,用elementwise multiplication运算得到了y。这种Multiplication是两个输入之间的:

值得注意的是,第二个输入并不是我们所想象的2。这是因为2首先被broadcasted成为一个和x同样大小的矩阵,然后再做multiplication的运算。这种变化使用的是DimShuffle这种op:

从这个图结构,我们可以很容易理解,这种自动微分是如何进行的,以及符号关系如何被优化以获得更稳定的性能。
图结构(Graph Structure)
本节罗列了Theano内部计算图中常用的结构类型,包括:Apply, Constant, Op, Variable以及Type。
Apply. Apply Node是Theano计算图中的一种内部节点。与Variable Node不同,Apply Node通常并不能直接被终端用户所操作,可以通过Variable的owner域被访问。一个Apply Node是Apply类的实例。它表示了一个Op应用再一个或多个input上,其中每个input都是一个Variable。通常来讲,每个Op都负责知道如何从一个input Varible的列表获得Apply Node。因此,一个Apply Node可以通过调用Op.make_node(*inputs),从一个Op和一个input Variable的列表获得。与Python语言相比,一个Apply Node是一个Theano版本的函数调用,而Op则是Theano版本的函数定义。一个Apply实例包括以下三个重要的域:(1)op:Op决定了使用哪种函数或变形。(2)inputs:Variable列表,表示函数的参数。(3)outputs:Variable列表,表示函数的返回值。通过调用gof.Apply(op,inputs,outputs)来创建Apply实例。
Op.Theano中一个Op定义了在某些类型inputs上的某种类型的运算,从而产生某些类型的输出。这对应于大多数编程语言中的函数定义。从一个input Variable的列表以及一个Op,我们可以构建Apply node表示将该Op应用到这些inputs上。能够理解Op与Apply之间的区别是非常重要的:Op相当于一个函数的定义,而Apply相当于一个函数的调用和使用。如果你想用Theano的结构来解释Python语言,代码是这样的def f(x):...将产生一个名称为f的Op,而代码a=f(x)或g(f(x),5)将产生一个涉及到名为f的Op的Apply Node。
Type.Theano中的Type表示的是对可能的数据对象的约束集合。这些约束允许Theano来对C代码进行裁剪,以能够处理它们,并能对计算图进行优化。举例来说,theano.tensor包中的irow类型定义了下述对数据的约束,也就是说具有irow类型的Variable需要包含:(1)必须是一个numpy.ndarray类型的实例(即isinstance(x,numpy.ndarray));(2)必须是一个32位整数类型的array(str(x.dtype)=='int32');(3)必须是1*N大小(len(x.shape)==2 and x.shape[0]==1)。知道了这些约束,Theano可以在产生例如加法这样的C代码的过程中声明正确的数据类型,包含维度上的正确循环次数。值得注意的是Theano的Type并不等同于Python的type或类。实际上,Theano中irow和dmatrix本质上都是numpy.ndarray类型,按该类型来做运算和存储数据,但是Theano的Type确实有些不同之处。例如,dmatrix的约束结合是:(1)必须是一个numpy.ndarray类型的实例(isinstance(x,numpy.ndarray));(2)必须是一个64位浮点数的array(str(x.dtype)=='float64');(3)必须是大小为M*N的,对M或N没有限制(len(x.shape)==2)。这些约束是与irow的不同。有些情况theano Type可以完全对应到Python类型的情况,如这里的double对应Python的float。除非特别指明,我们说的Type都是指Theano Type。
Variable.Variable是Theano中主要的数据结构。我们操作的符号输入是Variables,我们使用各种各样的符号在这些inputs得到的结果也是Variables。举个例子来说明:import theano x=theano.tensor.ivector() y=-x。其中x与y都是Variables,也就是Variable类的实例。这里x与y的类型都是theano.tensor.ivector。不像x,y是经过计算得到的Variable。y是运算的输出Variable,x对应的是它的输入Variable。计算本身用另外一种Node,即Apply Node来表示,可以通过y.owner来访问。更具体来讲,一个Variable是Theano中的一个基本结构,它表示的是在计算过程中的某个点。通常来讲,它是Variable类的或它的子类的实例。一个Variable r包含以下四个重要的域:(1)type: 运算中Variable所采用的值的类型;(2)owner:要么是None要么是Apply Node(当Variable是output时);(3)index:r在owner.outputs中的索引owner.outputs[index]=r,若owner=None即可忽略;(4)name: 在pretty-printing以及debugging中使用的字符串。Variable有一个特殊的子类:Constant。
Constant.Constant是一个具有额外域的Variable,该域为data,仅有一次设置机会。当在计算图(Computation Graph)中用作Op的input时,假设该input总会取data域中的值。进一步讲,假设Op在任何情况下都不会改变这种输入。这就意味着Constant适合于好多优化:C代码中的constant内联,constant folding等。一个Constant不必要通过function函数来指定一个输入Variable的列表。如果这样做的话会带来异常。
图结构扩展(Graph Structures Extension)
当我们开始编译Theano函数时,我们也计算一些额外的信息。本节描述了一些可用信息的一部分。图在编译之初被cloned,所以在编译过程中任何改动并不会影响图结构。每个变量接受一个称为clients的新域。这个域是对图中每个使用该Variable的位置的引用列表。若该长度为0,也就意味着该Variable没有被使用。该变量被使用的每个位置用一个二元组表示。有两种类型的二元组:(1)第一个元素为Apply Node,第二个元素为index:var.clients[*][0].inputs[index]或fgraph.outputs[index]就是这个变量;(2)第一个元素为字符串Output,意思是函数的输出为该变量,第二个元素为index:var.clients[*][0].inpus[index]或fgraph.outputs[index]就是这个变量。
自动微分(Automatic Differentiation)
一旦有了图结构,自动计算微分变得容易。唯一要做的事情就是调用tensor.grad(),该方法从输出开始回溯到输入,通过所有的Apply Nodes来遍历图,apply nodes是那些定义了图中要做哪些运算的节点。对于每个这样的Apply Node,它的op定义了如何计算该node的输出对输入的梯度。值得注意的是若一个op并没有提供这种信息,那么认为梯度没有定义。为了得到整个图的输出对输入的梯度,需要使用链式法则对这些梯度进行组合。该tutorial的下一章会对微分做详细介绍。
优化(Optimization)
当编译一个Theano function时,我们需要给theano.function提供的一个图结构(从输出Variable,我们可以遍历整个图,到达输入Variable。)。整个图结构不但展示了如何从输入计算得到输出,而且给我们提供了对计算进行改进的可能。theano的优化方式时识别并用其它以更快的速度或更稳定的产生相同结果的pattern替换其中的一些pattern。优化也能探测相似的子图,从而确保同一值不被计算两次,或者重构部分图以适应到GPU版本。例如,Theano中一个简单的优化时用x来代替pattern xy/y。更详尽的介绍见文档。
Theano入门笔记1:Theano中的Graph Structure的更多相关文章
- Theano入门笔记2:scan函数等
1.Theano中的scan函数 目前先弱弱的认为:相当于symbolic的for循环吧,或者说计算图上的for循环,也可以用来替代repeat-until. 与scan相比,scan_checkpo ...
- Theano学习笔记:Theano的艰辛安装体验
http://www.cnblogs.com/hanahimi/p/4127026.html
- 母函数入门笔记(施工中…
定义:对于一个数列,它的母函数(即生成函数)为 为了对这个准确求值,我们设 举一个简单的例子 例1 对于数列 他的生成函数为 ,那么应用一下等比数列求和公式 这里由于 所以当时 那么 例 ...
- Theano 学习笔记(一)
Theano 学习笔记(一) theano 为什么要定义共享变量? 定义共享变量的原因在于GPU的使用,如果不定义共享的话,那么当GPU调用这些变量时,遇到一次就要调用一次,这样就会花费大量时间在数据 ...
- Ruby小白入门笔记之 <Gemfile 文件>
因为初学Ruby,四处查资料无果,才来的贴出亲自试过的操作,覆盖整个个人入门笔记博客中,故所有的操作,都以最明了的方式阐述,当你创建完一个新的Rails应用后,你发现JAVA中我们可以编写maven聚 ...
- Theano学习笔记(一)——代数
标量相加 import theano.tensor as T from theano import function x = T.dscalar('x') y = T.dscalar('y') z = ...
- Theano入门——CIFAR-10和CIFAR-100数据集
Theano入门——CIFAR-10和CIFAR-100数据集 1.CIFAR-10数据集介绍 CIFAR-10数据集包含60000个32*32的彩色图像,共有10类.有50000个训练图像和1000 ...
- Theano Graph Structure
Graph Structure Graph Definition theano's symbolic mathematical computation, which is composed of: A ...
- Theano入门神经网络(三)
附录一个:Keras学习随笔 http://blog.csdn.net/niuwei22007/article/details/49045909 参考 <Python Machine Learn ...
随机推荐
- 2、在NET中实现多线程
1.System.Threading命名空间 System.Threading命名空间提供了使得可以多线程编程的类和接口 其中 (1)Thread类构成了C#多线程编程的支柱,他用于创建并控制线程 ( ...
- ASP.NET WebApi 学习与实践系列(1)---如何创建 WebApi
写在前面 最近在做一个app的时候发现需要写后台服务.所以,在考虑是使用webapi还是使用webserver来写这个后台服务的时候.爱纠结的我,最后还是选择了使用webapi来写这个后台服务. 原因 ...
- Vert.x 异步访问数据库 MySQL
Vert.x提供异步访问数据库的API,数据库操作是一个耗时操作,使用传统的同步模型,容易阻塞线程,导致整体性能下降,因此我们对于数据库操作,需要使用Vert.x提供的异步API. Vert.x提供的 ...
- MVC Filter的使用方法
相信对权限过滤大家伙都不陌生 用户要访问一个页面时 先对其权限进行判断并进行相应的处理动作 在webform中 最直接也是最原始的办法就是 在page_load事件中所有代码之前 先执行一个权限判断的 ...
- 2019 苏宁控股java面试笔试题 (含面试题解析)
本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.苏宁等公司offer,岗位是Java后端开发,因为发展原因最终选择去了苏宁,入职一年时间了,也成为了面试官,之 ...
- 2019 昆仑万维java面试笔试题 (含面试题解析)
本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.昆仑万维等公司offer,岗位是Java后端开发,因为发展原因最终选择去了昆仑万维,入职一年时间了,也成为了面 ...
- Java之路---Day02
2019-10-17-20:21:22 顺序结构: 概述:顺序执行,根据编写的顺序,从上到下执行语句 判断语句1-if: if语句第一种格式: if(关系表达式){ 语句体; } 执行流程: 1.首先 ...
- onActivityResult方法的使用
转发自:https://blog.csdn.net/hacker_crazy/article/details/78345450 在进行界面间的跳转和传递数据的时候,我们有的时候要获得跳转之后界面传递回 ...
- Eclipse中run as run on server和run as java application
一.run java application (作为Java应用程序运行)是运行 java main方法 run on server是启动一个web 应用服务器 二.两者的区别: Eclipse中 ...
- Java 之 NOSQL
一.什么是 NOSQL NoSQL(NoSQL = Not Only SQL),意即“不仅仅是SQL”,是一项全新的数据库理念,泛指非关系型的数据库. 随着互联网web2.0网站的兴起,传统的关系数据 ...