Python RNN 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
你的训练日志显示完全没有进展:
Epoch 1/20 - 63s - loss: 15.0343 - acc: 0.0570
Epoch 2/20 - 60s - loss: 15.0343 - acc: 0.0570
Epoch 3/20 - 60s - loss: 15.0343 - acc: 0.0570
Epoch 4/20 - 60s - loss: 15.0343 - acc: 0.0570
1. 最关键的问题:时间序列维度构造错误
LSTM的核心是捕捉时间序列的依赖关系,但你现在把每个单独的时间步作为一个样本(reshape((-1,1,6))),相当于每个样本只有1个时间点,LSTM完全没法学习时间上的规律,这就失去了用LSTM的意义。
你需要按患者分组,把连续的时间步组合成序列样本(比如每个序列包含20个连续时间点),代码示例:
def create_sequences(data, time_steps=20): X, y = [], [] # 按患者ID分组,不同患者的序列不能混在一起 patient_ids = np.unique(data[:, 0]) for pid in patient_ids: patient_data = data[data[:, 0] == pid] # 提取特征和标签 features = patient_data[:, [2,3,4,5,6,7]] labels = patient_data[:, 8] # 为当前患者生成序列样本 for i in range(len(features) - time_steps): X.append(features[i:i+time_steps]) # 这里用序列最后一个时间步的标签作为样本标签,可根据任务调整 y.append(labels[i+time_steps]) return np.array(X), np.array(y) # 重新构造训练和测试序列 x_train, y_train = create_sequences(train, time_steps=20) x_test, y_test = create_sequences(test, time_steps=20) # 此时x_train的形状应为 (样本数, 时间步长, 特征数),比如 (N,20,6) print(x_train.shape)
2. 输出层激活函数与任务不匹配
你的任务是二分类(标签0/1),但你用了softmax激活函数(这是多分类任务用的),二分类应该用sigmoid激活,同时要确保标签是浮点型:
# 转换标签为浮点型 y_train = y_train.astype(float) y_test = y_test.astype(float) # 重构模型 model = Sequential() # 输入形状改为 (时间步长, 特征数) model.add(LSTM(64, activation='relu', input_shape=(x_train.shape[1], x_train.shape[2]))) model.add(Dense(1, activation='sigmoid')) # 替换为sigmoid model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
3. 特征尺度不一致导致训练不稳定
你的特征尺度差异极大:X/Y/Z是接近0的小数,而峰度值在-86左右,姿态角也有不同尺度,这会导致模型梯度不稳定,难以收敛。需要用标准化处理特征:
from sklearn.preprocessing import StandardScaler # 用训练+测试的所有特征拟合标准化器,避免数据泄露 all_features = np.vstack([train[:,[2,3,4,5,6,7]], test[:,[2,3,4,5,6,7]]]) scaler = StandardScaler() scaler.fit(all_features) # 对训练和测试特征做标准化 train_scaled = train.copy() train_scaled[:,[2,3,4,5,6,7]] = scaler.transform(train[:,[2,3,4,5,6,7]]) test_scaled = test.copy() test_scaled[:,[2,3,4,5,6,7]] = scaler.transform(test[:,[2,3,4,5,6,7]]) # 用标准化后的数据重新构造序列 x_train, y_train = create_sequences(train_scaled, time_steps=20) x_test, y_test = create_sequences(test_scaled, time_steps=20)
4. 检查数据集的类别平衡
从你的准确率0.057来看,大概率存在严重的类别不平衡(比如94.3%的样本是标签1),模型直接输出多数类就能得到这个准确率,根本不需要学习。先统计标签分布:
print("训练集标签分布:") print(np.bincount(y_train.astype(int))) print("测试集标签分布:") print(np.bincount(y_test.astype(int)))
如果确实不平衡,可以尝试:
- 过采样少数类/欠采样多数类
- 在
model.fit中加入class_weight参数,给少数类更高的权重,比如class_weight={0:18, 1:1}(假设0类占比5%)
5. 可选:调整模型结构提升性能
如果前面的问题都解决了,还可以尝试优化模型结构,比如增加LSTM层或Dropout防止过拟合:
model = Sequential() model.add(LSTM(64, activation='relu', return_sequences=True, input_shape=(x_train.shape[1], x_train.shape[2]))) model.add(Dropout(0.2)) model.add(LSTM(32, activation='relu')) model.add(Dense(1, activation='sigmoid')) model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
把这些步骤逐一修正后,再训练模型,应该能看到损失下降和准确率提升的过程。
内容的提问来源于stack exchange,提问作者hadeerdodo

