Keras LSTM分类器目标形状匹配失败问题求助
问题分析与解决
核心错误原因
- 目标变量结构不匹配:输入
X是按walk分组后的序列数据,形状为(3, 5, 2)(3个walk序列,每个最长5个时间步,2个特征),但错误地将y_onehot强行reshape为(3,12),和模型输出形状(当前模型默认输出单步结果(1,3))完全不兼容。 - 代码冗余与变量冲突:代码中重复定义
y变量,中间备选编码逻辑存在语法错误(如未定义的y_wals、max_length),且覆盖了后续分组的y,导致数据混乱。 - 模型结构不符合需求:需要预测每个时间步的
value,但当前LSTM层默认return_sequences=False,只会输出整个序列的最后一个时间步结果,无法满足逐时间步预测的需求。
修正后的完整代码
import pandas as pd import numpy as np from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, LSTM, Masking, TimeDistributed from tensorflow.keras.utils import np_utils, pad_sequences from sklearn.preprocessing import LabelEncoder # 读取数据 df = pd.DataFrame({ 'value': ['A', 'A', 'A', 'C', 'C', 'C', 'C', 'C', 'B', 'B', 'B', 'B'], 'X1': [1.2, 1.5, 0.91, 3.5, 0.2, 2.7, 2.2, 0.91, 3.5, 0.2, 0.91, 2.4], 'X2': [2.4, 0.82, 2.1, 0.4, 4.4, 3.5, 0.2, 2.7, 2.2, 4.2, 3.4, 0.9], 'walk': ['d', 'd', 'd', 'sa', 'sa', 'sa', 'sa', 'sa', 'p', 'p', 'p', 'p'], 'time': [1, 2, 3, 1, 2, 3, 4, 5, 1, 2, 3, 4]}) # 设置参数 TIME_STEPS = max(df.groupby(['walk'])['time'].count()) NUM_FEATURES = 2 # X特征数量 CLASSES = df['value'].unique() NUM_CLASSES = len(CLASSES) # 按walk分组生成输入输出序列 X = [] y_raw = [] for walk, group in df.groupby('walk'): x_walk = group[['X1', 'X2']].values y_walk = group['value'].values X.append(x_walk) y_raw.append(y_walk) # 对输入序列补零到最大长度 X = pad_sequences(X, maxlen=TIME_STEPS, dtype='float32', padding='post', value=0.0) # 编码目标变量并补全到对应序列长度 encoder = LabelEncoder() encoder.fit(df['value']) # 对每个walk的y序列编码,然后补全到TIME_STEPS长度,再转为one-hot y_encoded = [] for seq in y_raw: encoded_seq = encoder.transform(seq) # 补全序列,用-1标记补位(后续会忽略) padded_seq = pad_sequences([encoded_seq], maxlen=TIME_STEPS, padding='post', value=-1)[0] y_encoded.append(padded_seq) # 转为one-hot编码,补位的-1转为全0(不参与损失计算) y_onehot = [] for seq in y_encoded: onehot_seq = [] for val in seq: if val == -1: onehot_seq.append(np.zeros(NUM_CLASSES)) else: onehot_seq.append(np_utils.to_categorical(val, NUM_CLASSES)) y_onehot.append(onehot_seq) y_onehot = np.array(y_onehot, dtype='float32') # 定义模型:需要逐时间步输出,所以LSTM设置return_sequences=True,用TimeDistributed包装Dense model = Sequential() model.add(Masking(mask_value=0.0, input_shape=(TIME_STEPS, NUM_FEATURES))) model.add(LSTM(units=50, return_sequences=True)) model.add(TimeDistributed(Dense(NUM_CLASSES, activation='softmax'))) model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) print(model.summary()) # 拟合模型,此时X形状(3,5,2),y_onehot形状(3,5,3),完全匹配 model.fit(X, y_onehot, epochs=100, batch_size=1, verbose=2)
关键修正点说明
- 统一数据结构:输入
X和目标y_onehot都按walk序列组织,形状分别为(样本数, 时间步数, 特征数)和(样本数, 时间步数, 类别数),保证维度匹配。 - 补位处理:对目标序列的补位用
-1标记,转为one-hot时设为全0,结合Masking层忽略补位的损失计算。 - 模型调整:将LSTM的
return_sequences设为True,并使用TimeDistributed包装Dense层,实现每个时间步输出对应类别的预测结果。
内容的提问来源于stack exchange,提问作者Noque
相关产品推荐
相关产品推荐

