Theano - 如何覆盖部分操作图的梯度
Theano - how to override gradient for part of op graph
我手头有一个相当复杂的模型。该模型有多个具有 线性 结构的部分:
y = theano.tensor.dot(W,x) + b
我想构建一个优化器,它使用自定义规则来计算所有 线性 结构的梯度,同时保持其他操作不变。 为我的模型的所有线性部分覆盖梯度操作的最简单方法是什么?最好不需要编写新的操作。
所以,我花了一些时间为 Theano 开发 PR( 截至 2017 年 1 月 13 日未合并 已经合并),它使用户能够部分覆盖theano.OpFromGraph
实例的梯度。覆盖是用符号图完成的,因此您仍然可以获得 theano 优化的全部好处。
典型用例:
- 数值安全考虑
- Rescale/clipping渐变
- 像黎曼自然梯度这样的专业梯度程序
要制作具有覆盖渐变的 Op:
- 制作所需的计算图
- 为 Op
的梯度创建一个 OpFromGraph 实例(或 python 函数)
- 将 OfG 实例作为您的 Op,并设置
grad_overrides
参数
- 调用 OfG 实例来构建您的模型
定义一个 OpFromGraph 就像编译一个 theano 函数,有一些区别:
- 不支持
updates
和 givens
(截至 2017 年 1 月)
- 你得到一个符号运算而不是一个数值函数
示例:
'''
This creates an atan2_safe Op with smoothed gradient at (0,0)
'''
import theano as th
import theano.tensor as T
# Turn this on if you want theano to build one large graph for your model instead of precompiling the small graph.
USE_INLINE = False
# In a real case you would set EPS to a much smaller value
EPS = 0.01
# define a graph for needed Op
s_x, s_y = T.scalars('xy')
s_darg = T.scalar(); # backpropagated gradient
s_arg = T.arctan2(s_y, s_x)
s_abs2 = T.sqr(s_x) + T.sqr(s_y) + EPS
s_dx = -s_y / s_abs2
s_dy = s_x / s_abs2
# construct OfG with gradient overrides
# NOTE: there are unused inputs in the gradient expression,
# however the input count must match, so we pass
# on_unused_input='ignore'
atan2_safe_grad = th.OpFromGraph([s_x, s_y, s_darg], [s_dx, s_dy], inline=USE_INLINE, on_unused_input='ignore')
atan2_safe = th.OpFromGraph([s_x, s_y], [s_arg], inline=USE_INLINE, grad_overrides=atan2_safe_grad)
# build graph using the new Op
x, y = T.scalar(), T.scalar()
arg = atan2_safe(x, y)
dx, dy = T.grad(arg, [x, y])
fn = th.function([x, y], [dx, dy])
fn(1., 0.) # gives [-0.0, 0.99099]
fn(0., 0.) # gives [0.0, 0.0], no more annoying nan!
注意:theano.OpFromGraph
很大程度上仍处于试验阶段,可能会出现错误。
我手头有一个相当复杂的模型。该模型有多个具有 线性 结构的部分:
y = theano.tensor.dot(W,x) + b
我想构建一个优化器,它使用自定义规则来计算所有 线性 结构的梯度,同时保持其他操作不变。 为我的模型的所有线性部分覆盖梯度操作的最简单方法是什么?最好不需要编写新的操作。
所以,我花了一些时间为 Theano 开发 PR( 截至 2017 年 1 月 13 日未合并 已经合并),它使用户能够部分覆盖theano.OpFromGraph
实例的梯度。覆盖是用符号图完成的,因此您仍然可以获得 theano 优化的全部好处。
典型用例:
- 数值安全考虑
- Rescale/clipping渐变
- 像黎曼自然梯度这样的专业梯度程序
要制作具有覆盖渐变的 Op:
- 制作所需的计算图
- 为 Op 的梯度创建一个 OpFromGraph 实例(或 python 函数)
- 将 OfG 实例作为您的 Op,并设置
grad_overrides
参数 - 调用 OfG 实例来构建您的模型
定义一个 OpFromGraph 就像编译一个 theano 函数,有一些区别:
- 不支持
updates
和givens
(截至 2017 年 1 月) - 你得到一个符号运算而不是一个数值函数
示例:
'''
This creates an atan2_safe Op with smoothed gradient at (0,0)
'''
import theano as th
import theano.tensor as T
# Turn this on if you want theano to build one large graph for your model instead of precompiling the small graph.
USE_INLINE = False
# In a real case you would set EPS to a much smaller value
EPS = 0.01
# define a graph for needed Op
s_x, s_y = T.scalars('xy')
s_darg = T.scalar(); # backpropagated gradient
s_arg = T.arctan2(s_y, s_x)
s_abs2 = T.sqr(s_x) + T.sqr(s_y) + EPS
s_dx = -s_y / s_abs2
s_dy = s_x / s_abs2
# construct OfG with gradient overrides
# NOTE: there are unused inputs in the gradient expression,
# however the input count must match, so we pass
# on_unused_input='ignore'
atan2_safe_grad = th.OpFromGraph([s_x, s_y, s_darg], [s_dx, s_dy], inline=USE_INLINE, on_unused_input='ignore')
atan2_safe = th.OpFromGraph([s_x, s_y], [s_arg], inline=USE_INLINE, grad_overrides=atan2_safe_grad)
# build graph using the new Op
x, y = T.scalar(), T.scalar()
arg = atan2_safe(x, y)
dx, dy = T.grad(arg, [x, y])
fn = th.function([x, y], [dx, dy])
fn(1., 0.) # gives [-0.0, 0.99099]
fn(0., 0.) # gives [0.0, 0.0], no more annoying nan!
注意:theano.OpFromGraph
很大程度上仍处于试验阶段,可能会出现错误。