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(不是特定的)(请忽略降价,因为我在第一个版本上失败了输出并且它不是最新的日期 :) )。
对于每个时间步,我都提供训练的输入和预期输出(因此它是一个多对多模型)。
Input/output 是 "OneHotEncoded"(基于字符串 "BTSXPVE")所以例如
- B is [1, 0, 0, 0, 0, 0, 0]
- V is [0, 0, 0, 0, 0, 1, 0]
对于时间步长,我有一个长度未知的字符串(这里没有编码以使其更清楚)例如:
- BPVVE
- BPVPXVPXVPXVVE
所以我决定将它们填充到 20 个时间步长。
- 对于批次,我有空。我生成了 2048 个用于训练的编码字符串和 256 个用于测试的编码字符串。
所以我的输入张量是 (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))
这个选择是随意的,我不知道它对你的数据来说是够好还是太好。
我正在尝试使用 Reber Grammar inputs (not embedded for now). You can find the jupyter notebook on this link 来理解 RNN(不是特定的)(请忽略降价,因为我在第一个版本上失败了输出并且它不是最新的日期 :) )。
对于每个时间步,我都提供训练的输入和预期输出(因此它是一个多对多模型)。
Input/output 是 "OneHotEncoded"(基于字符串 "BTSXPVE")所以例如
- B is [1, 0, 0, 0, 0, 0, 0]
- V is [0, 0, 0, 0, 0, 1, 0]
对于时间步长,我有一个长度未知的字符串(这里没有编码以使其更清楚)例如:
- BPVVE
- BPVPXVPXVPXVVE
所以我决定将它们填充到 20 个时间步长。
- 对于批次,我有空。我生成了 2048 个用于训练的编码字符串和 256 个用于测试的编码字符串。
所以我的输入张量是 (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))
这个选择是随意的,我不知道它对你的数据来说是够好还是太好。