EfficientNetB0与LSTM融合模型适配失败:输入形状不兼容求助
问题解决:EfficientNetB0与LSTM融合的输入形状不兼容问题
核心错误分析
- 模型输入定义错误:最终模型
model1错误地将EfficientNet的输出张量Res_model作为输入,而非EfficientNet的输入层effnet.input,导致输入形状不匹配。 - LSTM输入与数据格式不匹配:LSTM要求输入形状为
(None, 序列长度, 特征维度),当前定义的sequence_input=(150,150)与X_train=(150,150,3)的维度不兼容。 - 训练数据传入格式错误:多输入模型训练时,需传入对应每个输入层的数据,而非单一的
(X_train,y_train)。 - 激活函数与损失函数不匹配:输出层用
sigmoid但损失用categorical_crossentropy,二分类场景下需调整对应关系。
修正后的完整代码
import tensorflow as tf from tensorflow.keras.layers import Input, LSTM, Concatenate, Dense, GlobalAveragePooling2D, Dropout from tensorflow.keras.applications import EfficientNetB0 from tensorflow.keras.models import Model # ---------------------- 构建EfficientNet分支 ---------------------- input_shape=(150,150,3) # 补全缺失的右括号 effnet = EfficientNetB0(weights=None, include_top=False, input_shape=input_shape) Res_model = effnet.output print(Res_model.shape) # (None, 5, 5, 1280) # 特征提取与全连接层 x = GlobalAveragePooling2D()(Res_model) print(x.shape) # (None, 1280) x = Dense(512, activation="relu")(x) print(x.shape) # (None, 512) # 移除training=True,训练时模型自动处理dropout状态 x = Dropout(rate=0.5)(x) print(x.shape) # (None, 512) effnet_output = Dense(32, activation='relu')(x) # 用relu作为中间输出,避免与最终输出激活冲突 print(effnet_output.shape) # (None, 32) # 封装EfficientNet分支模型 effnet_model = Model(inputs=effnet.input, outputs=effnet_output) print(effnet_model.input_shape) # (None, 150, 150, 3) print(effnet_model.output_shape) # (None, 32) # ---------------------- 构建LSTM分支 ---------------------- # 根据X_train形状调整LSTM输入:将图像每行作为序列步,每行的特征为150*3=450个像素值 # LSTM输入形状为(序列长度, 特征维度) sequence_input = Input(shape=(150, 150*3)) print(sequence_input.shape) # (None, 150, 450) lstm_output = LSTM(32)(sequence_input) print(lstm_output.shape) # (None, 32) # ---------------------- 融合两个分支 ---------------------- concatenated = Concatenate()([effnet_output, lstm_output]) # 二分类场景下,若标签是one-hot编码用softmax+categorical_crossentropy;若为单标签用sigmoid+binary_crossentropy output = Dense(2, activation='softmax')(concatenated) # 最终模型的输入是两个输入层张量:effnet.input 和 sequence_input model1 = Model(inputs=[effnet.input, sequence_input], outputs=output) # 根据输出激活选择对应损失函数 model1.compile(loss='categorical_crossentropy', optimizer='Adam', metrics=['accuracy']) # ---------------------- 数据预处理与训练 ---------------------- # 假设X_train形状为(N,150,150,3),y_train为(N,2)的one-hot编码 # 预处理LSTM输入:将图像reshape为(N,150, 150*3) X_train_lstm = X_train.reshape(-1, 150, 150*3) # 传入两个输入数据,对应模型的两个输入层 history = model1.fit( [X_train, X_train_lstm], y_train, batch_size=32, epochs=2, validation_split=0.1, verbose=1 )
关键修改说明
- 输入层修正:将
model1的输入改为[effnet.input, sequence_input],确保模型接收原始图像输入和适配LSTM的序列输入。 - LSTM输入适配:通过
reshape将原始图像转换为LSTM要求的(序列长度, 特征维度)格式,这里选择图像的高度(150)作为序列长度,每行的所有像素(150×3)作为特征维度,你可根据任务需求调整序列维度的定义(比如按通道作为序列)。 - 训练数据传入:多输入模型训练时,需传入包含所有输入数据的列表,对应模型的每个输入层。
- 激活与损失匹配:二分类场景下,若标签是one-hot编码,使用
softmax激活+categorical_crossentropy损失;若为单标签(0/1),则改为sigmoid激活+binary_crossentropy损失。
内容的提问来源于stack exchange,提问作者Monika Kohli
相关产品推荐
相关产品推荐

