Keras构建气象预测LSTM模型时输入维度不兼容问题求助
气象预测多输入LSTM模型维度错误修复
问题概述
目标是构建神经网络,输入过去30天数据预测一周后气温变化百分比的正负分类,模型包含两个输入:
- 数值输入:形状为
(30,3),对应每日的[温度, 湿度, 气压]数据 - 文本输入:30天嵌套列表,对应每日的气象观测文本序列
用户编写的Keras模型代码如下:
embedding_dim = 128 vocab_size = len(words_to_int) # number of unique words num_input = keras.Input(shape= (30,3), name="nums") nmlstm = layers.LSTM(64)(num_input) #num input goes to num lstm nmdense = layers.Dense(64)(nmlstm) #num lstm goes to num dense text_input = keras.Input(shape= (30, max_sequence_length), name="text") #basically length of the longest string observation sequence text_vec = layers.Embedding(vocab_size, embedding_dim, mask_zero=True)(text_input) #text input goes to text embedding txlstm = layers.LSTM(64)(text_vec) #text embedding goes to text lstm united = layers.concatenate([nmdense, txlstm]) #concatenating text lstm and num dense almostlast = layers.Dense(64)(united) #computing united input last = layers.Dense(2, name='prediction')(almostlast) #output dense layer model = keras.Model(inputs=[num_input, text_input], outputs=last) model.compile(optimizer='adam', loss=keras.losses.CategoricalCrossentropy) model.fit({"nums": X1_train, "text": X2_train}, {"prediction": y_train}, epochs=8, batch_size=10)
运行时出现维度不兼容错误:
ValueError: Input 0 of layer "lstm_1" is incompatible with the layer: expected ndim=3, found ndim=4. Full shape received: (None, 30, 2, 128)
错误原因
文本输入经过Embedding层后,输出张量为4维:(batch_size, 30, max_sequence_length, embedding_dim),而LSTM层仅接受3维输入((batch_size, timesteps, features))。这里的30是天数(外层时间步),每个天数下包含max_sequence_length个词的序列,需要先对单日文本序列提取特征,将4维张量压缩为3维后,再送入处理30天序列的LSTM。
修复方案
在Embedding层之后添加TimeDistributed层,对每天的文本序列单独提取特征,将4维张量转换为3维,再送入后续LSTM。以下是两种可行的修改方式:
方式1:用LSTM提取单日文本特征
embedding_dim = 128 vocab_size = len(words_to_int) # 唯一词数量 # 数值输入分支 num_input = keras.Input(shape=(30,3), name="nums") nmlstm = layers.LSTM(64)(num_input) nmdense = layers.Dense(64)(nmlstm) # 文本输入分支 text_input = keras.Input(shape=(30, max_sequence_length), name="text") text_vec = layers.Embedding(vocab_size, embedding_dim, mask_zero=True)(text_input) # 对每天的文本序列单独应用LSTM,提取单日特征 daily_text_feature = layers.TimeDistributed(layers.LSTM(32))(text_vec) # 此时daily_text_feature形状为(None, 30, 32),符合LSTM输入要求 txlstm = layers.LSTM(64)(daily_text_feature) # 拼接与输出层 united = layers.concatenate([nmdense, txlstm]) almostlast = layers.Dense(64)(united) last = layers.Dense(2, name='prediction')(almostlast) model = keras.Model(inputs=[num_input, text_input], outputs=last) model.compile(optimizer='adam', loss=keras.losses.CategoricalCrossentropy) model.fit({"nums": X1_train, "text": X2_train}, {"prediction": y_train}, epochs=8, batch_size=10)
方式2:用池化提取单日文本特征(计算量更小)
若觉得LSTM计算量过大,可替换为GlobalAveragePooling1D做平均池化:
embedding_dim = 128 vocab_size = len(words_to_int) # 唯一词数量 # 数值输入分支 num_input = keras.Input(shape=(30,3), name="nums") nmlstm = layers.LSTM(64)(num_input) nmdense = layers.Dense(64)(nmlstm) # 文本输入分支 text_input = keras.Input(shape=(30, max_sequence_length), name="text") text_vec = layers.Embedding(vocab_size, embedding_dim, mask_zero=True)(text_input) # 对每天的文本序列做平均池化,提取单日特征 daily_text_feature = layers.TimeDistributed(layers.GlobalAveragePooling1D())(text_vec) # 此时daily_text_feature形状为(None, 30, 128),符合LSTM输入要求 txlstm = layers.LSTM(64)(daily_text_feature) # 拼接与输出层 united = layers.concatenate([nmdense, txlstm]) almostlast = layers.Dense(64)(united) last = layers.Dense(2, name='prediction')(almostlast) model = keras.Model(inputs=[num_input, text_input], outputs=last) model.compile(optimizer='adam', loss=keras.losses.CategoricalCrossentropy) model.fit({"nums": X1_train, "text": X2_train}, {"prediction": y_train}, epochs=8, batch_size=10)
内容的提问来源于stack exchange,提问作者flexorcist
相关产品推荐
相关产品推荐

