基于三轴加速度计数据的CNN人体活动分类模型输入维度错误问题
问题描述
基于智能手机三轴加速度计(x、y、z轴)数据对6种人体活动分类,已用Random Forest、KNN、MLP、LDA实现80-90%的准确率,现在尝试CNN但遇到维度不兼容问题。
数据集情况:共2086923行×4列,包含3列加速度数据(x-accel、y-accel、z-accel)和1列活动标签。
尝试的代码如下:
train,test = train_test_split(df,test_size=0.3,random_state=42) X_train = train[train.columns[2:4]] y_train = train['Activity'] X_test = test[test.columns[2:4]] y_test = test['Activity'] model=Sequential() model.add(Conv2D(32,(3,3),activation='relu',input_shape=(3,))) model.add(MaxPool2D(2,2)) model.add(Flatten()) model.add(Dense(100,activation='relu')) model.add(Dense(10,activation='softmax')) model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['accuracy']) model.fit(X_train,y_train,epochs=10) model.evaluate(X_test,y_test)
运行后报错:
ValueError: Input 0 of layer "conv2d_1" is incompatible with the layer: expected min_ndim=4, found ndim=2. Full shape received: (None, 3)
解决方案
核心问题分析
- Conv2D不适用于时序加速度数据:Conv2D是为图像设计的二维卷积层,要求输入为4维张量(样本数×图像高度×图像宽度×通道数),但你的输入是2维(样本数×3个轴的加速度值),维度不匹配导致报错。
- 未做时序窗口分割:加速度数据是时序数据,单个时间点的3个值无法体现运动的时序特征,CNN需要处理连续的时间窗口样本才能捕捉动作模式。
具体修正步骤
1. 生成时序窗口样本
先定义函数,将原始时序数据分割成连续时间窗口(窗口大小可根据数据采样率调整,示例用30):
import numpy as np def create_sequence_data(X, y, window_size=30): sequences = [] labels = [] for i in range(len(X) - window_size): # 取连续window_size个时间步的加速度数据 seq = X.iloc[i:i+window_size].values # 取窗口最后一个时间步的标签作为样本标签 label = y.iloc[i+window_size] sequences.append(seq) labels.append(label) return np.array(sequences), np.array(labels)
2. 预处理训练/测试数据
修正列索引确保取到完整的x、y、z三列数据,同时生成时序样本并编码标签:
# 修正列索引:确保取到x、y、z三列加速度数据(根据实际列位置调整) X_train = train[['x-accel', 'y-accel', 'z-accel']] y_train = train['Activity'] X_test = test[['x-accel', 'y-accel', 'z-accel']] y_test = test['Activity'] # 生成时序窗口样本 window_size = 30 X_train_seq, y_train_seq = create_sequence_data(X_train, y_train, window_size) X_test_seq, y_test_seq = create_sequence_data(X_test, y_test, window_size) # 标签整数编码(适配sparse_categorical_crossentropy损失函数) from sklearn.preprocessing import LabelEncoder le = LabelEncoder() y_train_seq = le.fit_transform(y_train_seq) y_test_seq = le.transform(y_test_seq)
3. 用Conv1D构建适配的模型
Conv1D专为一维时序数据设计,输入为3维张量(样本数×时间步长度×特征数),完全匹配时序窗口样本:
from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Conv1D, MaxPooling1D, Flatten, Dense model = Sequential() # 输入形状为(窗口长度, 特征数),对应(30,3) model.add(Conv1D(filters=32, kernel_size=3, activation='relu', input_shape=(window_size, 3))) model.add(MaxPooling1D(pool_size=2)) model.add(Flatten()) model.add(Dense(100, activation='relu')) # 输出层神经元数等于活动类别数(6种) model.add(Dense(6, activation='softmax')) model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy']) # 训练模型 model.fit(X_train_seq, y_train_seq, epochs=10, batch_size=32) # 评估模型 test_loss, test_acc = model.evaluate(X_test_seq, y_test_seq) print(f"测试准确率: {test_acc:.4f}")
额外优化建议
- 调整窗口大小:根据数据采样率调整,比如50Hz采样率下,30个窗口对应0.6秒动作片段,可尝试20-50区间的数值。
- 添加Dropout层:在Dense层之间加入
Dropout(0.2)抑制过拟合。 - 调整卷积参数:尝试增加filters数量(64、128)或调整kernel_size(5、7)提升性能。
内容的提问来源于stack exchange,提问作者Matheus Torres
相关产品推荐
相关产品推荐

