构建二分类RNN/LSTM模型遇输入维度错误问题求助
Fixing "expected lstm_1_input to have 3 dimensions, but got array with shape (1415684, 6)" Error in LSTM Binary Classification
我的问题
我正在构建一个用于0/1二分类的LSTM模型,数据集包含患者编号、时间(毫秒/秒)、X/Y/Z归一化值、峰度、偏度、俯仰角(pitch)、翻滚角(roll)、偏航角(yaw)及标签,数据集示例如下:
1,15,-0.248010047716,0.00378335508419,-0.0152548459993,-86.3738760481,0.872322164158,-3.51314800063,0 1,31,-0.248010047716,0.00378335508419,-0.0152548459993,-86.3738760481,0.872322164158,-3.51314800063,0 1,46,-0.267422664673,0.0051143782875,-0.0191247001961,-85.7662354031,1.0928406847,-4.08015176908,0 1,62,-0.267422664673,0.0051143782875,-0.0191247001961,-85.7662354031,1.0928406847,-4.08015176908,0
我尝试了以下代码:
import numpy as np from keras.datasets import imdb from keras.models import Sequential from keras.layers import Dense from keras.layers import LSTM from keras.layers import Bidirectional from keras.preprocessing import sequence # fix random seed for reproducibility np.random.seed(7) train = np.loadtxt("featwithsignalsTRAIN.txt", delimiter=",") test = np.loadtxt("featwithsignalsTEST.txt", delimiter=",") x_train = train[:,[2,3,4,5,6,7]] x_test = test[:,[2,3,4,5,6,7]] y_train = train[:,8] y_test = test[:,8] # create the model model = Sequential() model.add(LSTM(20, dropout=0.2, input_dim=6)) model.add(Dense(4, activation = 'sigmoid')) model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) model.fit(x_train, y_train, epochs = 2)
但运行时出现错误:
Error when checking input: expected lstm_1_input to have 3 dimensions, but got array with shape (1415684, 6)
请求解决这个输入维度不匹配的问题。
解决方案
这个错误的核心原因是LSTM层要求输入必须是三维张量,形状为 (样本数, 时间步长, 特征数),但你当前的输入是二维的 (总记录数, 特征数)——你把所有患者的时序数据直接平铺成了单个集合,完全丢失了“每个患者是一个时间序列”的结构。下面一步步帮你修正:
1. 按患者ID分组,构建时序样本
你的数据是按患者编号分组的时序数据,每个患者的多条时间点记录构成一个完整的时间序列样本。我们需要先把训练集和测试集按患者ID拆分:
# 处理训练集:按患者ID分组 patient_ids_train = train[:, 0].astype(int) unique_patients_train = np.unique(patient_ids_train) x_train_seq = [] y_train_seq = [] for pid in unique_patients_train: # 提取当前患者的所有记录 patient_records = train[train[:, 0] == pid] # 取出特征列(X/Y/Z 到 yaw) seq_features = patient_records[:, [2,3,4,5,6,7]] # 每个患者的标签(假设同一患者的标签一致,取第一条记录的标签即可) seq_label = patient_records[0, 8] x_train_seq.append(seq_features) y_train_seq.append(seq_label) # 同样处理测试集 patient_ids_test = test[:, 0].astype(int) unique_patients_test = np.unique(patient_ids_test) x_test_seq = [] y_test_seq = [] for pid in unique_patients_test: patient_records = test[test[:, 0] == pid] seq_features = patient_records[:, [2,3,4,5,6,7]] seq_label = patient_records[0, 8] x_test_seq.append(seq_features) y_test_seq.append(seq_label)
2. 统一所有序列的长度
LSTM要求输入的所有序列长度必须一致,所以需要对过长的序列截断,过短的序列补零(padding)。我们可以用Keras提供的pad_sequences工具:
# 找到训练集中最长的序列长度作为统一标准 max_sequence_length = max([len(seq) for seq in x_train_seq]) # 对训练集和测试集的序列进行填充/截断 x_train_padded = sequence.pad_sequences(x_train_seq, maxlen=max_sequence_length, dtype='float32') x_test_padded = sequence.pad_sequences(x_test_seq, maxlen=max_sequence_length, dtype='float32') # 把标签转换成numpy数组格式 y_train = np.array(y_train_seq) y_test = np.array(y_test_seq)
3. 调整模型输入并重新训练
现在输入已经是三维的了,我们需要调整LSTM层的输入参数(用input_shape更直观,指定(时间步长, 特征数)),同时优化最后一层的设置(二分类任务输出维度应为1,用sigmoid激活):
# 重建模型 model = Sequential() # input_shape = (统一的时间步长, 特征数) model.add(LSTM(20, dropout=0.2, input_shape=(max_sequence_length, 6))) # 二分类任务:输出1个概率值,用sigmoid激活 model.add(Dense(1, activation='sigmoid')) model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) # 开始训练,加入验证集监控效果 model.fit(x_train_padded, y_train, epochs=10, batch_size=32, validation_data=(x_test_padded, y_test))
额外说明
- 如果你的数据中同一个患者的标签会随时间变化(比如不同时间点标签不同),那需要调整标签的处理方式——每个时间步对应一个标签,模型结构也要改成返回序列的LSTM(
return_sequences=True),但从你的数据集示例看,同一患者标签都是0,所以用单标签是合理的。 - 你之前导入了
Bidirectional但没用到,如果需要双向LSTM,可以把LSTM层换成Bidirectional(LSTM(20, dropout=0.2)),效果可能更好。
内容的提问来源于stack exchange,提问作者Hadeer El-Zayat
相关产品推荐
相关产品推荐

