Theano梯度故障转移扫描操作



在theano中实现深度网络使我能够从头开始精确控制我的层。我知道它不再受支持,但在我看来仍然有活跃的用途(至少来自我:->(。无论如何,我通过扫描操作注意到了一些与梯度计算相关的行为。

我有以下内部函数(RNN内部迭代步骤的一部分,如果需要,我可以提供(:

def iter_step(x_step, h):
...
return hidden, obj, est

我有一组用于计算梯度的参数h_paramso_paramse_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 (Subtensor{int64}.0) of the for{cpu,scan_fn} op is mathematically undefined. Depends on a shared variable

为什么会这样?我还不能调试-图形并没有断开,手动展开扫描可以提供良好的梯度。梯度计算应执行扫描操作。如果可以计算h(iter_step的第一个输出(上的梯度,为什么不计算扫描的类似输出上的梯度呢?

问题已经解决。上面的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。这似乎在所有情况下都有效。

最新更新