【问题标题】:I cant understand LSTM implementation in tensorflow 1我无法理解 tensorflow 1 中的 LSTM 实现
【发布时间】:2020-07-01 15:35:30
【问题描述】:

我一直在研究 LSTM 层在神经网络架构中的实现。 LSTM 层已在其中定义,如下所示。我无法理解这段代码。我在sn-p代码后面列出了我的疑惑。

代码来源:https://gist.github.com/awjuliani/66e8f477fc1ad000b1314809d8523455#file-a3c-py

    lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(RNN_SIZE,state_is_tuple=True)
    c_init = np.zeros((1, lstm_cell.state_size.c), np.float32)
    h_init = np.zeros((1, lstm_cell.state_size.h), np.float32)
    state_init = [c_init, h_init]
    c_in = tf.placeholder(tf.float32, [1, lstm_cell.state_size.c])
    h_in = tf.placeholder(tf.float32, [1, lstm_cell.state_size.h])
    state_in = (c_in, h_in)
    rnn_in = tf.expand_dims(self.h3, [0])
    step_size = tf.shape(inputs)[:1]
    state_in = tf.nn.rnn_cell.LSTMStateTuple(c_in, h_in)
    lstm_outputs, lstm_state = tf.nn.dynamic_rnn(
    lstm_cell, rnn_in, initial_state=state_in, sequence_length=step_size,
    time_major=False)
    lstm_c, lstm_h = lstm_state
    state_out = (lstm_c[:1, :], lstm_h[:1, :])
    self.rnn_out = tf.reshape(lstm_outputs, [-1, RNN_SIZE])

这是我的疑问:

  1. 我知道我们需要初始化一个随机上下文并隐藏 向量传递给我们的第一个 LSTM 单元。但是为什么要同时初始化 c_init、h_init 和 c_in、h_in。他们的目的是什么? 它们彼此有何不同? (state_in 和 state_init 一样吗?)
  2. 我们为什么要使用 LSTMStateTuple?

【问题讨论】:

  • 在详细介绍之前,请告诉我们您是否从真实来源获取了此代码。如果是这样,请指定来源的链接,以便我们深入研究并为您提供帮助。谢谢!
  • @TensorflowSupport 是的,来源来自博客系列。 git:gist.github.com/awjuliani/…
  • 很抱歉有一个额外的问题而不是解决方案。该代码有效吗?你执行了吗?
  • @TensorflowSupport 是的,它取自工作代码文件

标签: tensorflow machine-learning deep-learning lstm recurrent-neural-network


【解决方案1】:
def work(self, max_episode_length, gamma, sess, coord, saver, dep):
........
rnn_state = self.local_AC.state_init

def train(self, rollout, sess, gamma, bootstrap_value):
......
rnn_state = self.local_AC.state_init
feed_dict = {self.local_AC.target_v: discounted_rewards,
                 self.local_AC.inputs: np.vstack(observations),
                 self.local_AC.actions: actions,
                 self.local_AC.advantages: advantages,
                 self.local_AC.state_in[0]: rnn_state[0],
                 self.local_AC.state_in[1]: rnn_state[1]}

在工作开始时,然后 在训练一个新批次之前,网络状态被零填充

【讨论】:

    【解决方案2】:
    1. 我知道我们需要初始化一个随机上下文和隐藏向量以传递给我们的第一个 LSTM 单元。但是为什么要同时初始化c_init、h_init,然后再初始化c_in、h_in。他们的目的是什么?它们彼此有何不同? (state_in 和 state_init 一样吗?)

    要开始使用 LSTM,应该初始化它的单元格和状态状态 - 分别命名为 ch。对于每个输入,这些状态都被认为是“空的”,应该用零初始化。所以,我们在这里

    c_in = tf.placeholder(tf.float32, [1, lstm_cell.state_size.c])
    h_in = tf.placeholder(tf.float32, [1, lstm_cell.state_size.h])
    state_in = (c_in, h_in)
    state_in = tf.nn.rnn_cell.LSTMStateTuple(c_in, h_in)
    

    为什么会有两个变量state_instate_init?第一个只是 placeholders,它将在评估状态(即 session.run)用第二个初始化。因为state_in不包含任何实际值,换句话说,在训练阶段使用numpy数组,在定义网络架构的阶段使用tf.placeholders

    TL;DR
    为什么这样?好吧,tf1.x(是?)是一个相当低级的系统。它具有以下实体:

    • tf.Session 又名计算会话 - 包含计算图并允许用户通过 session.run 向图提供输入的东西。
    • tf.Graph,这是一个计算图的表示。通常工程师使用tf.placeholders 和tf.Variabless 定义图形。可以“像”数学运算一样连接它们:
    with tf.Session() as sess:
      a = tf.placeholder(tf.float32, (1,))
      b = tf.Variable(1.0, dtype=tf.float32)
      tf.global_variables_initializer()
      c = a * b
      # ...and so on
    
    
    • tf.占位符是占位符,但不是实际值,旨在在session.run 阶段填充实际值。还有tf.Variables,嗯,是为了优化神经网络的实际权重。为什么不是普通的 NumPy 数组,而是其他的呢?这是因为 TensorFlow 会自动将每个张量和占位符作为边添加到默认计算图中(使用 NumPy 数组做同样的事情是不可能的);此外,它还允许定义架构,然后使用不同的输入对其进行初始化/训练,这很好。

    因此,要进行计算(前向/后向传播等),必须将占位符和变量设置为某些值。为此,在一个简单的示例中,我们可以执行以下操作:

    import tensorflow as tf
    
    with tf.compat.v1.Session() as sess:
      a = tf.compat.v1.placeholder(tf.float32, shape=())
      b = tf.compat.v1.Variable(1.0, dtype=tf.float32)
      init = tf.compat.v1.global_variables_initializer()
      c = a + b
      sess.run(init)
      
      a_value = 2.0
      result = sess.run([c], feed_dict={a: a_value})
    
    print("value of [c]:", result)
    

    (我在这里使用tf.compat.v1 而不是tf,因为我在tf2 环境中工作;你可以省略它) 注意两件事:首先,我创建init 操作。因为在 tf1.x 中,仅初始化 tf.Variable(1.0) 之类的变量是不够的,但用户必须“通知”框架创建和运行 init 操作。 然后我进行计算:我初始化一个a_value 变量并将其映射到占位符a' in the sess.runmethod.Session.run` 需要计算张量列表作为第一个参数和必要的占位符映射将目标张量计算为其实际值。

    回到您的示例:state_in 是一个占位符,state_init 包含要在代码中某处输入此占位符的值。

    看起来像这样:less.run(..., feed_dict={state_in: state_init, ...})

    1. 我们为什么要使用 LSTMStateTuple?

    解决问题的第二部分:看起来 TensorFlow 开发人员实施它是为了进行一些性能优化。来自source code

    logging.warning(
      "%s: Using a concatenated state is slower and will soon be"
      "deprecated. Use state_is_tuple=True.", self)
    

    如果state_is_tuple=True,状态应该是一个StateTuple。但我不是 100% 确定它——我不记得我是如何使用它的。毕竟,StateTuple 只是一个具有两个命名属性的 collections.namedtuplech

    【讨论】:

      猜你喜欢
      • 2017-07-18
      • 1970-01-01
      • 2019-06-13
      • 2021-07-16
      • 1970-01-01
      • 2016-11-01
      • 2019-08-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多