十四行诗中的LSTM时间步

时间:2019-06-05 17:28:28

标签: python tensorflow deep-learning eager-execution

我正在尝试学习Sonnet

我的网络(不完整,问题基于此):

class Model(snt.AbstractModule):

    def __init__(self, name="LSTMNetwork"):
        super(Model, self).__init__(name=name)
        with self._enter_variable_scope():
            self.l1 = snt.LSTM(100)
            self.l2 = snt.LSTM(100)
            self.out = snt.LSTM(10)

    def _build(self, inputs):

        # 'inputs' is of shape (batch_size, input_length)
        # I need it to be of shape (batch_size, sequence_length, input_length)

        l1_state = self.l1.initialize_state(np.shape(inputs)[0]) # init with batch_size
        l2_state = self.l2.initialize_state(np.shape(inputs)[0]) # init with batch_size
        out_state = self.out.initialize_state(np.shape(inputs)[0])

        l1_out, l1_state = self.l1(inputs, l1_state)
        l1_out = tf.tanh(l1_out)
        l2_out, l2_state = self.l2(l1_out, l2_state)
        l2_out = tf.tanh(l2_out)
        output, out_state = self.out(l2_out, out_state)
        output = tf.sigmoid(output)

        return output, out_state

在其他框架(例如Keras)中,LSTM输入的格式为(batch_size, sequence_length, input_length)

但是,Sonnet文档指出,Sonnet的LSTM的输入格式为(batch_size, input_length)

如何使用它们进行顺序输入?

到目前为止,我已经尝试在_build内使用for循环,在每个时间步上进行迭代,但这看起来似乎是随机输出。

我在Keras中尝试了相同的架构,该架构运行时没有任何问题。

我正在急切地执行,使用GradientTape进行训练。

1 个答案:

答案 0 :(得分:0)

通常,我们在Sonnet中编写RNN可以在单个时间步的基础上工作,因为对于强化学习,您通常需要运行一个时间步来选择一个动作,而没有该动作,您将无法获得下一个观察值(以及下一个观察值)。输入时间步长)。使用tf.nn.dynamic_rnn在序列上展开单个时间步模块很容易(请参见下文)。我们还有一个包装器,负责处理每个时间步的几个RNN核心,我相信这是您想要的工作。这样做的好处是DeepCore对象支持dynamic_rnn所需的开始状态方法,因此它的API与LSTM或任何其他单一时间步模块兼容。

您想做的事情应该是可以实现的:

# Create a single-timestep RNN module by composing recurrent modules and
# non-recurrent ops.
model = snt.DeepRNN([
    snt.LSTM(100),
    tf.tanh,
    snt.LSTM(100),
    tf.tanh,
    snt.LSTM(100),
    tf.sigmoid
], skip_connections=False)

batch_size = 2
sequence_length = 3
input_size = 4

single_timestep_input = tf.random_uniform([batch_size, input_size])
sequence_input = tf.random_uniform([batch_size, sequence_length, input_size])

# Run the module on a single timestep
single_timestep_output, next_state = model(
    single_timestep_input, model.initial_state(batch_size=batch_size))

# Unroll the module on a full sequence
sequence_output, final_state = tf.nn.dynamic_rnn(
    core, sequence_input, dtype=tf.float32)

需要注意的几件事-如果还没有,请查看存储库中的RNN example,因为这显示了围绕一个非常相似的模型的完整图形模式训练过程。

第二,如果您最终需要实现DeepRNN允许的更复杂的模块,则将循环状态穿入和穿出模块很重要。在您的示例中,您在内部设置输入状态,并且l1_statel2_state作为输出被有效地丢弃,因此无法正确地进行训练。如果DeepRNN不可用,您的模型将如下所示:

class LSTMNetwork(snt.RNNCore):  # Note we inherit from the RNN-specific subclass
  def __init__(self, name="LSTMNetwork"):
    super(Model, self).__init__(name=name)
    with self._enter_variable_scope():
      self.l1 = snt.LSTM(100)
      self.l2 = snt.LSTM(100)
      self.out = snt.LSTM(10)

  def initial_state(self, batch_size):
    return (self.l1.initial_state(batch_size),
            self.l2.initial_state(batch_size),
            self.out.initial_state(batch_size))

  def _build(self, inputs, prev_state):

    # separate the components of prev_state
    l1_prev_state, l2_prev_state, out_prev_state = prev_state

    l1_out, l1_next_state = self.l1(inputs, l1_prev_state)
    l1_out = tf.tanh(l1_out)
    l2_out, l2_next_state = self.l2(l1_out, l2_prev_state)
    l2_out = tf.tanh(l2_out)
    output, out_next_state = self.out(l2_out, out_prev_state)

    # Output state of LSTMNetwork contains the output states of inner modules.
    full_output_state = (l1_next_state, l2_next_state, out_next_state)

    return tf.sigmoid(output), full_output_state

最后,如果您使用的是渴望模式,我强烈建议您看一下Sonnet 2-这是对TF 2 / Eager模式的完整重写。它不是向后兼容的,但是所有相同种类的模块组成都是可能的。 Sonnet 1主要是为Graph模式TF编写的,虽然它确实可以在Eager模式下工作,但您可能会遇到一些不太方便的事情。

我们与TensorFlow团队紧密合作,以确保TF 2和Sonnet 2可以很好地协同工作,因此请看一下:(https://github.com/deepmind/sonnet/tree/v2)。 Sonnet 2应该被视为Alpha,并且正在积极开发中,因此我们还没有很多示例,但是在不久的将来还会有更多示例。