我正在尝试使用以下模型生成莎士比亚文本:
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笔记本示例是here:
我刚刚意识到我需要发送以前的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
个输入。
答案 0 :(得分:1)
使用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必须知道批次的完整形状(参见文档here)。 由于您只想为网络提供一步字符的一个样本,因此批处理的形状为(1,1,len(字符))。
答案 1 :(得分:0)
正如@ 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
是否通过了隐藏状态,或者它是否只是单元状态。