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

时间:2016-02-04 20:51:21

标签: python theano gradient-descent lstm recurrent-neural-network

我使用lasagne构建了一个LSTM循环NNet,它基于此blog post中的体系结构。我的输入是一个文本文件,有大约1,000,000个句子和2000个单词令牌的词汇表。通常,当我构建用于图像识别的网络时,我的输入层将如下所示:

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

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

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

如上文引用的博文中所述,

  

面膜
  因为并非每个小批量中的所有序列总是具有相同的长度,所以所有的重复层都在   千层面    接受具有形状的单独掩模输入   (batch_size,n_time_steps)   ,这是人口稠密的   mask [i,j] = 1    什么时候   j< =(序列i的长度)    和   mask [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函数中发生?

感谢。

1 个答案:

答案 0 :(得分:0)

注意:这是一个解决方案,但绝不是我有足够的经验来验证其最佳状态,而且代码只是一个草率的例子

你需要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将采用渐变的平均值并像往常一样更新params

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

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

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