【问题标题】:make LSTM cell trainable使 LSTM 单元可训练
【发布时间】:2018-02-16 10:59:08
【问题描述】:

我使用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 单元具有忘记等操作符。这些操作是否也被视为变量,因此在训练时进行了调整?

【问题讨论】:

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


    【解决方案1】:

    关于语法的一点说明:从 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' 的大小n_hidden 确定。 W_*b_* 是我们将要学习的更多参数。

    3. 将旧信息与新候选状态相结合,得出新的细胞状态:c_k = f_k * c_k-1 + i_k * c'_k

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

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

      o_k = sigmoid(W_o * [h_k-1, x_k] + b_o)
      h_k = o_k * tanh(c_k)
      

    所以基本上我们将新旧信息混合到内部“单元状态”c_k,然后在h_k 中输出一些信息。我还建议查看 gated recurrent unit (GRU) network,它的性能与 LSTM 类似,但结构更易于理解。

    现在介绍多层网络的堆叠方式。基本上,你有这样的东西:

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

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

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

    可训练变量


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

    for var in tf.trainable_variables():
        print('{}\nShape: {}'.format(var.name, var.get_shape()))
    

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

    • 权重:W_fW_iW_cW_o每一层
    • 偏差:b_fb_ib_cb_o对于每一层
    • 以及您在最后一个 LSTM 层之上添加的其他输出层权重/偏差

    我更熟悉 TF 如何处理 GRU 架构,它基本上将所有门组合成一个大矩阵运算,因此所有门都有一个组合权重矩阵和一个组合偏置向量。然后它将结果拆分到每个单独的门中,以将它们应用到正确的位置。仅供参考,以防您看起来每个单元格的每个单独步骤都没有权重和偏差。

    【讨论】:

    • @Engineero...非常感谢您提供非常清晰简洁的解释...几个快速问题 1. 通常,当底层(例如 O1)的输出被馈送到在多层 LSTM 中的下一个顶层,我们可以将这些输出 O1 乘以权重矩阵 W1。当我问这些权重是否也可训练时,我指的是这些权重 W1?
    • 如果我们看到这个 pdf arxiv.org/pdf/1409.2329v5.pdf 的第 2 页,那么我们意识到有一个矩阵 T_{2n,n} 在决定时乘以前一层 (l-1) 的输出第 l 层的输出。
    • 这真的很有帮助!但是,我主要担心的是,在您制作的图表中,当 h0_k 被馈送到 network_1 时,它会乘以一个矩阵。我的问题是 tensorflow 是否也会自动优化这个矩阵?
    • @rahul_88 在您链接的论文中,他们在层之间应用 dropout,而不是乘以权重矩阵。这是不同的。您可以通过在我的答案中的第一行 cell 之后添加一行 cell = tf.contrib.rnn.DropoutWrapper(cell, output_keep_prob=some_dropout_placeholder) 来应用辍学。基本上 dropout 在训练期间会随机切割通道以防止过度拟合。您可以以类似的方式在层之间添加权重,但我认为您不需要...
    • @rahul_88 由于前一层的隐藏状态成为当前层的输入,它在我的回答中取代了x。因此,它仍然经过x 上面经过的仿射变换和非线性变换,因此您不需要额外的权重矩阵。它基本上会将每个门更改为f_k = sigmoid(W_f * [h_k-1, (W_x * x_k + b_x)], + b_f) 之类的东西。我很确定你可以证明离开 W_xb_x 是等价的。
    猜你喜欢
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-08
    • 2016-01-25
    • 2020-12-15
    • 2021-09-02
    • 2019-11-25
    相关资源
    最近更新 更多