首页 > 解决方案 > 在 Keras 中为每个具有不同隐藏大小和多个 LSTM 层的小批量设置隐藏状态

问题描述

我使用 Keras 和 TensorFlow 作为后端创建了一个 LSTM。在将 num_step 为 96 的小批量提供给训练之前,LSTM 的隐藏状态设置为前一个时间步的真值。

首先是参数和数据:

batch_size = 10
num_steps = 96
num_input = num_output = 2
hidden_size = 8
X_train = np.array(X_train).reshape(-1, num_steps, num_input)
Y_train = np.array(Y_train).reshape(-1, num_steps, num_output)
X_test = np.array(X_test).reshape(-1, num_steps, num_input)
Y_test = np.array(Y_test).reshape(-1, num_steps, num_output)

Keras 模型由两个 LSTM 层和一个层组成,用于将输出修剪为 num_output,即 2:

model = Sequential()
model.add(LSTM(hidden_size, batch_input_shape=((batch_size, num_steps, num_input)),
               return_sequences=True, stateful = True)))
model.add(LSTM(hidden_size, return_sequences=True)))
model.add(Dropout(0.2))
model.add(TimeDistributed(Dense(num_output, activation='softmax')))

model.compile(loss='mean_squared_error', optimizer='adam', metrics=['accuracy'])

生成器以及训练(hidden_​​states[x] 的形状为 (2,)):

def gen_data():
        x = np.zeros((batch_size, num_steps, num_input))
        y = np.zeros((batch_size, num_steps, num_output))
        while True:
            for i in range(batch_size):
                model.layers[0].states[0] = K.variable(value=hidden_states[gen_data.current_idx]) # hidden_states[x] has shape (2,)
                x[i, :, :] = X_train[gen_data.current_idx]
                y[i, :, :] = Y_train[gen_data.current_idx]
                gen_data.current_idx += 1
            yield x, y
gen_data.current_idx = 0


for epoch in range(100):
    model.fit_generator(generate_data(), len(X_train)//batch_size, 1,
                        validation_data=None, max_queue_size=1, shuffle=False)
    gen_data.current_idx = 0

这段代码没有给我错误,但我有两个问题:

1) 在生成器内部,我将 LSTM 的隐藏状态设置为形状为 (2,)model.layers[0].states[0]的变量。hidden_states[gen_data.current_idx]为什么这对于隐藏大小大于 2 的 LSTM 是可能的?

2) 中的值hidden_states[gen_data.current_idx]也可以是 Keras 模型的输出。两层 LSTM 以这种方式设置隐藏状态有意义吗?

标签: pythontensorflowkerasdeep-learninglstm

解决方案


LSTM 中的状态

LSTM 由计算cell state和的门组成hidden state在此处输入图像描述

在图中,从 LSTM 右侧出来的顶部箭头是单元状态 ( c_t),底部箭头是隐藏状态 ( h_t)。单元状态是门控操作的结果,状态的大小与 LSTM 的大小相同hidden_size。每次展开(及其对应的输入 X)都会产生自己的单元格状态。在 LSTM 的情况下,单元状态由 (batch_size x hidden_​​size) 的两个值 hidden_​​state( h_t) 和 (batch_size x hidden_​​size) 的 cell_state ( c_t) 组成。

batch_size = 2
num_steps = 5
num_input = num_output = 1
hidden_size = 8

inputs = Input(batch_shape=(batch_size,num_steps, num_input))
lstm, state_h, state_c = LSTM(hidden_size, return_state=True, return_sequences=True)(inputs)
model = Model(inputs=inputs, outputs=[state_h, state_c])

print (model.predict(np.zeros((batch_size, num_steps, num_input))))
print (model.layers[1].cell.state_size)

注意:在 GRU/RNN 的情况下,没有单元状态,只有隐藏状态,因此单元状态h_t的大小(batch_size,hidden_​​size)

参考:

LSTM的 Keras 实现

Keras 文档:

状态张量的数量为 1(对于 RNN 和 GRU)或 2(对于 LSTM)。

LSTM 和 GRU 图解指南

喂养状态

在您的示例中,layers[0]指的是 1 LSTM 并layers[1]指的是 2nd LSTM。如果您的意图是将c_t第 n 个批次的单元状态 ( ) 初始化为 (n-1) 的单元状态,即前一批有两个选项

  • 您在生成器中执行的方式,但states[1]如果需要c_t, 请使用states[0]for h_t。同样layers[0]用于第一个 LSTM 和layers[1]第二个 LSTM。但改用set_value方法。请参阅下面的编辑。

  • 使用 keras Stateful=True:将 stateful 设置为 true 时,LSTM 状态不会在每批后重置。因此,如果您有一个包含 5 个数据样本(每个都有一定序列长度)的批次,您将获得 5 个数据样本中每一个的单元状态。将 stateful 设置为 true 这些状态用于为下一批初始化下一批单元状态。

编辑:

该方法set_value应该用于设置张量变量的值。该代码model.layers[0].states[0] = K.variable(value=hidden_states[gen_data.current_idx])是有效的,因为它所做的是将指向大小变量 (batch_size X hidden_​​size) 的 state[0] 更改为大小变量 (batch_size x 2)。它不是改变张量变量的值,而是使其指向不同维度的新张量变量。

测试代码:

 print (model.layers[0].states[0], hex(id(model.layers[0].states[0])))
 model.layers[0].states[0]= K.variable(np.random.randn(10,2))
 print (model.layers[0].states[0], hex(id(model.layers[0].states[0])))

输出

<tf.Variable 'lstm_18/Variable:0' shape=(10, 8) dtype=float32_ref> 0x7f8812e6ee10
<tf.Variable 'Variable_2:0' shape=(10, 2) dtype=float32_ref> 0x7f881269afd0

如您所见,它们是两个不同的变量。正确的方法是

 print (model.layers[0].states[0], hex(id(model.layers[0].states[0])))
 K.set_value(model.layers[0].states[0], np.random.randn(10,8))
 print (model.layers[0].states[0], hex(id(model.layers[0].states[0])))

输出

<tf.Variable 'lstm_20/Variable:0' shape=(10, 8) dtype=float32_ref> 0x7f881138eb70
<tf.Variable 'lstm_20/Variable:0' shape=(10, 8) dtype=float32_ref> 0x7f881138eb70

如果您的代码是固定的,那么

K.set_value(model.layers[0].states[0], np.random.randn(10,2))

由于张量的大小与您设置的值的大小不匹配,将引发错误。


推荐阅读