Keras 序列模型 - 如何在 test/generation 期间生成数据?
Keras sequence models - how to generate data during test/generation?
有没有办法在Keras中使用已经训练好的RNN(SimpleRNN或LSTM)模型生成新的序列?
我正在尝试修改 Coursera 深度学习专业化 - Sequence Models 课程中的练习,在该课程中,您训练 RNN 来生成恐龙的名字。在练习中,您仅使用 numpy 构建 RNN,但我想使用 Keras。
其中一个问题是序列(恐龙名称)的长度不同,所以我使用填充并将序列长度设置为数据集中出现的最大大小(我用 0 填充,这也是'\n').
的代码
我的问题是训练完成后如何生成实际序列?在练习的 numpy 版本中,您获取前一个单元格的 softmax 输出并将其用作分布以对下一个单元格的新输入进行采样。但是有没有办法在 testing/generation 时间内将前一个单元格的输出连接为 Keras 中下一个单元格的输入?
另外 - 一些额外的问题:
- 由于我使用了填充,我怀疑准确性过于乐观。有没有办法告诉 Keras 不要在其精度计算中包含填充值?
我这样做对吗?有没有更好的方法来使用具有不同长度序列的 Keras?
您可以查看我的 (WIP) 代码 here。
从已在序列上训练的模型进行推断
因此,在 RNN 模型和 Keras 中,最好的方法(至少据我所知)是创建两个不同的模型。
- 一个训练模型(使用序列而不是单个项目)
- 另一种预测模型(使用单个元素而不是序列)
让我们看一个例子。假设您有以下模型。
from tensorflow.keras import models, layers
n_chars = 26
timesteps = 10
inp = layers.Input(shape=(timesteps, n_chars))
lstm = layers.LSTM(100, return_sequences=True)
out1 = lstm(inp)
dense = layers.Dense(n_chars, activation='softmax')
out2 = layers.TimeDistributed(dense)(out1)
model = models.Model(inp, out2)
model.summary()
现在从这个模型推断,你创建另一个模型,如下图所示。
inp_infer = layers.Input(shape=(1, n_chars))
# Inputs to feed LSTM states back in
h_inp_infer = layers.Input(shape=(100,))
c_inp_infer = layers.Input(shape=(100,))
# We need return_state=True so we are creating a new layer
lstm_infer = layers.LSTM(100, return_state=True, return_sequences=True)
out1_infer, h, c = lstm_infer(inp_infer, initial_state=[h_inp_infer, c_inp_infer])
out2_infer = layers.TimeDistributed(dense)(out1_infer)
# Our model takes the previous states as inputs and spits out new states as outputs
model_infer = models.Model([inp_infer, h_inp_infer, c_inp_infer], [out2_infer, h, c])
# We are setting the weights from the trained model
lstm_infer.set_weights(lstm.get_weights())
model_infer.summary()
所以有什么不同。您会看到我们已经定义了一个新的输入层,它接受只有一个时间步长的输入(或者换句话说,只有一个项目)。然后模型输出一个具有单个时间步长的输出(从技术上讲,我们不需要 TimeDistributedLayer
。但为了保持一致性,我保留了它)。除此之外,我们将先前的 LSTM 状态输出作为输入,并产生新的状态作为输出。更具体地说,我们有以下推理模型。
- 输入:
[(None, 1, n_chars) (None, 100), (None, 100)]
张量列表
- 输出:
[(None, 1, n_chars), (None, 100), (None, 100)]
张量列表
请注意,我正在更新训练模型中新层的权重或使用训练模型中的现有层。如果您不重复使用经过训练的层和权重,这将是一个非常无用的模型。
现在我们可以编写推理逻辑了。
import numpy as np
x = np.random.randint(0,2,size=(1, 1, n_chars))
h = np.zeros(shape=(1, 100))
c = np.zeros(shape=(1, 100))
seq_len = 10
for _ in range(seq_len):
print(x)
y_pred, h, c = model_infer.predict([x, h, c])
y_pred = x[:,0,:]
y_onehot = np.zeros(shape=(x.shape[0],n_chars))
y_onehot[np.arange(x.shape[0]),np.argmax(y_pred,axis=1)] = 1.0
x = np.expand_dims(y_onehot, axis=1)
这部分以首字母 x, h, c
开头。获取预测 y_pred, h, c
并将其转换为以下行中的输入并将其分配回 x, h, c
。因此,您继续选择 n
次迭代。
关于屏蔽零
Keras 确实提供了一个 Masking
layer which can be used for this purpose. And the second answer in 问题,这似乎正是您要找的问题。
有没有办法在Keras中使用已经训练好的RNN(SimpleRNN或LSTM)模型生成新的序列?
我正在尝试修改 Coursera 深度学习专业化 - Sequence Models 课程中的练习,在该课程中,您训练 RNN 来生成恐龙的名字。在练习中,您仅使用 numpy 构建 RNN,但我想使用 Keras。
其中一个问题是序列(恐龙名称)的长度不同,所以我使用填充并将序列长度设置为数据集中出现的最大大小(我用 0 填充,这也是'\n').
的代码我的问题是训练完成后如何生成实际序列?在练习的 numpy 版本中,您获取前一个单元格的 softmax 输出并将其用作分布以对下一个单元格的新输入进行采样。但是有没有办法在 testing/generation 时间内将前一个单元格的输出连接为 Keras 中下一个单元格的输入?
另外 - 一些额外的问题:
- 由于我使用了填充,我怀疑准确性过于乐观。有没有办法告诉 Keras 不要在其精度计算中包含填充值?
我这样做对吗?有没有更好的方法来使用具有不同长度序列的 Keras?
您可以查看我的 (WIP) 代码 here。
从已在序列上训练的模型进行推断
因此,在 RNN 模型和 Keras 中,最好的方法(至少据我所知)是创建两个不同的模型。
- 一个训练模型(使用序列而不是单个项目)
- 另一种预测模型(使用单个元素而不是序列)
让我们看一个例子。假设您有以下模型。
from tensorflow.keras import models, layers
n_chars = 26
timesteps = 10
inp = layers.Input(shape=(timesteps, n_chars))
lstm = layers.LSTM(100, return_sequences=True)
out1 = lstm(inp)
dense = layers.Dense(n_chars, activation='softmax')
out2 = layers.TimeDistributed(dense)(out1)
model = models.Model(inp, out2)
model.summary()
现在从这个模型推断,你创建另一个模型,如下图所示。
inp_infer = layers.Input(shape=(1, n_chars))
# Inputs to feed LSTM states back in
h_inp_infer = layers.Input(shape=(100,))
c_inp_infer = layers.Input(shape=(100,))
# We need return_state=True so we are creating a new layer
lstm_infer = layers.LSTM(100, return_state=True, return_sequences=True)
out1_infer, h, c = lstm_infer(inp_infer, initial_state=[h_inp_infer, c_inp_infer])
out2_infer = layers.TimeDistributed(dense)(out1_infer)
# Our model takes the previous states as inputs and spits out new states as outputs
model_infer = models.Model([inp_infer, h_inp_infer, c_inp_infer], [out2_infer, h, c])
# We are setting the weights from the trained model
lstm_infer.set_weights(lstm.get_weights())
model_infer.summary()
所以有什么不同。您会看到我们已经定义了一个新的输入层,它接受只有一个时间步长的输入(或者换句话说,只有一个项目)。然后模型输出一个具有单个时间步长的输出(从技术上讲,我们不需要 TimeDistributedLayer
。但为了保持一致性,我保留了它)。除此之外,我们将先前的 LSTM 状态输出作为输入,并产生新的状态作为输出。更具体地说,我们有以下推理模型。
- 输入:
[(None, 1, n_chars) (None, 100), (None, 100)]
张量列表 - 输出:
[(None, 1, n_chars), (None, 100), (None, 100)]
张量列表
请注意,我正在更新训练模型中新层的权重或使用训练模型中的现有层。如果您不重复使用经过训练的层和权重,这将是一个非常无用的模型。
现在我们可以编写推理逻辑了。
import numpy as np
x = np.random.randint(0,2,size=(1, 1, n_chars))
h = np.zeros(shape=(1, 100))
c = np.zeros(shape=(1, 100))
seq_len = 10
for _ in range(seq_len):
print(x)
y_pred, h, c = model_infer.predict([x, h, c])
y_pred = x[:,0,:]
y_onehot = np.zeros(shape=(x.shape[0],n_chars))
y_onehot[np.arange(x.shape[0]),np.argmax(y_pred,axis=1)] = 1.0
x = np.expand_dims(y_onehot, axis=1)
这部分以首字母 x, h, c
开头。获取预测 y_pred, h, c
并将其转换为以下行中的输入并将其分配回 x, h, c
。因此,您继续选择 n
次迭代。
关于屏蔽零
Keras 确实提供了一个 Masking
layer which can be used for this purpose. And the second answer in