获取 LSTM 中的预测状态



我正在尝试使用以下模型生成莎士比亚文本:

model = Sequential()
model.add(Embedding(len_vocab, 64))
model.add(LSTM(256, return_sequences=True))
model.add(TimeDistributed(Dense(len_vocab, activation='softmax')))
model.compile(loss='sparse_categorical_crossentropy', optimizer='adam')
model.summary()

训练集由转换为数字的字符组成。其中x的形状为(num_sentences, sentence_len)y的形状相同,其中y只是x偏移一个字符。在这种情况下sentence_len=40.

但是,当我预测时,我一次预测一个角色。请参阅下文,了解如何使用该模型进行拟合和预测:

for i in range(2):
model.fit(x,y, batch_size=128, epochs=1)
sentence = []
letter = np.random.choice(len_vocab,1).reshape((1,1)) #choose a random letter
for i in range(100):
sentence.append(val2chr(letter))
# Predict ONE letter at a time
p = model.predict(letter)
letter = np.random.choice(27,1,p=p[0][0])
print(''.join(sentence))

然而,无论我训练多少个时期,我得到的输出都是乱七八糟的。其中一个可能的原因是我没有从之前的预测中获得细胞记忆

所以问题是我如何确保在预测之前将状态发送到下一个单元格?

完整的 jupyter 笔记本示例在这里:

编辑 1:

我刚刚意识到我需要发送以前的 LSTM 隐藏状态,而不仅仅是单元内存。 此后,我尝试将模型重做为:

batch_size = 64
model = Sequential()
model.add(Embedding(len_vocab, 64, batch_size=batch_size))
model.add(LSTM(256, return_sequences=True, stateful=True))
model.add(TimeDistributed(Dense(len_vocab, activation='softmax')))
model.compile(loss='sparse_categorical_crossentropy', optimizer='adam')
model.summary()

但是,现在我无法一次预测一个字母,因为它需要batch_size输入。

使用 Keras 训练 char-rnn 的标准方法可以在官方示例中找到:lstm_text_generation.py。

model = Sequential()
model.add(LSTM(128, input_shape=(maxlen, len(chars))))
model.add(Dense(len(chars)))
model.add(Activation('softmax'))

此模型基于 maxlen 字符序列进行训练。 在训练此网络时,LSTM 状态在每个序列后重置(默认情况下为 stateful=False(。

一旦训练了这样的网络,你可能希望一次输入和预测一个角色。最简单的方法(我知道(是构建另一个具有相同结构的 Keras 模型,使用第一个模型的权重对其进行初始化,但在 Keras "有状态"模式下使用 RNN 层:

model = Sequential()
model.add(LSTM(128, stateful=True, batch_input_shape=(1, 1, len(chars))))
model.add(Dense(len(chars)))
model.add(Activation('softmax'))

在这种模式下,Keras 必须知道批次的完整形状(请参阅此处的文档(。 由于您只想向网络提供一步字符的一个样本,因此批处理的形状为 (1, 1, len(chars((。

正如 @j-c-doe 指出的那样,您可以将有状态选项与批次一起使用 1 并转移权重。我发现的另一种方法是继续展开 LSTM 并预测如下:

for i in range(150):
sentence.append(int2char[letter[-1]])
p = model.predict(np.array(letter)[None,:])
letter.append(np.random.choice(len(char2int),1,p=p[0][-1])[0])

注意:预测的维度非常重要!np.array(letter)[None,:]给人一种(1,i+1)形状。这样就不需要修改模型。

最重要的是,它不断传递细胞状态记忆和隐藏状态。我不完全确定stateful=True它是否也传递了隐藏状态,或者它是否只传递了单元格状态。

最新更新