Theano 梯度扫描操作失败
Posted
技术标签:
【中文标题】Theano 梯度扫描操作失败【英文标题】:Theano gradients failing over scan operation 【发布时间】:2020-06-27 01:30:08 【问题描述】:在 theano 中实现深度网络让我可以从头开始精确控制我的层。我知道它不再受支持,但在我看来仍然在积极使用(至少从我这里:->)。无论如何,我注意到一些与通过扫描操作计算梯度有关的行为。
我有以下内部函数(RNN 内部迭代步骤的一部分,如果需要,我可以提供):
def iter_step(x_step, h):
...
return hidden, obj, est
我有一组用于计算梯度的参数h_params
、o_params
、e_params
:
h, o, e = iter_step(x_step, h)
hidden_grads = T.grad(T.sum(h), h_params)
obj_grads = T.grad(T.sum(o), o_params)
est_grads = T.grad(T.sum(est), e_params)
一切都很好。我添加一个扫描操作
[h_n, obj_n, x_n], _ = theano.scan(
fn=iter_step,
sequences=[x],
outputs_info=[T.as_tensor_variable(np.zeros(model.h_shape), model.h.dtype),
None,
None],
)
评估很好,但是在相同参数上计算梯度现在是个问题:
# Works
h_n0 = theano.function([], h_n)()
# Fails
h_n_grads = T.grad(T.sum(h_n), h_params)
---------------------------------------------------------------------------
NullTypeGradError Traceback (most recent call last)
<ipython-input-32-0d7c8a65d265> in <module>
----> 1 h_n_grads = T.grad(T.sum(h_n), h_params)
/usr/local/lib/python3.6/dist-packages/theano/gradient.py in grad(cost, wrt, consider_constant, disconnected_inputs, add_names, known_grads, return_disconnected, null_gradients)
609 if null_gradients == 'raise':
610 raise NullTypeGradError("tensor.grad encountered a NaN. " +
--> 611 rval[i].type.why_null)
612 else:
613 assert null_gradients == 'return'
NullTypeGradError: tensor.grad encountered a NaN. This variable is Null because the grad method for input 4 (Subtensorint64.0) of the forcpu,scan_fn op is mathematically undefined. Depends on a shared variable
这是为什么?我还无法调试 - 图形未断开连接,手动展开扫描可提供良好的渐变。梯度计算应该通过扫描操作进行。如果可以计算 h(iter_step 的第一个输出)上的梯度,为什么不能在扫描的模拟输出上计算?
【问题讨论】:
【参考方案1】:问题解决了。上面的iter_step
包含一个采样步骤,类似于
def sample(self, mu, logSigma):
global SEED
srng = T.shared_randomstreams.RandomStreams(seed=SEED)
dev = srng.normal((self.batch_size, self.n_latent[-1]))
z = mu + T.exp(0.5 * logSigma) * dev
return z
通过此计算得出的梯度无法通过scan
操作保留下来。分离样本中的所有参数依赖项仍然不起作用。最终奏效的是在dev
中创建偏差并将其作为non_sequences
之一在扫描中传递,如
[h_n, obj, x],inner_updates = theano.scan(
fn=iter_step,
sequences=[x_in],
outputs_info=[T.as_tensor_variable(np.zeros(self.h_shape), self.h.dtype),
None,
None],
non_sequences=[T.as_tensor_variable(self.srng.normal((self.batch_size, self.n_latent[-1])), self.h.dtype)],
)
我知道为什么这个scan
上的渐变会失败,而即使使用randomstreams.RandomStreams
对象也可以进行简单的扫描操作。我会深入研究一下。
总结:如果您的发行版允许,请使用重新参数化技巧,传入白化偏差,预先参数化为 non_sequences
。这似乎适用于所有情况。
【讨论】:
以上是关于Theano 梯度扫描操作失败的主要内容,如果未能解决你的问题,请参考以下文章
Theano / Pytorch / Tensorflow 可以自动计算以下梯度吗?
theano-windows学习笔记二十——LSTM理论及实现