初始化LSTM隐藏状态Tensorflow/Keras

17
有人能解释一下如何在tensorflow中初始化LSTM的隐藏状态吗?我正在尝试构建LSTM循环自编码器,所以在训练该模型后,我希望将无监督模型学习到的隐藏状态转移到有监督模型的隐藏状态中。 当前API是否支持这样做? 这是我试图复制的论文:http://papers.nips.cc/paper/5949-semi-supervised-sequence-learning.pdf
4个回答

21

是的,这是可能的,但非常繁琐。让我们通过一个例子来说明。

  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实现)。

  • 现在我们可以设置初始状态的值:

  • 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 吗? - bicepjai

    7

    正如Keras API文档中递归层所述(https://keras.io/layers/recurrent/):

    关于RNN的初始状态说明

    您可以通过使用关键字参数initial_state来符号化地指定RNN层的初始状态。 initial_state的值应该是一个张量或表示RNN层初始状态的张量列表。

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

    由于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。如何将初始状态转换为符号? - bcsta

    3
    我采用了这种方法,对我来说完全奏效:
    lstm_cell = LSTM(cell_num, return_state=True) 
    
    output, h, c = lstm_cell(input, initial_state=[h_prev, c_prev])
    

    1
    假设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步进之后,我的状态值仍然保持不变。

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接