0

我构建了一个使用lasagne的LSTM经常性NNet,它基于这个blog post中的体系结构松散地构建。我的输入是一个文本文件,它有大约1,000,000个句子和一个2,000个词的词汇表。通常,当我构建网络的图像识别我的输入层看起来像以下:在计算N个损失计算后,计算Theano中的更新

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 时 Ĵ< =(序列的长度i) 和 掩模[I,J] = 0 当 J>时序列(长度 我) 。 未提供掩码时,假定小批量中的所有序列长度为 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函数中吗?

谢谢。

+0

你不会在编译时需要定义一个将batch_size渐变作为输入的theano函数,取其意义并将变化应用于共享值params? – user2255757

+0

@ user2255757是的,这听起来像我以后。我只是不确定如何使用符号CudaNdarray实例列表来做这件事。如果他们是数组中的实际值的numpy数组,我只需要'map(np.mean,zip(* grads))'然后更新参数,但他们不是这样,我不知道如何继续。 – gobrewers14

+0

我更新了我的问题答案,希望对您有所帮助 – user2255757

回答

0

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

您需要2种theano功能。第一个是你已经从你提问中提供的信息来判断的毕业生。

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

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函数,并且获得整批梯度的总和。第二个函数将这些累加参数梯度和一个定标器(批量大小)作为输入,从而能够在累加梯度的平均值上更新NN参数。
+0

对不起,一直忙于工作。感谢您的答复;我会在本周查看并回复你。 – gobrewers14

+0

如果您查看大多数在线资源,SGD并不会对这些更新进行求和并取其平均值,但它们只是逐个更新1,似乎与正常梯度下降没有区别,除非您立即在多个培训案例中进行投入 – user2255757