Keras - "Convert" 训练有素的多对多模型到一对多模型(生成器)

Keras - "Convert" a trained many-to-many model to one-to-many model (generator)

我正在尝试使用 Reber Grammar inputs (not embedded for now). You can find the jupyter notebook on this link 来理解 RNN(不是特定的)(请忽略降价,因为我在第一个版本上失败了输出并且它不是最新的日期 :) )

对于每个时间步,我都提供训练的输入和预期输出(因此它是一个多对多模型)。

所以我决定将它们填充到 20 个时间步长。

所以我的输入张量是 (2048, 20, 7)。我的输出张量也是 (2048, 20, 7) 因为对于每个时间步我都想得到预测。

所以我像下面的代码一样训练了 3 个多对多模型(Simple RNN、GRU 和 LSTM)。

model = Sequential()

model.add(LSTM(units=7, input_shape=(maxlen, 7), return_sequences=True))
model.compile(loss='mse',
              optimizer='Nadam',
              metrics=['mean_squared_error'])

history = model.fit(X_train, y_train, validation_data=(X_test, y_test), 
                    epochs=1500, batch_size=1024)

正如预期的那样,对于每个时间步长,我都有可能获得特定值,例如(经过一些清理后):

B predict [ 0, 0.622, 0, 0, 0.401, 0, 0] (60% of having a T or 40% of having P )

根据图生成一个词是正确的


现在,我想使用此模型生成字符串(因此是一对多模型),但我不知道如何保留该模型并将其用作生成器。

我想只输入 B 的输入(填充到 20 个时间步长),得到结果,将 B 与输出的最佳索引连接起来,填充到 20 个时间步长,将需要的输入提供给 NN 和很快。但我很确定这不是我们应该做的方式:s

此外,我尝试输入'B'和'T'来检查输出的概率是多少(应该是S或X)但是我得到了:

X = np.array([[[1,0,0,0,0,0,0], [0,1,0,0,0,0,0]]])  # [[[B, P]]]
X = sequence.pad_sequences(X, maxlen=20)
print(model.predict(X)[0])

[0, 0.106, 0.587, 0.1, 0, 0.171, 0.007]

我的理解是预测 T(10%)、S(60%)、X(10%)、V (18%) 但是在 BT 之后,我应该在 X 上获得更多百分比并且几乎 none on V/T(因为 T 之后的 V 和 T 仅在 B/P 之后才有可能)。就像我的模型没有考虑 n-1 个时间步长一样。所以也许我的模型是错误的:(

非常感谢您的支持,

您可以将此模型重新制作为 stateful=True 模型。使其与 timesteps=1 (或 None 可变长度)一起使用。

改造模型:

newModel = Sequential()

newModel.add(LSTM(units=7, stateful=True,batch_input_shape=(1,1,7), return_sequences=True))

从另一个模型获取权重:

newModel.set_weights(model.get_weights())

在预测中使用模型:

现在,使用此模型,您一次只需输入一个步骤。并且每次要输入新序列时都必须小心reset_states()

所以,假设我们有起始字母 B

startingLetter = oneHotForBWithShape((1,1,7))


#we are starting a new "sentence", so, let's reset states:
newModel.reset_states()

#now the prediction loop:
nextLetter = startingLetter
while nextLetter != endLetter:
    nextLetter = newModel.predict(nextLetter)
    nextLetter = chooseOneFromTheProbabilities(nextLetter)

关于结果的质量....也许您的模型太小了。

您可以尝试更多层,例如:

model = Sequential()

model.add(LSTM(units=50, input_shape=(maxlen, 7), return_sequences=True))
model.add(LSTM(units=30, return_sequences=True))
model.add(LSTM(units=7, return_sequences=True))

这个选择是随意的,我不知道它对你的数据来说是够好还是太好。