如何向Keras模型输入滑动窗口式多列序列数据?
滑动窗口时序输入的实现方案
问题背景
手里有个形状为(128, 47088)的NumPy数组,需要用滑动窗口的方式喂给模型:比如先取第0-4列(总共640条数据)作为一个输入样本,下一次取第1-5列,以此类推。之前试了GRU、LSTM和Flatten层都没成功,想知道是要提前预处理数据,还是能在模型内部完成这种数据重塑?
原训练代码参考:
# np_input 是形状为(128, 47088)的NumPy数组 model = keras.Sequential([ keras.Input(shape=(128,)), keras.layers.Dense(1024, activation='relu', kernel_regularizer='l2'), keras.layers.Dense(1024, activation='relu', kernel_regularizer='l2'), keras.layers.Dense(1024, activation='relu', kernel_regularizer='l2'), keras.layers.Dense(np_output.shape[0], activation='sigmoid'), ]) model.compile(optimizer=keras.optimizers.Adam(learning_rate=0.0001), loss='mean_squared_error', metrics=['acc', 'mse'], run_eagerly=True) model.summary() # 按轴1划分训练测试集,所以先转置输入数据 X_train, X_test, y_train, y_test = train_test_split(np_input.T, np_output.T, test_size=0.2, shuffle=False, random_state=None) hist = model.fit(X_train, y_train, epochs=100, verbose=2, batch_size=2048, use_multiprocessing=True, validation_data=(X_test, y_test), callbacks=callbacks )
两种可行方案
方案一:提前预处理数据(更推荐)
滑动窗口逻辑在预处理阶段实现更直观,调试起来也简单,不会和模型层的逻辑混在一起。具体步骤如下:
- 确定窗口参数:比如你需要的窗口大小是
5(每次取5列),滑动步长是1(每次移动1列)。 - 将原始数组转换成
(样本数, 窗口大小, 特征数)的格式——这是LSTM/GRU要求的输入形状(batch_size, timesteps, features)。
代码示例:
import numpy as np from sklearn.model_selection import train_test_split import keras # 模拟原始输入和标签 np_input = np.random.rand(128, 47088) # (特征数, 时序步数) np_output = np.random.rand(1, 47088) # 假设标签和每一步输入对应 window_size = 5 step = 1 # 计算能生成的样本总数 num_samples = np_input.shape[1] - window_size + 1 # 生成滑动窗口样本 X_windowed = np.zeros((num_samples, window_size, 128)) for i in range(num_samples): # 截取i到i+window_size的列,转置后变成(window_size, 128)的形状 X_windowed[i] = np_input[:, i:i+window_size].T # 处理标签:通常标签对应窗口最后一个时间步的输出,所以取从第window_size-1列开始的所有标签 y_windowed = np_output[:, window_size-1:].T # 划分训练测试集(时序数据别打乱) X_train, X_test, y_train, y_test = train_test_split(X_windowed, y_windowed, test_size=0.2, shuffle=False) # 构建带GRU的模型 model = keras.Sequential([ keras.Input(shape=(window_size, 128)), # 输入形状(窗口大小, 特征数) keras.layers.GRU(256, kernel_regularizer='l2'), keras.layers.Dense(1024, activation='relu', kernel_regularizer='l2'), keras.layers.Dense(np_output.shape[0], activation='sigmoid'), ]) model.compile(optimizer=keras.optimizers.Adam(learning_rate=0.0001), loss='mean_squared_error', metrics=['acc', 'mse']) model.summary() # 启动训练 hist = model.fit(X_train, y_train, epochs=100, verbose=2, batch_size=2048, validation_data=(X_test, y_test))
方案二:在模型内部实现滑动窗口(用Lambda层)
如果一定要在模型里处理,可以用TensorFlow的tf.sliding_window_view结合Lambda层实现,但这种方式会增加模型复杂度,调试难度更高,只适合特定场景。
代码示例:
import tensorflow as tf import keras window_size = 5 model = keras.Sequential([ # 输入完整的时序序列,形状(特征数, 时序长度) keras.Input(shape=(128, None)), # 转置成(批量, 时序长度, 特征数),适配滑动窗口函数 keras.layers.Lambda(lambda x: tf.transpose(x, perm=[0, 2, 1])), # 生成滑动窗口,输出形状(批量, 样本数, 窗口大小, 特征数) keras.layers.Lambda(lambda x: tf.sliding_window_view(x, window_size, axis=1)), # 把窗口内的特征展平,或者直接喂给GRU(根据需求调整) keras.layers.Reshape((-1, window_size * 128)), keras.layers.GRU(256, kernel_regularizer='l2'), keras.layers.Dense(1024, activation='relu', kernel_regularizer='l2'), keras.layers.Dense(np_output.shape[0], activation='sigmoid'), ])
注意:这种方式需要喂入完整的时序序列,而不是单个样本,所以数据加载逻辑要对应调整,灵活性不如预处理方案。
之前失败的原因
你之前的模型输入形状是(128,),这只是单个样本的特征数,没有包含时序维度。而GRU/LSTM要求输入必须带有时间步维度(即形状为(timesteps, features)),所以直接用原数据格式喂入肯定会失败。不管用哪种方案,核心都是要把数据转换成包含窗口时间步的形状。
内容的提问来源于stack exchange,提问作者Leandro
相关产品推荐
相关产品推荐

