使用VGG16训练模型出现输入层形状不兼容ValueError报错如何解决
报错原因
你遇到的形状不匹配报错核心是两套逻辑冲突:
- 预处理阶段你已经用VGG16的卷积基底对原始图片做了特征提取,得到的每个样本特征形状为
(1, 8, 3, 512),最终组装的features整体形状为(样本数, 1, 8, 3, 512) - 你搭建的模型输入要求为原始图片形状
(None, 256, 96, 3),且模型内部重复添加了一次VGG16卷积层,和你提前提取特征的逻辑完全重复。
解决方案(二选一即可)
方案一:保留提前提取特征的逻辑(推荐,训练速度更快)
你已经提前做好了VGG卷积层的特征提取,不需要在模型里重复加卷积部分,修改对应代码即可:
1. 调整预处理代码,去掉多余维度
在提取特征时去掉单样本的批次维度,避免后续多余维度干扰:
for input_image in tqdm(os.listdir(dir)): try: img = image.load_img(os.path.join(dir, input_image), target_size=(img_width, img_height)) img_tensor = image.img_to_array(img) img_tensor /= 255. # 取predict结果的第一个元素,去掉批次维度,得到(8,3,512)的特征 pic = conv_base.predict(img_tensor.reshape(1, img_width, img_height, 3), verbose=0)[0] data.append([pic, index]) except Exception as e: pass
组装features和labels时可以再加一步维度压缩,确保没有多余维度:
import numpy as np features = np.array([x[0] for x in data]).squeeze() labels = np.array([x[1] for x in data])
2. 调整模型结构,匹配特征输入
删除模型中重复的VGG卷积部分,输入改为提取到的特征形状,同时修正输出类别数(你提到数据集共4类,原代码输出45类是错误的):
from tensorflow.keras.layers import Input, Flatten, Dense, Dropout from tensorflow.keras.models import Model # 输入改为VGG卷积输出的特征形状 input = Input(shape=(8, 3, 512)) # 直接接全连接层即可,不需要重复走VGG卷积 x = Flatten(name='flatten')(input) x = Dense(512, activation='relu', name='Dense1')(x) x = Dropout(0.2, name = 'Dropout')(x) # 输出类别数改为4,匹配你的数据集分类数 x = Dense(4, activation='softmax', name='predictions')(x) my_model = Model(inputs=input, outputs=x) my_model.summary() my_model.compile( loss = 'sparse_categorical_crossentropy', optimizer = 'adam', metrics = ['accuracy'] ) # 此时features形状为(样本数,8,3,512),和模型输入匹配,可正常训练 my_model.fit( features, labels, batch_size = 5, epochs = 15, validation_split = 0.1, callbacks=[TensorBoard] )
方案二:不提前提取特征,直接喂原始图片训练
如果你需要端到端训练整个模型(包括VGG卷积层),就修改预处理逻辑,不要提前做特征提取:
for input_image in tqdm(os.listdir(dir)): try: img = image.load_img(os.path.join(dir, input_image), target_size=(img_width, img_height)) img_tensor = image.img_to_array(img) img_tensor /= 255. # 直接存原始图片张量,不做VGG特征提取 data.append([img_tensor, index]) except Exception as e: pass
组装后的features形状为(样本数,256,96,3),可以直接匹配你原本的模型输入,只需要把最后一层输出的45类改为4类即可正常训练。如果要加快训练速度,可以冻结VGG16的卷积层参数:
model_vgg16_conv = VGG16(weights='imagenet', include_top=False, input_shape=(img_width, img_height, 3)) # 冻结VGG卷积层参数,只训练后面的全连接层 model_vgg16_conv.trainable = False
内容的提问来源于stack exchange,提问作者Fazlan Ahamed
相关产品推荐
相关产品推荐

