TensorFlow简单分类器输入形状错误求助:维度不匹配
首先,咱们来拆解你遇到的错误:Error when checking input: expected input_1 to have 4 dimensions, but got array with shape (None, None, 224, 224, 3),核心问题出在数据预处理阶段的图像解码+尺寸不匹配,还有模型本身的几个小错误,我一步步给你讲怎么修:
1. 修复图像解码的维度问题
你的_parse_function里同时调用了tf.image.decode_jpeg和tf.image.decode_gif,这会导致冲突:
- JPEG解码后是3维张量:
(height, width, 3) - GIF解码后是4维张量:
(num_frames, height, width, 3)
当你把GIF解码的结果传入resize后,输出还是带帧数维度的4维张量,再经过batch处理后,就变成了5维(batch_size, num_frames, 299, 299, 3),这完全不符合VGG16期望的4维输入(batch_size, height, width, 3)。
修改方案:
根据你的数据集(辛普森角色图片),应该都是JPEG格式,所以删掉tf.image.decode_gif那行代码,只保留JPEG解码:
def _parse_function(filename, label): image_string = tf.read_file(filename) # 只保留JPEG解码,删掉GIF解码的行 image_decoded = tf.image.decode_jpeg(image_string, channels=3) # 明确指定3通道 image_resized = tf.image.resize_images(image_decoded, [img_rows, img_cols]) label = tf.one_hot(label, num_classes) return image_resized, label
如果你的数据集里确实有GIF,那需要额外处理(比如取第一帧):
def _parse_function(filename, label): image_string = tf.read_file(filename) # 尝试先解码JPEG,失败则解码GIF并取第一帧 try: image_decoded = tf.image.decode_jpeg(image_string, channels=3) except: image_decoded = tf.image.decode_gif(image_string) # 取GIF的第一帧,去掉帧数维度 image_decoded = image_decoded[0] image_resized = tf.image.resize_images(image_decoded, [img_rows, img_cols]) label = tf.one_hot(label, num_classes) return image_resized, label
2. 统一输入图像尺寸
你初始化VGG16时指定的输入形状是(224, 224, 3),但预处理里resize的尺寸是img_rows, img_cols = 299, 299,这两个必须一致!
修改方案:
把预处理的尺寸改成224x224,和VGG16要求的一致:
img_rows, img_cols = 224, 224 # 改成和VGG16输入匹配的尺寸
3. 修复模型输出层的类别数错误
你的数据集有5个类别(homer/marge/bart/lisa/maggie),但模型最后一层Dense(2, activation='softmax')只设置了2个输出,这会导致标签和输出不匹配的问题。
修改方案:
把输出层的神经元数量改成5:
predictions = Dense(num_classes, activation='softmax')(x) # 用num_classes变量更灵活
4. 调整训练步数的计算
你的train_steps和val_steps计算明显有问题,应该用训练集总样本数 / batch_size,而不是固定的372/1和43/1:
batch_size = 10 # 你设置的batch size train_steps = len(train_filenames_list) // batch_size val_steps = len(val_filenames_list) // batch_size
最后,完整的修改后代码片段(关键部分)
# 统一输入尺寸 img_rows, img_cols = 224, 224 num_classes = 5 # 修复后的预处理函数 def _parse_function(filename, label): image_string = tf.read_file(filename) image_decoded = tf.image.decode_jpeg(image_string, channels=3) image_resized = tf.image.resize_images(image_decoded, [img_rows, img_cols]) # 可选:归一化到VGG16要求的像素范围(0-255转成0-1,或者用preprocess_input) image_resized = tf.cast(image_resized, tf.float32) / 255.0 # 或者用官方的预处理函数: # image_resized = tf.keras.applications.vgg16.preprocess_input(image_resized) label = tf.one_hot(label, num_classes) return image_resized, label # 修复后的模型定义 base_model = tf.keras.applications.vgg16.VGG16(weights='imagenet', include_top=False, input_shape=(img_rows, img_cols, 3)) x = base_model.output x = tf.keras.layers.GlobalAveragePooling2D()(x) # 要加完整的层路径,避免未定义错误 x = tf.keras.layers.Dense(512, activation='relu')(x) x = tf.keras.layers.Dropout(0.3)(x) predictions = tf.keras.layers.Dense(num_classes, activation='softmax')(x) model = tf.keras.models.Model(inputs=base_model.input, outputs=predictions) # 修复后的训练步数 batch_size = 10 train_steps = len(train_filenames_list) // batch_size val_steps = len(val_filenames_list) // batch_size history = model.fit( train_dataset, steps_per_epoch = train_steps, epochs = epochs, validation_data = valid_dataset, validation_steps = val_steps)
另外,还有个小细节:你在代码里重复设置了train_set_percentage = .9,第二次切割训练/验证集的操作其实是多余的,建议删掉,避免样本量意外减少。
内容的提问来源于stack exchange,提问作者Maniesha

