Theano学习-梯度计算
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-operator 与 R-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 和向量乘以 Hessian5
正在优化有效的计算完整的 Jacobian 和 Hessian 矩阵以及 Jacobian 乘以向量.
Theano学习-梯度计算的更多相关文章
- Theano 学习笔记(一)
Theano 学习笔记(一) theano 为什么要定义共享变量? 定义共享变量的原因在于GPU的使用,如果不定义共享的话,那么当GPU调用这些变量时,遇到一次就要调用一次,这样就会花费大量时间在数据 ...
- Softmax 损失-梯度计算
本文介绍Softmax运算.Softmax损失函数及其反向传播梯度计算, 内容上承接前两篇博文 损失函数 & 手推反向传播公式. Softmax 梯度 设有K类, 那么期望标签y形如\([0, ...
- 实现属于自己的TensorFlow(二) - 梯度计算与反向传播
前言 上一篇中介绍了计算图以及前向传播的实现,本文中将主要介绍对于模型优化非常重要的反向传播算法以及反向传播算法中梯度计算的实现.因为在计算梯度的时候需要涉及到矩阵梯度的计算,本文针对几种常用操作的梯 ...
- 多类 SVM 的损失函数及其梯度计算
CS231n Convolutional Neural Networks for Visual Recognition -- optimization 1. 多类 SVM 的损失函数(Multicla ...
- 吴裕雄 python 机器学习——集成学习梯度提升决策树GradientBoostingRegressor回归模型
import numpy as np import matplotlib.pyplot as plt from sklearn import datasets,ensemble from sklear ...
- TensorFlow 学习(八)—— 梯度计算(gradient computation)
maxpooling 的 max 函数关于某变量的偏导也是分段的,关于它就是 1,不关于它就是 0: BP 是反向传播求关于参数的偏导,SGD 则是梯度更新,是优化算法: 1. 一个实例 relu = ...
- theano学习指南5(翻译)- 降噪自动编码器
降噪自动编码器是经典的自动编码器的一种扩展,它最初被当作深度网络的一个模块使用 [Vincent08].这篇指南中,我们首先也简单的讨论一下自动编码器. 自动编码器 文献[Bengio09] 给出了自 ...
- IMPLEMENTING A GRU/LSTM RNN WITH PYTHON AND THEANO - 学习笔记
catalogue . 引言 . LSTM NETWORKS . LSTM 的变体 . GRUs (Gated Recurrent Units) . IMPLEMENTATION GRUs 0. 引言 ...
- 用Theano学习Deep Learning(三):卷积神经网络
写在前面的废话: 出了托福成绩啦,本人战战兢兢考了个97!成绩好的出乎意料!喜大普奔!撒花庆祝! 傻…………寒假还要怒学一个月刷100庆祝个毛线………… 正题: 题目是CNN,但是CNN的具体原理和之 ...
随机推荐
- mysql互换表中两列数据
在开发过程中,有时由于业务等需要把一个表中的两列数据进行交换. 解决方案 使用update命令,这完全得益于MySQL SQL命令功能的强大支持. 表格中原来数据类似如下: select * from ...
- 关于mysql的Fetch Time 和 Duration Time
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt411 Stackowerflow 上关于这两个时间有人这样解释 Fetch ...
- Spring详解(五)------AspectJ 实现AOP
上一篇博客我们引出了 AOP 的概念,以及 AOP 的具体实现方式.但是为什么要这样实现?以及提出的切入点表达式到底该怎么理解? 这篇博客我们通过对 AspectJ 框架的介绍来详细了解. 1.什么是 ...
- main方法和args参数
第一次接触java常常奇怪main方法和其参数有什么用.我们只知道main方法是程序入口,其实main方法同时也是一个可以手动调用的静态方法. 我们可以利用main方法写简单的一个递归程序 publi ...
- angular之scope.$watch
某“大神”挖了个陨石坑,我于是乎似懂非懂的接手,玩了一个月angular.现在项目告一段落,暂别了繁重的重复性工作,可以开始回顾.认真的折腾下之前犹抱琵琶的angular. angular吸引人的特性 ...
- web程序员标准环境之DreamWeaver【推荐】
Adobe Dreamweaver,简称"DW",中文名称 "梦想编织者",是美国MACROMEDIA公司开发的集网页制作和管理网站于一身的所见即所得网页编辑器 ...
- 解决 SQL 注入的另类方法
本文是翻译,版权归原作者所有 原文地址(original source):https://bitcoinrevolt.wordpress.com/2016/03/08/solving-the-prob ...
- Swing-布局管理器之FlowLayout(流式布局)-入门
FlowLayout应该是Swing布局管理器学习中最简单.最基础的一个.所谓流式,就是内部控件像水流一样,从前到后按顺序水平排列,直到达到容器的宽度时跳转到第二行.既然是水平排列,那么就存在三种基本 ...
- 201521123026 《java程序设计》第七周学习总结
1. 本章学习总结 以你喜欢的方式(思维导图或其他)归纳总结集合相关内容. 2. 书面作业 Q1.ArrayList代码分析 1.1 解释ArrayList的contains源代码 答: public ...
- 201521123025 《Java程序设计》第1周学习总结
1. 本章学习总结 (1)对JAVA的历史有了初步了解 (2)学会安装JDK和设置JAVA_HOME,PATH,CLASSPATH环境变量 (3)范围:JDK>JRE>JVM 2. 书面作 ...