【问题标题】:Initializing LSTM hidden state Tensorflow/Keras初始化 LSTM 隐藏状态 Tensorflow/Keras
【发布时间】:2017-02-23 12:34:36
【问题描述】:

谁能解释我如何在 tensorflow 中初始化 LSTM 的隐藏状态?我正在尝试构建 LSTM 循环自动编码器,因此在我训练了该模型之后,我想将学习到的无监督模型的隐藏状态转移到有监督模型的隐藏状态。 使用当前的 API 甚至可能吗? 这是我正在尝试重新创建的纸张:

http://papers.nips.cc/paper/5949-semi-supervised-sequence-learning.pdf

【问题讨论】:

    标签: tensorflow neural-network deep-learning keras lstm


    【解决方案1】:

    是的 - 这是可能的,但确实很麻烦。让我们来看一个例子。

    1. 定义模型:

      from keras.layers import LSTM, Input
      from keras.models import Model
      
      input = Input(batch_shape=(32, 10, 1))
      lstm_layer = LSTM(10, stateful=True)(input)
      
      model = Model(input, lstm_layer)
      model.compile(optimizer="adam", loss="mse")
      

      首先构建和编译模型很重要,因为在编译时会重置初始状态。此外-您需要指定batch_shape,其中指定batch_size,因为在这种情况下我们的网络应该是stateful(通过设置stateful=True模式来完成。

    2. 现在我们可以设置初始状态的值了:

      import numpy
      import keras.backend as K
      
      hidden_states = K.variable(value=numpy.random.normal(size=(32, 10)))
      cell_states = K.variable(value=numpy.random.normal(size=(32, 10)))
      
      model.layers[1].states[0] = hidden_states
      model.layers[1].states[1] = cell_states 
      

      请注意,您需要将状态作为keras 变量提供。 states[0] 保存隐藏状态,states[1] 保存单元状态。

    希望对您有所帮助。

    【讨论】:

    • 如果我只想设置初始隐藏状态,代码是model.layers[1].states[0][0] = h_0
    【解决方案2】:

    如循环层的 Keras API 文档中所述 (https://keras.io/layers/recurrent/):

    关于指定 RNN 初始状态的注意事项

    您可以通过使用关键字参数initial_state 调用RNN 层来象征性地指定它们的初始状态。 initial_state 的值应该是一个张量或张量列表,代表 RNN 层的初始状态。

    您可以通过使用关键字参数states 调用reset_states 以数字方式指定RNN 层的初始状态。 states 的值应该是一个 numpy 数组或 numpy 数组列表,代表 RNN 层的初始状态。

    由于 LSTM 层有两种状态(隐藏状态和单元状态),initial_statestates 的值是两个张量的列表。


    示例

    无状态 LSTM

    输入形状:(批次、时间步长、特征)= (1, 10, 1)
    LSTM 层中的单元数 = 8(即隐藏和单元状态的维数)

    import tensorflow as tf
    import numpy as np
    
    inputs = np.random.random([1, 10, 1]).astype(np.float32)
    
    lstm = tf.keras.layers.LSTM(8)
    
    c_0 = tf.convert_to_tensor(np.random.random([1, 8]).astype(np.float32))
    h_0 = tf.convert_to_tensor(np.random.random([1, 8]).astype(np.float32))
    
    outputs = lstm(inputs, initial_state=[h_0, c_0])
    

    有状态的 LSTM

    输入形状:(批次、时间步长、特征)= (1, 10, 1)
    LSTM 层中的单元数 = 8(即隐藏和单元状态的维数)

    请注意,对于有状态的 lstm,您还需要指定 batch_size

    import tensorflow as tf
    import numpy as np
    from pprint import pprint
    
    inputs = np.random.random([1, 10, 1]).astype(np.float32)
    
    lstm = tf.keras.layers.LSTM(8, stateful=True, batch_size=(1, 10, 1))
    
    c_0 = tf.convert_to_tensor(np.random.random([1, 8]).astype(np.float32))
    h_0 = tf.convert_to_tensor(np.random.random([1, 8]).astype(np.float32))
    
    outputs = lstm(inputs, initial_state=[h_0, c_0])
    

    使用有状态 LSTM,状态不会在每个序列的末尾重置,我们可以注意到层的输出对应于最后一个时间步的隐藏状态(即lstm.states[0]):

    >>> pprint(outputs)
    <tf.Tensor: id=821, shape=(1, 8), dtype=float32, numpy=
    array([[ 0.07119043,  0.07012419, -0.06118739, -0.11008392,  0.00573938,
            -0.05663438,  0.11196419,  0.02663924]], dtype=float32)>
    >>>
    >>> pprint(lstm.states)
    [<tf.Variable 'lstm_1/Variable:0' shape=(1, 8) dtype=float32, numpy=
    array([[ 0.07119043,  0.07012419, -0.06118739, -0.11008392,  0.00573938,
            -0.05663438,  0.11196419,  0.02663924]], dtype=float32)>,
     <tf.Variable 'lstm_1/Variable:0' shape=(1, 8) dtype=float32, numpy=
    array([[ 0.14726108,  0.13584498, -0.12986949, -0.22309153,  0.0125412 ,
            -0.11446435,  0.22290672,  0.05397629]], dtype=float32)>]
    

    调用reset_states()可以重置状态:

    >>> lstm.reset_states()
    >>> pprint(lstm.states)
    [<tf.Variable 'lstm_1/Variable:0' shape=(1, 8) dtype=float32, numpy=array([[0., 0., 0., 0., 0., 0., 0., 0.]], dtype=float32)>,
     <tf.Variable 'lstm_1/Variable:0' shape=(1, 8) dtype=float32, numpy=array([[0., 0., 0., 0., 0., 0., 0., 0.]], dtype=float32)>]
    >>>
    

    或将它们设置为特定值:

    >>> lstm.reset_states(states=[h_0, c_0])
    >>> pprint(lstm.states)
    [<tf.Variable 'lstm_1/Variable:0' shape=(1, 8) dtype=float32, numpy=
    array([[0.59103394, 0.68249655, 0.04518601, 0.7800545 , 0.3799634 ,
            0.27347744, 0.54415804, 0.9889024 ]], dtype=float32)>,
     <tf.Variable 'lstm_1/Variable:0' shape=(1, 8) dtype=float32, numpy=
    array([[0.43390197, 0.28252542, 0.27139077, 0.19655049, 0.7568088 ,
            0.05909375, 0.68569875, 0.19087408]], dtype=float32)>]
    >>>
    >>> pprint(h_0)
    <tf.Tensor: id=422, shape=(1, 8), dtype=float32, numpy=
    array([[0.59103394, 0.68249655, 0.04518601, 0.7800545 , 0.3799634 ,
            0.27347744, 0.54415804, 0.9889024 ]], dtype=float32)>
    >>>
    >>> pprint(c_0)
    <tf.Tensor: id=421, shape=(1, 8), dtype=float32, numpy=
    array([[0.43390197, 0.28252542, 0.27139077, 0.19655049, 0.7568088 ,
            0.05909375, 0.68569875, 0.19087408]], dtype=float32)>
    >>>
    

    【讨论】:

    • 执行此操作时,我收到一条错误消息,提示隐藏状态需要是象征性的。我正在使用功能 API。如何将初始状态转换为符号状态?
    【解决方案3】:

    我使用了这种方法,完全适合我:

    lstm_cell = LSTM(cell_num, return_state=True) 
    
    output, h, c = lstm_cell(input, initial_state=[h_prev, c_prev])
    

    【讨论】:

      【解决方案4】:

      假设 RNN 在第 1 层,隐藏/单元状态是 numpy 数组。你可以这样做:

      from keras import backend as K
      
      K.set_value(model.layers[1].states[0], hidden_states)
      K.set_value(model.layers[1].states[1], cell_states)
      

      状态也可以使用

      model.layers[1].states[0] = hidden_states
      model.layers[1].states[1] = cell_states
      

      但是当我这样做时,即使在步进 RNN 之后,我的状态值也保持不变。

      【讨论】: