GRU/LSTM 在 Keras 中具有不同长度的输入序列
GRU/LSTM in Keras with input sequence of varying length
我正在从事一个较小的项目,以更好地理解 RNN,尤其是 LSTM 和 GRU。我不是专家,所以请记住这一点。
我面临的问题以以下形式的数据给出:
>>> import numpy as np
>>> import pandas as pd
>>> pd.DataFrame([[1, 2, 3],[1, 2, 1], [1, 3, 2],[2, 3, 1],[3, 1, 1],[3, 3, 2],[4, 3, 3]], columns=['person', 'interaction', 'group'])
person interaction group
0 1 2 3
1 1 2 1
2 1 3 2
3 2 3 1
4 3 1 1
5 3 3 2
6 4 3 3
这只是为了解释。我们有不同的人以不同的方式与不同的群体互动。我已经对各种功能进行了编码。用户的最后一次交互总是3
,即选择某个组。在上面的简短示例中,person 1
选择组 2
,person 2
选择组 1
等等。
我的整个数据集要大得多,但我想先了解概念部分,然后再使用模型。我想学习的任务给出了一系列交互,哪个组由人选择。更具体一点,我想要一个输出列表,其中包含所有组(有 3 个组,1, 2, 3
)按最可能的选择排序,然后是第二和第三个最喜欢的组。因此,损失函数是平均倒数排名。
我知道 Keras Grus/LSTM 可以处理各种长度的输入。所以我的三个问题是。
输入格式为:
(samples, timesteps, features)
编写高级代码:
import keras.layers as L
import keras.models as M
model_input = L.Input(shape=(?, None, 2))
timestep=None
应该表示不同的大小,2
是针对特征 interaction
和 group
。但是样本呢?如何定义批次?
对于输出结果,我有点疑惑在这个例子中它应该是什么样子?我想对于一个人的每一次最后一次互动,我都希望有一个长度为 3
的列表。假设我已经设置了输出
model_output = L.LSTM(3, return_sequences=False)
然后我想编译它。有没有办法使用平均倒数排名?
model.compile('adam', '?')
我知道这些问题的水平很高,但我想先了解大局并开始尝试。因此,我们将不胜感激。
你在问题中提出的概念已经是一个很好的开始。我将添加一些内容以使其工作,以及下面的代码示例:
- 您可以直接指定
LSTM(n_hidden, input_shape=(None, 2))
,而不是插入额外的Input
层;定义中将省略批量维度。
- 由于您的模型将执行某种 class化(基于时间序列数据),最后一层是我们对 "normal" class化的期望,因为嗯,一个
Dense(num_classes, action='softmax')
。将 LSTM
和 Dense
层链接在一起将首先通过 LSTM
层传递时间序列输入,然后将其输出(由隐藏单元的数量确定)馈送到 Dense
层。 activation='softmax'
允许为每个 class 计算一个 class 分数(我们将在数据预处理步骤中使用单热编码,请参见下面的代码示例)。这意味着 class 分数未排序,但您始终可以通过 np.argsort
或 np.argmax
. 排序
- 分类交叉熵损失适合比较 class化分,所以我们将使用那个:
model.compile(loss='categorical_crossentropy', optimizer='adam')
.
- 以来互动次数。即模型输入的长度因样本而异,我们将使用 1 的批量大小并一次输入一个样本。
以下是上述注意事项的实施示例 w.r.t。请注意,我稍微修改了您的示例数据,以便在组选择后面提供更多 "reasoning"。此外,每个人在选择一组之前需要进行至少一次交互(即输入序列不能为空);如果您的数据不是这种情况,那么引入额外的无操作交互(例如 0
)会有所帮助。
import pandas as pd
import tensorflow as tf
model = tf.keras.models.Sequential()
model.add(tf.keras.layers.LSTM(10, input_shape=(None, 2))) # LSTM for arbitrary length series.
model.add(tf.keras.layers.Dense(3, activation='softmax')) # Softmax for class probabilities.
model.compile(loss='categorical_crossentropy', optimizer='adam')
# Example interactions:
# * 1: Likes the group,
# * 2: Dislikes the group,
# * 3: Chooses the group.
df = pd.DataFrame([
[1, 1, 3],
[1, 1, 3],
[1, 2, 2],
[1, 3, 3],
[2, 2, 1],
[2, 2, 3],
[2, 1, 2],
[2, 3, 2],
[3, 1, 1],
[3, 1, 1],
[3, 1, 1],
[3, 2, 3],
[3, 2, 2],
[3, 3, 1]],
columns=['person', 'interaction', 'group']
)
data = [person[1][['interaction', 'group']].values for person in df.groupby('person')]
x_train = [x[:-1] for x in data]
y_train = tf.keras.utils.to_categorical([x[-1, 1]-1 for x in data]) # Expects class labels from 0 to n (-> subtract 1).
print(x_train)
print(y_train)
class TrainGenerator(tf.keras.utils.Sequence):
def __init__(self, x, y):
self.x = x
self.y = y
def __len__(self):
return len(self.x)
def __getitem__(self, index):
# Need to expand arrays to have batch size 1.
return self.x[index][None, :, :], self.y[index][None, :]
model.fit_generator(TrainGenerator(x_train, y_train), epochs=1000)
pred = [model.predict(x[None, :, :]).ravel() for x in x_train]
for p, y in zip(pred, y_train):
print(p, y)
以及对应的样本输出:
[...]
Epoch 1000/1000
3/3 [==============================] - 0s 40ms/step - loss: 0.0037
[0.00213619 0.00241093 0.9954529 ] [0. 0. 1.]
[0.00123938 0.99718493 0.00157572] [0. 1. 0.]
[9.9632275e-01 7.5039308e-04 2.9268670e-03] [1. 0. 0.]
使用自定义生成器表达式: 根据 the documentation we can use any generator to yield the data. The generator is expected to yield batches of the data and loop over the whole data set indefinitely. When using tf.keras.utils.Sequence
我们不需要指定参数 steps_per_epoch
因为这将默认为 len(train_generator)
.因此,在使用自定义生成器时,我们还要提供这个参数:
import itertools as it
model.fit_generator(((x_train[i % len(x_train)][None, :, :],
y_train[i % len(y_train)][None, :]) for i in it.count()),
epochs=1000,
steps_per_epoch=len(x_train))
我正在从事一个较小的项目,以更好地理解 RNN,尤其是 LSTM 和 GRU。我不是专家,所以请记住这一点。
我面临的问题以以下形式的数据给出:
>>> import numpy as np
>>> import pandas as pd
>>> pd.DataFrame([[1, 2, 3],[1, 2, 1], [1, 3, 2],[2, 3, 1],[3, 1, 1],[3, 3, 2],[4, 3, 3]], columns=['person', 'interaction', 'group'])
person interaction group
0 1 2 3
1 1 2 1
2 1 3 2
3 2 3 1
4 3 1 1
5 3 3 2
6 4 3 3
这只是为了解释。我们有不同的人以不同的方式与不同的群体互动。我已经对各种功能进行了编码。用户的最后一次交互总是3
,即选择某个组。在上面的简短示例中,person 1
选择组 2
,person 2
选择组 1
等等。
我的整个数据集要大得多,但我想先了解概念部分,然后再使用模型。我想学习的任务给出了一系列交互,哪个组由人选择。更具体一点,我想要一个输出列表,其中包含所有组(有 3 个组,1, 2, 3
)按最可能的选择排序,然后是第二和第三个最喜欢的组。因此,损失函数是平均倒数排名。
我知道 Keras Grus/LSTM 可以处理各种长度的输入。所以我的三个问题是。
输入格式为:
(samples, timesteps, features)
编写高级代码:
import keras.layers as L
import keras.models as M
model_input = L.Input(shape=(?, None, 2))
timestep=None
应该表示不同的大小,2
是针对特征 interaction
和 group
。但是样本呢?如何定义批次?
对于输出结果,我有点疑惑在这个例子中它应该是什么样子?我想对于一个人的每一次最后一次互动,我都希望有一个长度为 3
的列表。假设我已经设置了输出
model_output = L.LSTM(3, return_sequences=False)
然后我想编译它。有没有办法使用平均倒数排名?
model.compile('adam', '?')
我知道这些问题的水平很高,但我想先了解大局并开始尝试。因此,我们将不胜感激。
你在问题中提出的概念已经是一个很好的开始。我将添加一些内容以使其工作,以及下面的代码示例:
- 您可以直接指定
LSTM(n_hidden, input_shape=(None, 2))
,而不是插入额外的Input
层;定义中将省略批量维度。 - 由于您的模型将执行某种 class化(基于时间序列数据),最后一层是我们对 "normal" class化的期望,因为嗯,一个
Dense(num_classes, action='softmax')
。将LSTM
和Dense
层链接在一起将首先通过LSTM
层传递时间序列输入,然后将其输出(由隐藏单元的数量确定)馈送到Dense
层。activation='softmax'
允许为每个 class 计算一个 class 分数(我们将在数据预处理步骤中使用单热编码,请参见下面的代码示例)。这意味着 class 分数未排序,但您始终可以通过np.argsort
或np.argmax
. 排序
- 分类交叉熵损失适合比较 class化分,所以我们将使用那个:
model.compile(loss='categorical_crossentropy', optimizer='adam')
. - 以来互动次数。即模型输入的长度因样本而异,我们将使用 1 的批量大小并一次输入一个样本。
以下是上述注意事项的实施示例 w.r.t。请注意,我稍微修改了您的示例数据,以便在组选择后面提供更多 "reasoning"。此外,每个人在选择一组之前需要进行至少一次交互(即输入序列不能为空);如果您的数据不是这种情况,那么引入额外的无操作交互(例如 0
)会有所帮助。
import pandas as pd
import tensorflow as tf
model = tf.keras.models.Sequential()
model.add(tf.keras.layers.LSTM(10, input_shape=(None, 2))) # LSTM for arbitrary length series.
model.add(tf.keras.layers.Dense(3, activation='softmax')) # Softmax for class probabilities.
model.compile(loss='categorical_crossentropy', optimizer='adam')
# Example interactions:
# * 1: Likes the group,
# * 2: Dislikes the group,
# * 3: Chooses the group.
df = pd.DataFrame([
[1, 1, 3],
[1, 1, 3],
[1, 2, 2],
[1, 3, 3],
[2, 2, 1],
[2, 2, 3],
[2, 1, 2],
[2, 3, 2],
[3, 1, 1],
[3, 1, 1],
[3, 1, 1],
[3, 2, 3],
[3, 2, 2],
[3, 3, 1]],
columns=['person', 'interaction', 'group']
)
data = [person[1][['interaction', 'group']].values for person in df.groupby('person')]
x_train = [x[:-1] for x in data]
y_train = tf.keras.utils.to_categorical([x[-1, 1]-1 for x in data]) # Expects class labels from 0 to n (-> subtract 1).
print(x_train)
print(y_train)
class TrainGenerator(tf.keras.utils.Sequence):
def __init__(self, x, y):
self.x = x
self.y = y
def __len__(self):
return len(self.x)
def __getitem__(self, index):
# Need to expand arrays to have batch size 1.
return self.x[index][None, :, :], self.y[index][None, :]
model.fit_generator(TrainGenerator(x_train, y_train), epochs=1000)
pred = [model.predict(x[None, :, :]).ravel() for x in x_train]
for p, y in zip(pred, y_train):
print(p, y)
以及对应的样本输出:
[...]
Epoch 1000/1000
3/3 [==============================] - 0s 40ms/step - loss: 0.0037
[0.00213619 0.00241093 0.9954529 ] [0. 0. 1.]
[0.00123938 0.99718493 0.00157572] [0. 1. 0.]
[9.9632275e-01 7.5039308e-04 2.9268670e-03] [1. 0. 0.]
使用自定义生成器表达式: 根据 the documentation we can use any generator to yield the data. The generator is expected to yield batches of the data and loop over the whole data set indefinitely. When using tf.keras.utils.Sequence
我们不需要指定参数 steps_per_epoch
因为这将默认为 len(train_generator)
.因此,在使用自定义生成器时,我们还要提供这个参数:
import itertools as it
model.fit_generator(((x_train[i % len(x_train)][None, :, :],
y_train[i % len(y_train)][None, :]) for i in it.count()),
epochs=1000,
steps_per_epoch=len(x_train))