【问题标题】:Compute updates in Theano after N number of loss calculations在 N 次损失计算后在 Theano 中计算更新
【发布时间】:2016-02-04 20:51:21
【问题描述】:

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

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

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

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

如上面引用的博文所述,

口罩
因为并非每个 minibatch 中的所有序列都将始终具有相同的长度,所以 千层面 接受具有形状的单独掩码输入 (batch_size, n_time_steps) ,其填充使得 掩码[i, j] = 1 什么时候 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 函数中全部发生?

谢谢。

【问题讨论】:

  • 难道您不需要在编译时定义一个将 batch_size 梯度作为输入、取平均值并将更改应用于共享值参数的 theano 函数吗?
  • @user2255757 是的,这听起来像我所追求的。我只是不确定如何使用符号 CudaNdarray 实例列表来做到这一点。如果它们是其中包含实际值的 numpy 数组,我只需执行 map(np.mean, zip(*grads)) 然后更新参数,但它们不是,所以我不确定如何继续。
  • 我更新了关于您更新问题的答案,希望对您有所帮助

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


【解决方案1】:

注意:这是一个解决方案,但我没有足够的经验来验证它的最佳效果,而且代码只是一个草率的例子

您需要 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 参数。

【讨论】:

  • 抱歉,@工作太忙了。感谢您的答复;我会在这周查看它并回复您。
  • 如果您查看大多数在线资源 SGD 不会对更新求和并取平均值,它们只是 1 对 1 更新,除了您立即进行多次训练外,它似乎与正常梯度下降没有什么不同案例
猜你喜欢
  • 2022-07-14
  • 1970-01-01
  • 2021-07-26
  • 1970-01-01
  • 1970-01-01
  • 2016-08-10
  • 2012-11-24
  • 2020-10-31
相关资源
最近更新 更多