Python Keras中具有可变序列长度的序列到序列分类

Python Keras中具有可变序列长度的序列到序列分类,python,keras,lstm,Python,Keras,Lstm,我想在TensorFlow/Keras中训练一个LSTM或GRU网络,以根据运动传感器(加速计和陀螺仪)的输入持续识别用户是否在行走。我有50个输入序列,长度从581到5629个时间步,6个特征和50个相应的布尔值输出序列。我的问题是,我不知道如何将训练数据提供给fit()方法 我大致知道我需要做什么:我想训练5批,每组10个序列,对于每批,我必须填充除最长序列外的所有序列,以便所有10个序列具有相同的长度并应用掩蔽。我只是不知道如何构建数据结构。我知道我可以制作一个大小为(505629,6)的

我想在TensorFlow/Keras中训练一个LSTM或GRU网络,以根据运动传感器(加速计和陀螺仪)的输入持续识别用户是否在行走。我有50个输入序列,长度从581到5629个时间步,6个特征和50个相应的布尔值输出序列。我的问题是,我不知道如何将训练数据提供给fit()方法

我大致知道我需要做什么:我想训练5批,每组10个序列,对于每批,我必须填充除最长序列外的所有序列,以便所有10个序列具有相同的长度并应用掩蔽。我只是不知道如何构建数据结构。我知道我可以制作一个大小为(505629,6)的大3D张量,这是可行的,但它的速度非常慢,所以我真的希望使每个批次的序列长度尽可能小

下面是代码中的问题:

import tensorflow as tf
import numpy as np

# Load data from file
x_list, y_list = loadSequences("train.csv")

# x_list is now a list of arrays (n,6) of float64, where n is the timesteps
# and 6 is the number of features, sorted by increasing sequence lengths.
# y_list is a list of arrays (n,1) of Boolean.

x_train = # WHAT DO I WRITE HERE?
y_train = # AND HERE?

model = tf.keras.models.Sequential([
            tf.keras.layers.Masking(),
            tf.keras.layers.LSTM(32, return_sequences=True),
            tf.keras.layers.Dense(2, activation=tf.nn.softmax)
        ])
model.compile(optimizer='adam',
            loss='sparse_categorical_crossentropy',
            metrics=['accuracy'])
model.fit(x_train, y_train, batch_size=10, epochs=100)

你可以做这样的事情

使用生成器功能查看此链接查找fit_生成器方法

def data_generater(batch_size):
print("reading data")
training_file = 'data_location', 'r')

# assuming data is in json format so feels free to change accordingly

training_set = json.loads(training_file.read())
training_file.close()

batch_i = 0  # Counter inside the current batch vector
batch_x = []  # The current batch's x data
batch_y = []  # The current batch's y data

while True:

    for obj in training_set:
        batch_x.append(your input sequences one by one)
        if obj['val'] == True:
            batch_y.append([1])
        elif obj['val'] == False:
            batch_y.append([0])
        batch_i += 1

        if batch_i == batch_size:
            # Ready to yield the batch
            # pad input to max length in the batch
            batch_x = pad_txt_data(batch_x)
            yield batch_x, np.array(batch_y)
            batch_x = []
            batch_y = []
            batch_i = 0

def pad_txt_data(arr):
# expecting arr to be in the shape of (10, m, 6)
paded_arr = []
prefered_len = len(max(arr, key=len))

# Now pad all your sequences to preferred length in the batch(arr)

return np.array(paded_arr)
在模型中

model = keras.Sequential()
model.add(keras.layers.Masking(mask_value=0., input_shape=(None,6)))
model.add(keras.layers.LSTM(32))
model.add(keras.layers.Dense(1, activation="softmax"))
model.compile(optimizer="Adam", loss='categorical_crossentropy', metrics=['categorical_accuracy'])
model.fit_generator(data_generater(10), steps_per_epoch=5, epochs=10)
批次大小、每个历元的步数、历元可以不同。 大体上

steps\u per\u epoch=(序列数/批次大小)

注意:阅读您的描述时,您的任务似乎是二进制分类问题,而不像序列到序列的问题。从序列到序列的一个很好的例子是语言翻译。只要在你周围搜索一下,就会发现我的意思


如果你真的想看到训练时间上的差异,我建议使用GPU(如果有的话)和

如果它对某人有帮助,下面是我最终实现解决方案的方式:

import tensorflow as tf
import numpy as np

# Load data from file
x_list, y_list = loadSequences("train.csv")

# x_list is now a list of arrays (m,n) of float64, where m is the timesteps
# and n is the number of features.
# y_list is a list of arrays (m,1) of Boolean.
assert len(x_list) == len(y_list)
num_sequences = len(x_list)
num_features = len(x_list[0][0])
batch_size = 10
batches_per_epoch = 5
assert batch_size * batches_per_epoch == num_sequences

def train_generator():
    # Sort by length so the number of timesteps in each batch is minimized
    x_list.sort(key=len)
    y_list.sort(key=len)
    # Generate batches
    while True:
        for b in range(batches_per_epoch):
            longest_index = (b + 1) * batch_size - 1
            timesteps = len(x_list[longest_index])
            x_train = np.zeros((batch_size, timesteps, num_features))
            y_train = np.zeros((batch_size, timesteps, 1))
            for i in range(batch_size):
                li = b * batch_size + i
                x_train[i, 0:len(x_list[li]), :] = x_list[li]
                y_train[i, 0:len(y_list[li]), 0] = y_list[li]
            yield x_train, y_train

model = tf.keras.models.Sequential([
            tf.keras.layers.Masking(mask_value=0., input_shape=(None,num_features)),
            tf.keras.layers.LSTM(32, return_sequences=True),
            tf.keras.layers.Dense(2, activation=tf.nn.softmax)
        ])
model.compile(optimizer='adam',
            loss='sparse_categorical_crossentropy',
            metrics=['accuracy'])
model.fit_generator(train_generator(), steps_per_epoch=batches_per_epoch, epochs=100)

您可以尝试制作一些固定大小(例如500)的嵌入,并将其输入到您的应用程序中network@Novak我只知道嵌入是NLP中单词的一种特征向量。您能否澄清这对于将可变长度的序列馈送到model.fit()中有何用处?请注意,我的问题与NLP无关。嵌入主要用于NLP,但也用于其他内容。有些函数可以从任意序列创建嵌入。或者你可以用类似的东西。无论哪种方法,目标都是获得较短的序列,该序列保留了对象到其他对象的属性,并且它与原始对象的映射是1:1(每个对象都有不同的嵌入)。在Keras中,可以使用嵌入层来嵌入输入数据。因此,您将填充的数据馈送到嵌入层,并将嵌入层的维度设置为500-您将获得500个长嵌入。现在,您可以对其进行训练,对于predict,您可以使用嵌入层权重嵌入输入序列,以将数据提供给模型。我的问题是序列到序列的分类问题,这意味着我需要为每个时间步预测一个类。例如,(1000,6)个浮点序列(1000个时间步,6个特征)应该预测(1000,1)个布尔序列。此外,预测应该是实时的,因此它应该为每个新的6-特征向量预测一个新的布尔值。所以我认为在固定大小的嵌入中嵌入任意长度的序列在这里是行不通的。如果我的问题描述不清楚,我很抱歉!谢谢你,真管用!关于如何称呼这个问题,我知道你的意思,但我担心“二进制分类”会让读者认为应该对整个序列进行分类,而不是为每个时间步输出一个类。关于使用CuDNNLSTM,这一层似乎不支持掩蔽,对吗?不幸的是,是的。对不起,我的意思是CuDNNLSTM不支持掩蔽