使LSTM细胞可训练

时间:2017-09-07 16:05:31

标签: tensorflow lstm recurrent-neural-network tensorflow-serving

我使用tf.contrib.rnn.MultiRNNCell模块制作多层RNN。我使用以下行来定义3层RNN-LSTM网络:

n_hidden = 2
num_layers = 3        
lstm_cell = tf.contrib.rnn.BasicLSTMCell(n_hidden)
stacked_lstm_cell = tf.contrib.rnn.MultiRNNCell([lstm_cell] * num_layers)

然而,对于tensorflow中实际发生的事情,我的想法存在一些不确定性。据我所知,这段代码给了我一个计算图,其中有3层LSTM单元,每层有2个LSTM单元。我有以下疑问:

  1. 这3个LSTM层之间的权重是否被视为变量?
  2. 如果将这些权重视为变量,是否在培训期间进行了修改?
  3. LSTM细胞有像忘记等操作符。这些操作是否也被视为变量,因此在训练时进行调整?

1 个答案:

答案 0 :(得分:2)

关于语法的一点注意事项:从TF~1.0开始,您需要在循环中定义多个层而不是使用[cell] * num_layers语法,如下所示:

lstm_cells = []
for _ in range(num_layers):
    cell = tf.contrib.rnn.BasicLSTMCell(n_hidden)
    lstm_cells.append(cell)
stacked_lstm_cell = tf.contrib.rnn.MultiRNNCell(lstm_cells)

主要问题:

  • 您的代码为您提供了一个包含3层(num_layers)的网络,其中每个层都包含一个隐藏状态长度为2(n_hidden)的LSTM。更多相关内容。
  • 三个LSTM图层之间没有权重:每个LSTM将其输出反馈到下一个LSTM的输入。
  • 您的网络中的所有权重和偏差都将被视为可训练的变量并通过反向传播进行训练,除非您告诉TF不要训练某些事物。
  • LSTM中的忘记和更新等操作在网络输入和网络先前隐藏状态的线性组合上执行某些功能。 “线性组合”部分涉及由您的网络训练的重量和偏差。

了解LSTM

让我们来看看LSTM网络架构。 This is a pretty great overview that I recommend reading。基本上,单个LSTM单元保持一个隐藏状态,表示它到目前为止所看到的“记忆”,并且在每个更新步骤中,它决定使用“隐藏状态下与现有信息混合的新信息量”。门”。它还使用门来确定它将输出什么。看一下单个单元的更新过程:

  1. 我们首先确定忘记了多少旧信息(我们的遗忘门):f_k = sigmoid(W_f * [h_k-1, x_k] + b_f)

    我们在此处运行网络的历史记录h_k-1与当前观察x_k连接。您的历史记录向量h的大小由n_hidden定义。权重W_f和偏见b_f将通过培训程序学习。

  2. 我们确定要合并多少新信息(我们的输入门,i_k),并创建一些新的候选单元状态(c'_k):

    i_k = sigmoid(W_i * [h_k-1, x_k] + b_i)
    c`_k = tanh(W_c * [h_k-1, x_k] + b_c)
    

    同样,我们正在使用旧的内部状态h_k-1和新的观察x_k来确定下一步该做什么。单元格状态c和候选单元格状态c'的大小也由<{1}}确定n_hiddenW_*是我们将要学习的更多参数。

  3. 将旧信息与新候选状态相结合,以提出新的单元格状态:b_*

    这里我们正在进行逐元素乘法而不是点积或其他任何东西。基本上我们会选择保留多少旧信息(c_k = f_k * c_k-1 + i_k * c'_k),以及要合并多少新信息(f_k * c_k-1)。

  4. 最后,我们通过输出门确定我们想要输出多少单元状态:

    i_k * c'_k
  5. 基本上我们将旧信息和新信息混合到内部“单元状态”o_k = sigmoid(W_o * [h_k-1, x_k] + b_o) h_k = o_k * tanh(c_k) 中,然后在c_k中输出一些信息。我建议您同时查看gated recurrent unit (GRU) network,其执行方式与LSTM相似,但结构稍微容易理解。

    现在讨论多层网络的堆叠方式。基本上,你有一些看起来像这样的东西:

    h_k

    所以你的观察进入第一个网络,然后该网络的输出作为输入馈送到下一个网络,它将其与自己的内部状态混合以产生输出,然后输出成为第三个网络的输入,等等到最后。这应该有助于学习数据中的时间结构。我对此没有很好的引用。

    通常,如果您正在进行分类(例如),您将在最后一个网络的输出上抛出最终完全连接的图层,以获得一定程度的信心,即您观察到的进程位于您正在分类的每个类别中。

    可训练变量

    您可以使用以下内容打印出您的网络将要学习的所有可训练变量:

    x_k ---> (network 0) --h0_k--> (network_1) --h1_k--> (network_2) --h2_k-->
    

    Tensorflow通过组合不同的操作做了一些奇特的事情,所以你可能会看到一些奇怪的形状,显然缺少重量矩阵和偏差,但它就在那里。基本上你正在学习每个门的重量和偏差。在上面,那将是:

    • weigths:每个图层的for var in tf.trainable_variables(): print('{}\nShape: {}'.format(var.name, var.get_shape())) W_fW_iW_c
    • 每个图层的偏见:W_ob_fb_ib_c
    • 以及在最后一个LSTM图层顶部添加的其他输出图层权重/偏差

    我更熟悉TF如何处理GRU架构,它基本上将所有门组合成一个大矩阵运算,因此你有一个组合权重矩阵和一个组合偏置矢量用于所有门。然后它将结果分成每个单独的门,以便在正确的位置应用它们。只是一个FYI,以防你看起来每个单元的每个步骤都没有权重和偏差。