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



我使用千层面构建了一个LSTM循环NNet,它松散地基于这篇博文中的架构。 我的输入是一个文本文件,其中包含大约 1,000,000 个句子和 2,000 个单词标记的词汇表。 通常,当我构建用于图像识别的网络时,我的输入层将如下所示:

l_in = nn.layers.InputLayer((32, 3, 128, 128))

(其中尺寸是批量大小,通道,高度和宽度(,这很方便,因为所有图像的大小都相同,因此我可以批量处理它们。 由于 LSTM 网络中的每个实例都有不同的句子长度,因此我有一个如下所示的输入层:

l_in = nn.layers.InputLayer((None, None, 2000))

如上面引用的博客文章所述,

口罩
由于并非每个小批量中的所有序列始终具有相同的长度,因此所有循环层 千层面 接受具有形状的单独掩码输入 (batch_size、n_time_steps( ,其填充为 掩码 [i, j] = 1 什么时候 j <= (序列 i 的长度( 和 掩码[i, j] = 0 什么时候 j>(长度 序列 i( . 如果未提供掩码,则假定小批量中的所有序列的长度 n_time_steps。

我的问题是:有没有办法在不使用掩码的情况下小批量处理这种类型的网络?


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

# -*- 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)对,我正在计算train(X, y)并在每次迭代时更新梯度。 我想做的是做N个训练步骤,然后用平均梯度更新参数。

为此,我尝试创建一个compute_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 函数。第一个是你似乎已经从你的问题中提供的信息判断的毕业生。

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

params #list of params you wish to update
BATCH_SIZE = 1024 #size of the expected training batch
G = [T.matrix() for i in range(BATCH_SIZE) for param in params] #placeholder for grads result flattened so they can be fed into a theano function
updates = [G[i] for i in range(len(params))] #starting with list of  param updates from first batch
for i in range(len(params)): #summing the gradients for each individual param
     for j in range(1, len(G)/len(params)):
         updates[i] += G[i*BATCH_SIZE + j]
for i in range(len(params)): #making a list of tuples for theano.function updates argument
     updates[i] = (params[i], updates[i]/BATCH_SIZE) 
update = theano.function([G], 0, updates=updates)

像这个 theano 将取梯度的平均值并像往常一样更新参数

不知道您是否需要像我一样扁平化输入,但可能

编辑:

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

  1. 第一个 theano 函数采用参数大小为 2 的批次并返回总和。 你可以使用 Python 的 reduce(( 应用这个 theano 函数,并得到整批梯度的总和
  2. 第二个 theano 函数将这些求和的参数梯度和缩放器(批量大小(作为输入,因此能够在求和梯度的平均值上更新 NN 参数。

最新更新