Python 在N次损失计算之后,在Theano中计算更新

Python 在N次损失计算之后,在Theano中计算更新,python,theano,gradient-descent,lstm,recurrent-neural-network,Python,Theano,Gradient Descent,Lstm,Recurrent Neural Network,我已经使用构建了一个LSTM递归NNet,它松散地基于本文中的体系结构。我的输入是一个文本文件,它有大约1000000个句子和2000个单词标记的词汇表。通常,当我构建图像识别网络时,我的输入层将如下所示: l_in = nn.layers.InputLayer((32, 3, 128, 128)) l_in = nn.layers.InputLayer((None, None, 2000)) (尺寸为批量大小、通道、高度和宽度)这很方便,因为所有图像的大小相同,因此我可以批量处理它们。由于

我已经使用构建了一个LSTM递归NNet,它松散地基于本文中的体系结构。我的输入是一个文本文件,它有大约1000000个句子和2000个单词标记的词汇表。通常,当我构建图像识别网络时,我的输入层将如下所示:

l_in = nn.layers.InputLayer((32, 3, 128, 128))
l_in = nn.layers.InputLayer((None, None, 2000))
(尺寸为批量大小、通道、高度和宽度)这很方便,因为所有图像的大小相同,因此我可以批量处理它们。由于我的LSTM网络中的每个实例都有不同的句子长度,因此我有一个如下所示的输入层:

l_in = nn.layers.InputLayer((32, 3, 128, 128))
l_in = nn.layers.InputLayer((None, None, 2000))
如上面提到的博客文章所述

遮罩
因为不是每个小批量中的所有序列都具有相同的长度,所以每个小批量中的所有重复层都具有相同的长度 千层面 接受具有形状的单独掩码输入 (批量大小,n个时间步长) ,其填充方式如下: 掩码[i,j]=1 什么时候 j(长度 (序列i) . 如果未提供掩码,则假定小批量中的所有序列都具有长度 n_time_步数

我的问题是:有没有一种方法可以在不使用掩码的情况下以小批量处理此类网络


这里是一个简化的版本,如果我的网络

# -*- coding: utf-8 -*-

import theano
import theano.tensor as T
import lasagne as nn

softmax = nn.nonlinearities.softmax

def build_model():
    l_in  = nn.layers.InputLayer((None, None, 2000))
    lstm  = nn.layers.LSTMLayer(l_in, 4096, grad_clipping=5)
    rs    = nn.layers.SliceLayer(lstm, 0, 0)
    dense = nn.layers.DenseLayer(rs, num_units=2000, nonlinearity=softmax)
    return l_in, dense

model = build_model()
l_in, l_out = model

all_params = nn.layers.get_all_params(l_out)
target_var = T.ivector("target_output")

output = nn.layers.get_output(l_out)
loss = T.nnet.categorical_crossentropy(output, target_var).sum()
updates = nn.updates.adagrad(loss, all_params, 0.005)

train = theano.function([l_in.input_var, target_var], cost, updates=updates)
从那里我有了一个生成器,它可以输出
(X,y)
对,我正在计算
序列(X,y)
,并在每次迭代中更新梯度。我想做的是做N个训练步骤,然后用平均梯度更新参数

为此,我尝试创建一个
compute\u gradient
函数:

gradient = theano.grad(loss, all_params)

compute_gradient = theano.function(
    [l_in.input_var, target_var],
    output=gradient
  )
然后循环几个训练实例以创建“批处理”,并将梯度计算收集到列表中:

grads = []
for _ in xrange(1024):
    X, y = train_gen.next()  # generator for producing training data
    grads.append(compute_gradient(X, y))
这将生成一个列表列表

>>> grads
[[<CudaNdarray at 0x7f83b5ff6d70>,
<CudaNdarray at 0x7f83b5ff69f0>,
<CudaNdarray at 0x7f83b5ff6270>,
<CudaNdarray at 0x7f83b5fc05f0>],
[<CudaNdarray at 0x7f83b5ff66f0>,
<CudaNdarray at 0x7f83b5ff6730>,
<CudaNdarray at 0x7f83b5ff6b70>,
<CudaNdarray at 0x7f83b5ff64f0>] ...
>毕业生
[[,
,
,
],
[,
,
,
] ...
从这里开始,我需要在每一层上取梯度的平均值,然后更新模型参数。这是可能的,就像这样,梯度计算/参数更新需要在一个theano函数中进行吗

谢谢。

注意:这是一个解决方案,但我绝对没有足够的经验来验证它的最佳性能,代码只是一个草率的示例

你需要2个theano函数。第一个是你在问题中提供的信息判断出你似乎已经拥有的grad函数

因此,在计算批处理梯度后,您希望立即将其作为输入参数反馈给另一个theano函数,该函数用于更新共享变量。为此,您需要在神经网络编译时指定预期的批处理大小。因此,您可以执行以下操作:(为了简单起见,我假设您有一个全局列表变量,其中存储了所有参数)

像这样,theano将采用梯度的平均值,并像往常一样更新参数

我不知道你是否需要像我一样平展输入,但可能

编辑:收集您编辑问题的方式批次大小可能有所不同似乎很重要。在这种情况下,您可以向现有的一个添加两个theano函数:

  • 第一个theano函数获取一批大小为2的参数并返回总和。您可以使用python的reduce()应用此theano函数,并获得整个渐变批次的总和
  • 第二个theano函数将这些求和的参数梯度和定标器(批量大小)作为输入,因此能够根据求和的梯度的平均值更新NN参数

  • 在编译时,您是否需要定义一个theano函数,该函数将批大小梯度作为输入,取平均值并将更改应用于共享值参数?@user2255757是的,这听起来像是我想要的。我只是不确定如何使用符号CudaNdarray实例列表来执行此操作。如果它们是具有它们的实际值我只需要做
    map(np.mean,zip(*grads))
    然后更新参数,但参数没有更新,所以我不知道如何继续。我更新了关于您更新问题的答案,希望是Helpssory,一直非常忙@work。感谢您的回复;我会在本周查看并回复您。如果您查看大多数在线资源,SGD不会对更新进行汇总,而是取平均值,它们只是一个接一个地更新,看起来和正常的梯度下降没什么不同,只是你在多个训练案例中会立即进食