1. 计算梯度

创建一个函数 \(y\) ,并且计算关于其参数 \(x\) 的微分. 为了实现这一功能,将使用函数 \(T.grad\) . 例如:计算 \(x^2\) 关于参数 \(x\) 的梯度. 注:$ d(x^2)/d(x) = 2 * x$.

以下就是计算该梯度的 Python 代码:

import numpy
import theano
import theano.tensor as T
from theano import pp
x = T.dscalar('x')
y = x ** 2
gy = T.grad(y, x)
pp(gy)
f = theano.function([x], gy)
print(f(4)) #print 8
print(numpy.allclose(f(94.2), 188.4)) #print True
print(pp(f.maker.fgraph.outputs[0])) #print (TensorConstant{2.0} * x)

我们能从 \(pp(gy)\) 看出计算出的符号梯度是正确的.

同时也能计算复杂表达式的梯度,例如 \(Logistic\) 函数的梯度.

\(Logistic\) 函数: \(s(x) = \frac{1}{1 + e^{-x}}\)

其导数: \(ds(x)/d(x) = s(x) * (1 - s(x))\)

import numpy
import theano
import theano.tensor as T
x = T.dmatrix('x')
s = T.sum(1 / (1 + T.exp(-x)))
gs = T.grad(s, x)
dlogistic = theano.function([x], gs)
print(dlogistic([[0, 1], [-1, -2]]))
#print [[ 0.25 0.19661193]
[ 0.19661193 0.10499359]]

总的来说,对于标量表达式 \(s\) , Theano 提供的方法 \(T.grad(s, w)\) 即为计算 \(\frac{\partial s}{\partial w}\).

补充: \(T.grad\) 的第二个参数可以是一个列表 (list),此时输出也为一个列表 . 不管是参数还是输出,列表的顺序是很重要的,输出列表中的第 \(i\) 个元素,就是 \(T.grad\) 中第一个参数关于第二个列表参数中第 \(i\) 个元素的导数. \(T.grad\) 的第一个参数必须是个标量.

2. 计算Jacobian

Theano 中,Jacobian 表示输出函数关于其输入的一阶偏导数(在数学中,就称为雅可比矩阵). Theano 中使用 \(theano.gradient.jacobian()\) 来计算需要的 Jacobian . 接下来说明怎样手动执行.

我们使用 \(scan\) 来手动计算函数 \(y\) 关于参数 \(x\) 的 Jacobian ,就是循环 \(y\) 的元素计算 \(y[i]\) 关于参数 \(x\) 的梯度.

补充: \(scan\) 在 Theano 中是一个通用操作, 允许以符号方式写入循环方程. 创建符号循环是一个艰巨的任务,目前正在努力提高 \(scan\) 的性能.

import theano
import theano.tensor as T
x = T.dvector('x')
y = x ** 2
J, updates = theano.scan(lambda i, y, x: T.grad(y[i], x), sequences = T.arange(y.shape[0]), non_sequences=[y, x])
f = theano.function([x], J, updates = updates)
print(f([4, 4]))
#print [[ 8. 0.]
[ 0. 8.]]

在此代码中,使用 \(T.arange\) 产生从 \(0\) 到 \(y.shape[0]\) 的 \(int\) 序列. 当循环序列时,计算元素 \(y[i]\) 关于参数 \(x\) 的梯度. \(scan\) 自动连接所有的行,生成一个对应于 Jacobian 的矩阵.

补充:关于 \(T.grad\) 的使用,有一些陷阱. 例如,不能将代码中的 Jacobian 表达式改为 \(theano.scan(lambda y_i, x: T.grad(y_i, x), sequences = y, non_sequences = x )\) ,即使从 \(scan\) 的文档上看似乎是可以的. 不能改写的原因在于 \(y_i\) 不再是关于 \(x\) 的函数,而 \(y[i]\) 仍然是.

3. 计算 Hessian

Theano 中,术语 Hessian 和数学中的概念一样:是标量输出函数关于向量输入的二阶偏微分矩阵. Theano 中使用 \(theano.gradient.hessian()\) 函数计算 Hessian . 接下来解释怎样手动执行.

手动计算 Hessian 和手动计算 Jacobian 类似,唯一的不同就是用 \(T.grad(cost, x)\) 代替 Jacobian 中的函数 \(y\), \(cost\) 通常是一个标量.

import theano
import theano.tensor as T
x = T.dvector('x')
y = x ** 2
cost = y.sum()
gy = T.grad(cost, x)
H, updates = theano.scan(lambda i, gy, x: T.grad(gy[i], x), sequences = T.arange(gy.shape[0]), non_sequences=[gy, x])
f = theano.function([x], H, updates = updates)
print(f([4, 4]))
#print [[ 2. 0.]
[ 0. 2.]]

4. Jacobian 乘以向量

在解释算法的过程中,有时我们需要表示 Jacobian 乘以向量,或者是向量乘以 Jacobian . 与先评估 Jacobian 再做乘积相比,目前有许多方式能直接计算所需结果从而避免实际的 Jacobian 评估. 这能带来显著的性能提升,具体参考下文:

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

原则上我们希望 Theano 能为我们自动识别这些模式,实际上,以通用的方式进行优化是很困难的.

因此,提供了特殊的函数专用于这些任务.

R-operator

R-operator 用于评估 Jacobian 和向量之间的乘积,写作: \(\frac{\partial f(x)}{\partial x}v\). 这个公式能够被扩展,即使 \(x\) 是一个矩阵或者张量,此时 Jacobian 成为了一个张量而其乘积成为了张量的乘积. 因此在实际中,我们需要根据权重矩阵计算这些表达式, Theano 支持这种更通用的表示形式. 为了评估表达式 \(y\) 关于参数 \(x\) 的 R-operator,将 Jacobian 与 \(v\) 右乘,你需要做下面的事:

import theano
import theano.tensor as T
W = T.dmatrix('W')
V = T.dmatrix('V')
x = T.dvector('x')
y = T.dot(x, W)
JV = T.Rop(y, W, V)
f = theano.function([W, V, x], JV)
print(f([[1, 1], [1, 1]], [[2, 2], [2, 2]], [0, 1]))
#print [ 2. 2.]

L-operator

R-operator 类似, L-operator是计算行向量与 Jacobian 的乘积. 数学形式为: $ v\frac{\partial f(x)}{\partial x}$ . 同样的,可以通过下面的程序执行:

import theano
import theano.tensor as T
W = T.dmatrix('W')
V = T.dmatrix('V')
x = T.dvector('x')
y = T.dot(x, W)
VJ = T.Lop(y, W, V)
f = theano.function([V, x], VJ)
print(f([2, 2], [0, 1]))
#print [[ 0. 0.]
[ 2. 2.]]

补充:\(v\) 的评估,L-operatorR-operator 是不一样的. 对 L-operator 而言, \(v\) 需要和输出有同样的形状;而对 R-operator 需要和输出参数有同样的形状. 进一步说,两种运算符的结果是不一样的. L-operator 的结果与输入参数形状相同;而 R-operator 的结果具有与输出类似的形状.

5. Hessian 乘以向量

假如你需要计算 Hessian 乘以一个向量,你可以使用上面定义的算子直接计算,这比先计算精确的 Hessian ,再计算乘积更有效. 由于 Hessian 矩阵的对称性,你有两种方式得到同样的结果,尽管这两种方式可能展现出不同的性能. 下面给出这两种方式:

  • 1
import theano
import theano.tensor as T
x = T.dvector('x')
v = T.dvector('v')
y = T.sum(x ** 2)
gy = T.grad(y, x)
vH = T.grad(T.sum(gy * v), x)
f = theano.function([x, v], vH)
print(f([4, 4], [2, 2]))
#print [ 4. 4.]
  • 2使用 R-operator
import theano
import theano.tensor as T
x = T.dvector('x')
v = T.dvector('v')
y = T.sum(x ** 2)
gy = T.grad(y, x)
Hv = T.Rop(gy, x, v)
f = theano.function([x, v], Hv)
print(f([4, 4], [2, 2]))
#print [ 4. 4.]

6. 指示

  • 1

    \(grad\) 函数以符号方式工作:接收与返回都是 Theano 变量

  • 2

    \(grad\) 可以比作宏,因为它可以重复使用

  • 3

    标量函数只能被 \(grad\) 直接处理,矩阵能够通过重复应用来处理

  • 4

    内置函数能有效的计算向量乘以 Jacobian 和向量乘以 Hessian

  • 5

    正在优化有效的计算完整的 JacobianHessian 矩阵以及 Jacobian 乘以向量.

Theano学习-梯度计算的更多相关文章

  1. Theano 学习笔记(一)

    Theano 学习笔记(一) theano 为什么要定义共享变量? 定义共享变量的原因在于GPU的使用,如果不定义共享的话,那么当GPU调用这些变量时,遇到一次就要调用一次,这样就会花费大量时间在数据 ...

  2. Softmax 损失-梯度计算

    本文介绍Softmax运算.Softmax损失函数及其反向传播梯度计算, 内容上承接前两篇博文 损失函数 & 手推反向传播公式. Softmax 梯度 设有K类, 那么期望标签y形如\([0, ...

  3. 实现属于自己的TensorFlow(二) - 梯度计算与反向传播

    前言 上一篇中介绍了计算图以及前向传播的实现,本文中将主要介绍对于模型优化非常重要的反向传播算法以及反向传播算法中梯度计算的实现.因为在计算梯度的时候需要涉及到矩阵梯度的计算,本文针对几种常用操作的梯 ...

  4. 多类 SVM 的损失函数及其梯度计算

    CS231n Convolutional Neural Networks for Visual Recognition -- optimization 1. 多类 SVM 的损失函数(Multicla ...

  5. 吴裕雄 python 机器学习——集成学习梯度提升决策树GradientBoostingRegressor回归模型

    import numpy as np import matplotlib.pyplot as plt from sklearn import datasets,ensemble from sklear ...

  6. TensorFlow 学习(八)—— 梯度计算(gradient computation)

    maxpooling 的 max 函数关于某变量的偏导也是分段的,关于它就是 1,不关于它就是 0: BP 是反向传播求关于参数的偏导,SGD 则是梯度更新,是优化算法: 1. 一个实例 relu = ...

  7. theano学习指南5(翻译)- 降噪自动编码器

    降噪自动编码器是经典的自动编码器的一种扩展,它最初被当作深度网络的一个模块使用 [Vincent08].这篇指南中,我们首先也简单的讨论一下自动编码器. 自动编码器 文献[Bengio09] 给出了自 ...

  8. IMPLEMENTING A GRU/LSTM RNN WITH PYTHON AND THEANO - 学习笔记

    catalogue . 引言 . LSTM NETWORKS . LSTM 的变体 . GRUs (Gated Recurrent Units) . IMPLEMENTATION GRUs 0. 引言 ...

  9. 用Theano学习Deep Learning(三):卷积神经网络

    写在前面的废话: 出了托福成绩啦,本人战战兢兢考了个97!成绩好的出乎意料!喜大普奔!撒花庆祝! 傻…………寒假还要怒学一个月刷100庆祝个毛线………… 正题: 题目是CNN,但是CNN的具体原理和之 ...

随机推荐

  1. Python 的经典入门书籍有哪些?

    是不是很多人跟你说,学Python开发就该老老实实地找书来看,再配合死命敲代码?电脑有了,软件也有了,心也收回来了?万事俱备,唯独只欠书籍?没找到到合适的书籍?可以看看这些. 1.Python基础教程 ...

  2. TCP/IP协议栈模型

    OSI七层模型介绍: 下面4层(物理层.数据链路层.网络层和传输层)主要提供数据传输和交换功能,即以节点到节点之间的通信为主:第4层作为上下两部分的桥梁,是整个网络体系结构中最关键的部分:而上3层(会 ...

  3. java内存管理(堆、栈、方法区)

    java内存管理 简介 首先我们要了解我们为什么要学习java虚拟机的内存管理,不是java的gc垃圾回收机制都帮我们释放了内存了吗?但是在写程序的过程中却也往往因为不懂内存管理而造成了一些不容易察觉 ...

  4. NAT集群部署solo之session server

    author:JevonWei 版权声明:原创作品 使用Nginx做代理服务器,部署solo,使用session server做会话黏滞 拓扑图 环境 tomcatA 172.16.253.108 t ...

  5. wowza拉流和推流接口备忘

    拉流接口地址:https://www.wowza.com/docs/stream-management-query-examples# 推流接口地址:https://www.wowza.com/doc ...

  6. Java面试系列之HashMap大扫盲汇总

    PS:整理的稍微有点急,不足之处,望各路道友指正,List相关可以查看前一篇随笔! HashMap的工作原理是近年来常见的Java面试题,几乎每个Java程序员都知道HashMap,都知道哪里要用Ha ...

  7. WebServices 之 WSDL

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt234 一,WSDL概述 WebServices Description La ...

  8. js变量以及其作用域详解

    详见: http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp73   一.变量的类型  Javascript和Java.C这些语言不同 ...

  9. (一)Builder(建造者)模式

    我们一般在构建javabean的对象的时候通常有三种写法: 1.直接通过构造函数传参的方式设置属性,这种方法如果属性过多的话会让构造函数十分臃肿,而且不能灵活的选择只设置某些参数. 2.采用重叠构造区 ...

  10. css编写注意事项(不定时更新)

    CSS的编写是需要积累的,而一个好的css编写习惯对我们将来的成长是非常有利的,我会把我平时看到的或者遇到的会不定时的更新到这里,不时翻一下,但求有所进步. 如果各位看官也有看法和建议,评论下,我也会 ...