python - 对可变长度序列进行训练和预测
问题描述
分散在我网站上的传感器(相同类型)正在不定期地手动向我的后端报告。在报告之间,传感器聚合事件并将它们作为一个批次报告。
以下数据集是序列事件数据的集合,批量收集。例如传感器 1 报告了 2 次。在第一批 2 个事件和第二批 3 个事件上,而传感器 2 报告了 1 次和 3 个事件。
我想将此数据用作我的火车数据X
sensor_id | batch_id | 时间戳 | 特征_1 | 特征_n |
---|---|---|---|---|
1 | 1 | 2020-12-21T00:00:00+00:00 | 0.54 | 0.33 |
1 | 1 | 2020-12-21T01:00:00+00:00 | 0.23 | 0.14 |
1 | 2 | 2020-12-21T03:00:00+00:00 | 0.51 | 0.13 |
1 | 2 | 2020-12-21T04:00:00+00:00 | 0.23 | 0.24 |
1 | 2 | 2020-12-21T05:00:00+00:00 | 0.33 | 0.44 |
2 | 1 | 2020-12-21T00:00:00+00:00 | 0.54 | 0.33 |
2 | 1 | 2020-12-21T01:00:00+00:00 | 0.23 | 0.14 |
2 | 1 | 2020-12-21T03:00:00+00:00 | 0.51 | 0.13 |
我的目标y是根据传感器收集的所有事件计算得出的分数:
IEsocre_sensor_1 = f([[batch1...],[batch2...]])
sensor_id | final_score |
---|---|
1 | 0.8 |
2 | 0.6 |
我想在每次收集批次时预测y ,IE 2 预测具有 2 个报告的传感器。
LSTM 模型:
我从 LSTM 模型开始,因为我试图预测事件的时间序列。我的第一个想法是选择一个固定大小的输入,并在收集的事件数小于输入大小时对输入进行零填充。然后屏蔽填充值:
model.add(Masking(mask_value=0., input_shape=(num_samples, num_features)))
例如:
sensor_id | batch_id | 时间戳 | 特征_1 | 特征_n |
---|---|---|---|---|
1 | 1 | 2020-12-21T00:00:00+00:00 | 0.54 | 0.33 |
1 | 1 | 2020-12-21T01:00:00+00:00 | 0.23 | 0.14 |
如果选择的长度为 5,将产生以下输入:
[
[0.54, 0.33],
[0.23, 0.14],
[0,0],
[0,0],
[0,0]
]
但是,我的火车数据中每个传感器报告的事件数量差异很大,一份报告可以收集 1000 个事件,而另一份可以收集 10 个。因此,如果我选择平均大小(比如说 200),一些输入会有很多填充,而其他会被截断并且数据会丢失。
我听说过ragged tensors,但我不确定它是否适合我的用例。如何解决这样的问题?
解决方案
使用可变大小的输入序列非常简单。虽然每个批次中具有相同大小的序列是有限制的,但存在NO RESTRICTION of having variable-sized sequences between the batches
. 利用这一点,您可以简单地将 LSTM 的输入序列设置为(None, features)
并batch_size
用作 1。
让我们创建一个生成器,该生成器生成 2 个特征的可变长度序列和一个随机浮点分数,您根据这些序列寻找一个随机浮点分数,类似于传感器的输入数据。
#Infinitely creates batches of dummy data
def generator():
while True:
length = np.random.randint(2, 10) #Variable length sequences
x_train = np.random.random((1, length, 2)) #batch, seq, features
y_train = np.random.random((1,1)) #batch, score
yield x_train, y_train
next(generator())
#x.shape = (1,4,2), y.shape = (1,1)
(array([[[0.63841991, 0.91141833],
[0.73131801, 0.92771373],
[0.61298585, 0.6455549 ],
[0.25893925, 0.40202978]]]),
array([[0.05934613]]))
上面是由生成器创建的 4 长度序列的示例,而下一个是 9 长度序列。
next(generator())
#x.shape = (1,9,2), y.shape = (1,1)
(array([[[0.76006158, 0.27457503],
[0.57739596, 0.75416962],
[0.03029365, 0.29339812],
[0.93866829, 0.79137367],
[0.52739961, 0.11475738],
[0.85832651, 0.19247399],
[0.37098216, 0.48703114],
[0.95846681, 0.15507787],
[0.86945015, 0.70949593]]]),
array([[0.02560889]]))
现在,让我们创建一个基于 LSTM 的神经网络,它可以处理每个批次的这些可变大小的序列。
from tensorflow.keras import layers, Model, utils
inp = layers.Input((None, 2))
x = layers.LSTM(10, return_sequences=True)(inp)
x = layers.LSTM(10)(x)
out = layers.Dense(1)(x)
model = Model(inp, out)
utils.plot_model(model, show_layer_names=False, show_shapes=True)
以 1 的批大小训练这些 -
model.compile(loss='binary_crossentropy', optimizer='adam')
model.fit(generator(), steps_per_epoch=100, epochs=10, batch_size=1)
#Steps_per_epoch is to stop the generator from generating infinite batches of data per epoch.
Epoch 1/10
100/100 [==============================] - 1s 5ms/step - loss: 1.5145
Epoch 2/10
100/100 [==============================] - 0s 5ms/step - loss: 0.7435
Epoch 3/10
100/100 [==============================] - 0s 4ms/step - loss: 0.7885
Epoch 4/10
100/100 [==============================] - 0s 4ms/step - loss: 0.7384
Epoch 5/10
100/100 [==============================] - 0s 4ms/step - loss: 0.7139
Epoch 6/10
100/100 [==============================] - 0s 5ms/step - loss: 0.7462
Epoch 7/10
100/100 [==============================] - 0s 4ms/step - loss: 0.7173
Epoch 8/10
100/100 [==============================] - 0s 4ms/step - loss: 0.7116
Epoch 9/10
100/100 [==============================] - 0s 4ms/step - loss: 0.6875
Epoch 10/10
100/100 [==============================] - 0s 4ms/step - loss: 0.7153
这就是您可以使用可变大小的序列作为输入的方式。只有属于同一批次的序列才需要填充/屏蔽。
现在,您可以为输入数据创建一个生成器,该生成器一次生成一个事件序列作为模型的输入,在这种情况下,您不需要显式指定,batch_size
因为您已经一次生成一个序列。
如果您的数据采用数据集、生成器或 keras.utils.Sequence 实例的形式(因为它们会生成批次),请不要指定 batch_size。
或者您可以使用您提到的参差不齐的张量batch_size
并为每个序列提供 1。就个人而言,我更喜欢使用生成器来训练数据,因为它也为您提供了更大的预处理灵活性。
有趣的是,您可以optimize
进一步编写此代码,但将相同长度序列的批次捆绑在一起,然后将variable batch size
. 如果您有大量数据并且无法为每次梯度更新运行 1 的 batch_size ,这将有所帮助!
另一个警告!如果您的序列非常长,那么我建议使用(在此处Truncated Backpropagation through time (TBPTT)
查找详细信息)。
希望这可以解决您正在寻找的问题。
推荐阅读
- dictionary - 没有为类“对象”定义运算符“[]”。镖
- angular - 跨域请求被阻止:同源策略不允许读取远程资源 [Twitter API]
- byte-buddy - 在 ByteBuddy 中附加远程主机进程
- mysql - 查询包含多个案例时查找下一个或上一个 ID
- lua - 如何使用 Lua 进行搜索过滤器读取文件并将条目存储为变量
- automation - 我可以使用什么语言(或框架)来构建自动在网站中执行某些特定任务
- python - pip install keras-retinanet==0.5.0 OSError: [WinError 193] %1 不是有效的 Win32 应用程序
- c - 为什么我包含 stdio.h 时没有声明“gets()”函数?
- gdb - mingw gdb 没有布局命令
- laravel - 我可以在 laravel 中保存标签标题吗?