在 Keras 中为具有不同隐藏大小和多个 LSTM 层的每个小批量设置隐藏状态

Mer*_*klT 4 python deep-learning lstm keras tensorflow

我使用 Keras 创建了一个 LSTM,并以 TensorFlow 作为后端。在 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)
Run Code Online (Sandbox Code Playgroud)

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'])
Run Code Online (Sandbox Code Playgroud)

生成器以及训练(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
Run Code Online (Sandbox Code Playgroud)

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

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 以这种方式设置隐藏状态有意义吗?

muj*_*iga 5

LSTM 中的状态

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

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

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)
Run Code Online (Sandbox Code Playgroud)

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

参考:

LSTM的 Keras 实现

喀拉斯文档:

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

LSTM 和 GRU 图解指南

喂养状态

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

  • 您在生成器中所做的方式,但states[1]如果您愿意,请使用c_tstates[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 Xhidden_​​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])))
Run Code Online (Sandbox Code Playgroud)

输出

<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
Run Code Online (Sandbox Code Playgroud)

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

 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])))
Run Code Online (Sandbox Code Playgroud)

输出

<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
Run Code Online (Sandbox Code Playgroud)

如果你的代码是固定的

K.set_value(model.layers[0].states[0], np.random.randn(10,2))
Run Code Online (Sandbox Code Playgroud)

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