如何修复输入维度不匹配错误:预期2维但获(32,168,5)数组
我一眼就看出问题出在输入层定义和数据维度的不匹配上,还有你对序列数据的处理逻辑有点混乱,咱们一步步来修正:
错误核心原因
你定义的input_1 = Input(shape=(5, ))期望的是2D输入(形状为(batch_size, 5)),但你的实际输入x_batch_1是3D序列数据(形状为(32,168,5))——这里32是批量大小,168是序列长度,5是每个时间步的特征数。LSTM分支的input_2也存在同样的定义错误,而且你用tf.expand_dims的操作完全搞反了方向,反而让维度更混乱。
具体修正步骤
1. 修正输入层的形状定义
你的输入是带序列长度的3D数据,所以输入层的shape应该定义为(序列长度, 特征数),如果想兼容可变序列长度,可以用(None, 特征数):
# first input model: 对应输入形状(batch_size, 168, 5) input_1 = Input(shape=(168, 5)) # 换成(None,5)可支持任意长度的序列 # second input model: 对应输入形状(batch_size, 168,7) input_2 = Input(shape=(168,7)) # 换成(None,7)可支持任意长度的序列
2. 调整DNN分支的处理逻辑
因为input_1是序列数据,你需要让全连接层处理每个时间步的特征,这里要用TimeDistributed包裹Dense,这样每个时间步的5维特征都会经过64维的全连接,输出保持序列维度:
# DNN分支:处理序列数据,每个时间步独立过Dense dense_1 = TimeDistributed(Dense(units=64))(input_1) # 此时dense_1的形状是(batch_size, 168, 64)
3. 简化LSTM分支的输入处理
你的LSTM层已经设置了return_sequences=True,输出形状是(batch_size,168,64),和DNN分支的输出维度匹配。这里可以去掉冗余的input_shape参数(输入层已经定义了形状),也不需要tf.expand_dims——因为你的输入已经是LSTM需要的3D格式(batch, seq_len, features):
# LSTM分支:直接处理3D输入,return_sequences=True保留序列维度 lstm_1 = LSTM(units=64, return_sequences=True)(input_2) # 此时lstm_1的形状是(batch_size,168,64)
4. 修正拼接轴并调整输出层
现在两个分支的输出都是(batch_size,168,64),我们需要在**特征轴(axis=-1)**拼接,得到(batch_size,168,128),然后用TimeDistributed(Dense)输出每个时间步的预测结果(因为你的y_batch是(32,168,1),每个时间步都有一个标签):
# 在特征轴拼接两个分支的输出 merge = concatenate([dense_1, lstm_1], axis=-1) # 输出层:每个时间步输出1个结果 output = TimeDistributed(Dense(num_y_signals, activation='sigmoid'))(merge) model = Model(inputs=[input_1, input_2], outputs=output)
5. 调整验证数据的维度
你的验证数据不需要额外expand_dims(axis=0),如果x_test1_scaled的原始形状是(样本数, 168,5),直接传入即可。如果你的验证集是一个长序列(5808,5),那你需要把它分割成和训练数据一样的序列长度(168),或者让模型支持可变序列长度(输入层用(None,5)),否则模型会因为序列长度不匹配报错。
修正后的完整模型代码
from tensorflow.keras.layers import Input, Dense, LSTM, concatenate, TimeDistributed from tensorflow.keras.models import Model # first input model input_1 = Input(shape=(168, 5)) # 或者(None,5)支持可变序列长度 dense_1 = TimeDistributed(Dense(units=64))(input_1) # second input model input_2 = Input(shape=(168, 7)) # 或者(None,7) lstm_1 = LSTM(units=64, return_sequences=True)(input_2) # merge input models merge = concatenate([dense_1, lstm_1], axis=-1) output = TimeDistributed(Dense(num_y_signals, activation='sigmoid'))(merge) model = Model(inputs=[input_1, input_2], outputs=output) model.summary()
补充说明
你之前考虑的flatten思路不适用这里:如果直接flatten序列维度,会把(32,168,5)变成(32,840),这样和LSTM输出的(32,168,64)无法拼接——因为维度数量和长度都不匹配。只有保持序列维度一致,才能在特征轴拼接,这也是处理序列到序列任务的正确方式。
内容的提问来源于stack exchange,提问作者Joichiro Nishi

