来自:http://deeplearning.net/software/theano/tutorial/gradients.html

Derivatives in Theano

一、计算梯度

现在,让我们使用theano来做稍微更复杂的任务:创建一个函数,用来计算表达式y 关于它的参数x的导数。我们将会用到宏 T.grad 。例如,我们可以计算  关于 的梯度。注意: .

下面就是用来计算这个梯度的代码:

  1. >>> from theano import pp
  2. >>> x = T.dscalar('x')
  3. >>> y = x ** 2
  4. >>> gy = T.grad(y, x)
  5. >>> pp(gy) # print out the gradient prior to optimization
  6. '((fill((x ** 2), 1.0) * 2) * (x ** (2 - 1)))'
  7. >>> f = function([x], gy)
  8. >>> f(4)
  9. array(8.0)
  10. >>> f(94.2)
  11. array(188.40000000000001)

在这个例子中,我们可以从pp(gy) 中看到我们在计算的符号梯度是正确的。 fill((x ** 2), 1.0) 意思是说创建一个和 x ** 2一样shape的矩阵,然后用1.0来填充。

note:该优化器简化了符号梯度的表达式,你可以深挖编译后的函数的内部属性来了解细节。

  1. pp(f.maker.fgraph.outputs[0])
  2. '(2.0 * x)'

在优化之后,在graph中只有一个 Apply节点,其输入是乘以2的。

我们同样可以计算复杂表达式的梯度,例如由上面定义的逻辑函数。结果显示逻辑函数的梯度为: .

该图是逻辑函数的梯度,x轴表示x的变化,y轴表示梯度  。

  1. >>> x = T.dmatrix('x')
  2. >>> s = T.sum(1 / (1 + T.exp(-x)))
  3. >>> gs = T.grad(s, x)
  4. >>> dlogistic = function([x], gs)
  5. >>> dlogistic([[0, 1], [-1, -2]])
  6. array([[ 0.25 , 0.19661193],
  7. [ 0.19661193, 0.10499359]])

通常来说,对于任何标量表达式, T.grad(s, w) 提供theano表达式来计算 。这种方式下,甚至对于有着许多输入的函数来说,theano可以用来高效的计算符号微分 (正如 T.grad 返回的表达式可以在编译期间进行优化)
automatic
differentiation
 有详细的描述关于符号微分的)。

note: T.grad 的第二个参数可以是一个列表,这种情况下,输出也同样是一个列表。在这两个列表中的顺序都是很重要的:输出列表的第
i 个元素是T.grad 的第一个参数关于第二个参数的列表的第
i 个元素的梯度。 T.grad 第一个参数必须是一个标量(其tensor
size 为1)。更多有关T.grad的参数的语义的信息和实现的细节,可以参考库的 this 部分。

在内部微分的工作的信息可以在更高级的教程 Extending Theano中找到。

二、计算Jacobian

在theano中,术语 Jacobian 指定为张量包含函数的输出关于输入的第一个偏导数。 (在数学中这就是所谓的Jacobian矩阵) Theano 实现宏theano.gradient.jacobian() 所需要的就是计算Jacobian。下面部分就是解释如何手动去完成它:

为了手动计算一些函数 y 关于一些参数 x 的Jacobian,我们需要使用 scan。即在y
中使用循环来遍历所有元素,然后计算
 y[i] 关于x 的梯度。

note:scan 是theano中一个通用的操作,可以以符号方式写出各种递归等式。然而生成一个符号循环是很难的(而且还需要为了性能而去优化它们)
,所以需要努力提升scan.的效果。在后面会接着说 scan 的。

  1. >>> x = T.dvector('x')
  2. >>> y = x ** 2
  3. >>> J, updates = theano.scan(lambda i, y,x : T.grad(y[i], x), sequences=T.arange(y.shape[0]), non_sequences=[y,x])
  4. >>> f = function([x], J, updates=updates)
  5. >>> f([4, 4])
  6. array([[ 8., 0.],
  7. [ 0., 8.]])

在该代码中所做的就是生成一个int类型的序列,通过使用T.arange来使得其中从0到 y.shape[0] 。然后我们对这个序列进行循环,然后在每一步,灭我们计算元素 y[i]关于x
的梯度。scan 可以自动的连接所有的这些列,生成一个对应于jacobian的矩阵。

note:在使用T.grad的时候记得也有一些陷阱的。 其中一个就是你没法和这样theano.scan(lambda y_i,x: T.grad(y_i,x), sequences=y, non_sequences=x)重写jacobin的上述表达式,,尽管从文档上看scan是可以的。原因在于 y_i 不再试x的函数了,而 y[i]仍然是。

三、计算Hessian

在theano中,术语Hessian 与数学上的概念没差:是一个矩阵,其中包含着标量输出和向量输入的函数的二阶偏导数。Theano 实现宏theano.gradient.hessian() 所要做的就是计算Hessian。下面的部分就是介绍如何手动完成。

你可以可jacobian一样相似的计算Hessian。唯一的差别在于,我们通过计算T.grad(cost,x)的jacobian来代替计算一些表达式y
的jacobian,所以计算的cost是标量的。

  1. >>> x = T.dvector('x')
  2. >>> y = x ** 2
  3. >>> cost = y.sum()
  4. >>> gy = T.grad(cost, x)
  5. >>> H, updates = theano.scan(lambda i, gy,x : T.grad(gy[i], x), sequences=T.arange(gy.shape[0]), non_sequences=[gy, x])
  6. >>> f = function([x], H, updates=updates)
  7. >>> f([4, 4])
  8. array([[ 2., 0.],
  9. [ 0., 2.]])

四、Jacobian乘以一个向量

有时候我们需要将算法表示成jacobinas乘以向量,或者向量乘以jacobinans。相比较于评估jacobian,然后做乘法,可以直接计算合适的结果从而避免对jacobian的实际计算。这可以带来明显的性能的提升。一个这样的算法可以在下面的文献中找到:

  • Barak A. Pearlmutter, “Fast Exact Multiplication by the Hessian”, Neural Computation, 1994

然而在实际中,我们想要theano能够自动的识别这些模式,不过以通常的方式来实现这样的优化是非常难的。所以,我们提供了特别的函数来应对这些问题:

R-operator

R
操作符是用来评估介于一个jacobian和一个向量之间的乘积的,即 .
该式子可以扩展成当x是一个矩阵,或者一个张量的形式,这种情况下,jacobian就变成了一个张量,然后乘积就变成了某种张量的积。因为在实际中,我们最后是需要计算权重矩阵这样的表达式的,theano支持这种操作的更通用形式。为了评估表达式y的R
操作,(关于x的),使用v乘以jacobian,你需要做类似下面的事情:

  1. >>> W = T.dmatrix('W')
  2. >>> V = T.dmatrix('V')
  3. >>> x = T.dvector('x')
  4. >>> y = T.dot(x, W)
  5. >>> JV = T.Rop(y, W, V)
  6. >>> f = theano.function([W, V, x], JV)
  7. >>> f([[1, 1], [1, 1]], [[2, 2], [2, 2]], [0,1])
  8. array([ 2., 2.])

实现Rop的操作列表List 。

L-operator

相似于R-操作L-操作 会计算一个行向量乘积,其数学上的形式为 。该L-操纵 同样支持通用的张量
(不只是向量)。相思的,它可以按照下面形式实现:

  1. >>> W = T.dmatrix('W')
  2. >>> v = T.dvector('v')
  3. >>> x = T.dvector('x')
  4. >>> y = T.dot(x, W)
  5. >>> VJ = T.Lop(y, W, v)
  6. >>> f = theano.function([v,x], VJ)
  7. >>> f([2, 2], [0, 1])
  8. array([[ 0., 0.],
  9. [ 2., 2.]])

note:v,
在L操作和R操作中是不同的。对于L操作来说,该 v 需要有着和输出一样的shape,然而,R操作需要和输入参数一样的shape。更进一步说,这两个操作的结果是不同的。L操作的结果有着和输入参数一样的shape,而R操作有着和输出一样的shape。

五、Hessian乘以一个向量

如果你需要计算Hessian
乘以一个向量,你就需要用到上面定义的操作,它们通常比实际计算准确的Hessian,然后计算乘积更高效。因为Hessian矩阵的对称性,你可以用两种方式得到相同的结果,虽然这些选择也许会有不同的性能。因此,我们建议在使用它们之前先,
先对它们进行分析:

  1. >>> x = T.dvector('x')
  2. >>> v = T.dvector('v')
  3. >>> y = T.sum(x ** 2)
  4. >>> gy = T.grad(y, x)
  5. >>> vH = T.grad(T.sum(gy * v), x)
  6. >>> f = theano.function([x, v], vH)
  7. >>> f([4, 4], [2, 2])
  8. array([ 4., 4.])

或者使用R操作:

  1. >>> x = T.dvector('x')
  2. >>> v = T.dvector('v')
  3. >>> y = T.sum(x ** 2)
  4. >>> gy = T.grad(y, x)
  5. >>> Hv = T.Rop(gy, x, v)
  6. >>> f = theano.function([x, v], Hv)
  7. >>> f([4, 4], [2, 2])
  8. array([ 4., 4.])

备注:

  • grad 函数是符号化的工作的:它接受和返回theano变量。
  • grad 可以和宏相比较,因为它可以重复使用
  • 标量损失只能被直接通过grad进行处理。数组可以通过重复应用的形式来解决
  • 内建的函数可以高效的计算向量乘以jacobian和向量乘以Hessian
  • 优化需要高效的计算全jacobian和Hessian矩阵,以及jacobian乘以向量。

参考资料:

[1]官网:http://deeplearning.net/software/theano/tutorial/gradients.html

Theano2.1.6-基础知识之在thenao中的求导的更多相关文章

  1. Linux基础知识第九讲,linux中的解压缩,以及软件安装命令

    目录 Linux基础知识第九讲,linux中的解压缩,以及软件安装命令 一丶Linux Mac Windows下的压缩格式简介 2.压缩以及解压缩 3.linux中的软件安装以及卸载 1.apt进行安 ...

  2. js基础知识温习:Javascript中如何模拟私有方法

    本文涉及的主题虽然很基础,在很多人眼里属于小伎俩,但在JavaScript基础知识中属于一个综合性的话题.这里会涉及到对象属性的封装.原型.构造函数.闭包以及立即执行表达式等知识. 公有方法 公有方法 ...

  3. 深入理解python(一)python语法总结:基础知识和对python中对象的理解

    用python也用了两年了,趁这次疫情想好好整理下. 大概想法是先对python一些知识点进行总结,之后就是根据python内核源码来对python的实现方式进行学习,不会阅读整个源码,,,但是应该会 ...

  4. vue2.0基础知识,及webpack中vue的使用

    ## 基础指令 ## [v-cloak]{         Display:none;     }     <p v-cloak>xx{{msg}}xx</p> //解决闪烁问 ...

  5. Nginx基础知识之————RTMP模块中的中HLS专题(翻译文档)

    一.在Nginx配置文件的RTMP模块中配置hls hls_key_path /tmp/hlskeys; 提示错误信息: nginx: [emerg] the same path name " ...

  6. js基础知识温习:js中的对象

    在JavaScript中对象是一个无序属性的集合,其属性可以包含基本值.对象或者函数. 对象最简单的创建方式 JavaScript中创建对象最简单的方式就是创建一个Object对象的实例,然后再添加属 ...

  7. Python 基础知识(持续更新中)

    内置数据类型:     整型     浮点型     字符串     布尔值     空值 None     列表 list     元组 tuple     字典 dict     集合 set   ...

  8. es2015(es6)基础知识整理(更新中...)

    1.let let可以声明块级作用域变量 'use strict'; if (true) { let app = 'apple'; } console.log(app); //外面是访问不到app的 ...

  9. Android基础知识之Manifest文件中的用户权限元素

    原文:http://android.eoe.cn/topic/android_sdk 分任务原文链接一:http://developer.android.com/guide/topics/manife ...

随机推荐

  1. 揣摩实现一个ioc容器需要做的事情

    思路: ioc框架的核心就是管理bean的生命周期,bean的生命周期包括:创建,使用,销毁. 创建 容器在创建一个bean的实例之前必须要解决以下问题:第一个问题: 创建bean的信息如何提供给你容 ...

  2. [转载]DBA的特质第一部分:技术

    本文转自http://www.searchdatabase.com.cn/showcontent_84379.htm 支持原创.尊重原创,分享知识! 在本系列文章中,笔者将谈一谈数据库管理员(DBA) ...

  3. ASP.NET MVC 拓展ViewResult实现word文档下载

      最近项目中有同事用到word文档导出功能,遇到了一些导出失败问题,帮其看了下解决问题的同事,看了下之前的代码发现几个问题: 代码编写不规范,word导出功能未收口 重复代码导出都是 实现逻辑比较复 ...

  4. 描述Linux下文件删除的原理(计时3分钟)

    Linux是通过link的数量来控制文件删除的,只有当一个文件不存在任何link的时候,这个文件才会被删除.一般来说,每个文件都有2个link计数器:i_count 和 i_nlink. i_coun ...

  5. android 关于appcompat v7出错问题与解决

    1.appcompat_v7:应用兼容包,V7说的是版本7,即android2.1,这个兼容包支持2.1版本以上系统2.最近谷歌官方将兼容jar包与某些资源文件单独拿出来建立了一个android工程, ...

  6. hw 要的是螺丝钉

    日前突然接到华为HR的电话,叫我去面试。本来我的工作和工资收入等各方面在本地也还算可以,没有想要跳槽。但是本着去看看有没有更好机会的想法就去了。  9:30到了现场后,在那里等了很久,一个考官上来问了 ...

  7. aircack-ng抓握手包

    1.关闭影响进程 airmon-ng check kill 将要进入监听模式的无线网卡断开它已连接的AP 2.查看无线网卡的名字 ifconfig ,例如 wlan0 3.进入监听模式: airmon ...

  8. DevOps Workshop 研发运维一体化第一场(微软亚太研发集团总部)

    准备了近两周,写了大量的操作手册,设计了大量的动手实验场景,终于在中关村的微软大厦完成了两天的DevOps培训. 最初报名160人,按照之前的培训经验,一般能到一半就不错了,没想到这次现场登记人员就超 ...

  9. python log

    python的日志模块为logging,它可以将我们想要的信息输出保存到一个日志文件中. # cat log import logging logging.debug('This is debug m ...

  10. ZBrush中怎样对遮罩进行反选

    通过对ZBrush的学习,我们知道了如何手动创建遮罩,手动创建遮罩相对来说是最简单有效的方法,在某些特定的使用场合会起到事半功倍的效果.创建遮罩我们可以结合Ctrl键在物体保持编辑的状态下来执行,您可 ...