使用Theano定义相对于子张量的梯度

9
我有一个关于Theano的概念性简单问题,但我一直没有找到答案(坦率地说,尽管我花了很多时间看教程,但我仍然不太明白Theano中共享变量的工作原理)。
我正在尝试实现一个“反卷积网络”;具体来说,我有一个三维输入张量(每个输入都是二维图像)和一个四维编码器张量;对于第i个输入,codes[i]表示一组码字,这些码字一起编码输入i。
我一直在努力弄清楚如何在码字上进行梯度下降。以下是我的代码的相关部分:
idx = T.lscalar()
pre_loss_conv = conv2d(input = codes[idx].dimshuffle('x', 0, 1,2),
                       filters = dicts.dimshuffle('x', 0,1, 2),
                       border_mode = 'valid')
loss_conv = pre_loss_conv.reshape((pre_loss_conv.shape[2], pre_loss_conv.shape[3]))
loss_in = inputs[idx]
loss = T.sum(1./2.*(loss_in - loss_conv)**2) 

del_codes = T.grad(loss, codes[idx])
delc_fn = function([idx], del_codes)
train_codes = function([input_index], loss, updates = [
    [codes, T.set_subtensor(codes[input_index], codes[input_index] - 
                            learning_rate*del_codes[input_index])     ]])

(这里的代码和字典是共享张量变量)。Theano 对此感到不满,特别是对定义进行了限制。
del_codes = T.grad(loss, codes[idx])

我收到的错误信息是:theano.gradient.DisconnectedInputError: grad方法被要求计算相对于不属于代价计算图的变量的梯度,或者仅由不可微分操作符使用:Subtensor{int64}.0 我猜它需要一个符号变量而不是codes[idx];但我不确定如何连接所有内容以获得预期的效果。 我猜我需要将最后一行更改为类似以下内容:
learning_rate*del_codes)     ]])

有人能指点一下我如何正确定义这个函数吗? 我认为我可能忽略了一些基本的Theano使用方法,但我不确定是什么。

提前感谢!

-Justin

更新:Kyle的建议非常好。 这是我使用的具体代码:

current_codes = T.tensor3('current_codes')
current_codes = codes[input_index]
pre_loss_conv = conv2d(input = current_codes.dimshuffle('x', 0, 1,2),
                       filters = dicts.dimshuffle('x', 0,1, 2),
                       border_mode = 'valid')
loss_conv = pre_loss_conv.reshape((pre_loss_conv.shape[2], pre_loss_conv.shape[3]))
loss_in = inputs[input_index]
loss = T.sum(1./2.*(loss_in - loss_conv)**2)  

del_codes = T.grad(loss, current_codes)
train_codes = function([input_index], loss)
train_dicts = theano.function([input_index], loss, updates = [[dicts, dicts - learning_rate*del_dicts]])
codes_update = ( codes, T.set_subtensor(codes[input_index], codes[input_index] - learning_rate*del_codes) )
codes_update_fn = function([input_index], updates = [codes_update])

for i in xrange(num_inputs):
     current_loss = train_codes(i)
     codes_update_fn(i)

你尝试过像 grad_var = codes[idx] 这样的操作,然后对 grad_var 进行微分吗? - Kyle Kastner
感谢您的建议。问题是,如果 grad_var 是一个符号变量(T.tensor3),那么差异化会起作用,但更新不会起作用,因为更新需要共享变量。 - jdbrody
如果您保留grad_var,并将set_subtensor作为单独的变量(如https://dev59.com/DWUo5IYBdhLWcg3wmQZN中所述),而不是在更新函数内部进行分配,是否会导致相同的错误? - Kyle Kastner
Kyle -- 谢谢,看起来完美解决了!无尽的感谢!!现在有一个 Stackoverflow 的问题 -- 我该如何标记问题已解决并给你信用? - jdbrody
我添加了一个答案 - 如果这是正确的总结,请告诉我。如果您有更正的代码,那就发帖吧,那会很好。 - Kyle Kastner
1个回答

10
总结一下发现:
grad_var = codes[idx] 分配给变量,然后创建一个新变量,例如: subgrad = T.set_subtensor(codes[input_index], codes[input_index] - learning_rate*del_codes[input_index]) 然后调用 train_codes = function([input_index], loss, updates = [[codes, subgrad]]) 似乎解决了问题。总的来说,我尽量为尽可能多的事情创建变量。有时候,试图在单个语句中完成过多的操作会导致棘手的问题,而且以后很难调试和理解!此外,在这种情况下,我认为 Theano 需要一个共享变量,但如果需要它的函数内部创建共享变量则会出现问题。
很高兴这对你有用!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接