TensorFlow输入形状不兼容:数据集与模型形状匹配错误
我需要实现图像处理任务:输入一张图像,输出对应的掩码。测试阶段仅使用单张图像及其掩码,二者形状均为(720, 1280, 3)。通过以下代码创建数据集:
train_data = tf.data.Dataset.from_tensors((img, mask))
搭建的简单模型如下:
model = tf.keras.Sequential([ tf.keras.layers.experimental.preprocessing.Rescaling(1./255, input_shape=(720, 1280, 3)), tf.keras.layers.Conv2D(128, 5, padding='same', activation='relu'), tf.keras.layers.MaxPooling2D(), tf.keras.layers.Conv2D(128, 5, padding='same', activation='relu'), tf.keras.layers.MaxPooling2D(), tf.keras.layers.Conv2DTranspose(2, [720, 1280]) ]) model.compile(optimizer='adam', loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy'])
运行时触发错误:
ValueError: Input 0 of layer "sequential_24" is incompatible with the layer: expected shape=(None, 720, 1280, 3), found shape=(720, 1280, 3)
核心问题是输入缺少批次维度,尝试过调整括号、使用tf.data.Dataset.from_tensor_slices,但最多得到形状为(2, 720, 1280, 3)的结果,且丢失标签列。求正确的数据集设置或模型调整方案。
1. 补全数据集的批次维度
Keras模型默认要求输入包含批次维度(形状格式为(batch_size, height, width, channels)),可通过两种方式解决:
方式一:给数据集添加批次维度
直接使用batch()方法,或手动扩展图像/掩码的维度后创建数据集:
# 方法1:通过batch方法添加批次 train_data = tf.data.Dataset.from_tensors((img, mask)).batch(1) # 方法2:手动扩展维度后创建数据集 img_batch = tf.expand_dims(img, axis=0) mask_batch = tf.expand_dims(mask, axis=0) train_data = tf.data.Dataset.from_tensors((img_batch, mask_batch))
处理后数据集的元素形状为(1, 720, 1280, 3),完全匹配模型的输入要求。
方式二:调整模型支持单样本输入
修改模型的input_shape为(None, None, 3),让模型兼容任意尺寸的单样本输入,训练时手动给数据加批次维度:
model = tf.keras.Sequential([ tf.keras.layers.experimental.preprocessing.Rescaling(1./255, input_shape=(None, None, 3)), tf.keras.layers.Conv2D(128, 5, padding='same', activation='relu'), tf.keras.layers.MaxPooling2D(), tf.keras.layers.Conv2D(128, 5, padding='same', activation='relu'), tf.keras.layers.MaxPooling2D(), tf.keras.layers.Conv2DTranspose(2, [720, 1280]) ]) # 训练时扩展维度 model.fit(tf.expand_dims(img, 0), tf.expand_dims(mask, 0))
2. 修正模型的输出形状匹配问题
当前Conv2DTranspose层参数存在错误:经过两次MaxPooling2D(默认2倍下采样)后,特征图尺寸已缩小为(180, 320),直接使用[720, 1280]的卷积核会导致输出形状不匹配。需调整转置卷积参数,恢复到输入掩码的尺寸:
model = tf.keras.Sequential([ tf.keras.layers.experimental.preprocessing.Rescaling(1./255, input_shape=(720, 1280, 3)), tf.keras.layers.Conv2D(128, 5, padding='same', activation='relu'), tf.keras.layers.MaxPooling2D(pool_size=(2,2)), tf.keras.layers.Conv2D(128, 5, padding='same', activation='relu'), tf.keras.layers.MaxPooling2D(pool_size=(2,2)), # 两次转置卷积逐步恢复尺寸,每次上采样2倍 tf.keras.layers.Conv2DTranspose(128, 5, strides=(2,2), padding='same', activation='relu'), tf.keras.layers.Conv2DTranspose(2, 5, strides=(2,2), padding='same') # 输出通道数对应分类类别数 ])
调整后模型输出形状为(batch_size, 720, 1280, 2),与掩码形状匹配。另外,若掩码是3通道格式,需将其转换为单通道的类别索引(因为使用了SparseCategoricalCrossentropy损失)。
3. 关于from_tensor_slices的误区
from_tensor_slices会按输入张量的第一维度进行切片,若直接传入(img, mask),会将(720,1280,3)的图像切分为720个形状为(1280,3)的样本,这不符合任务需求。单样本场景下,应优先使用from_tensors配合batch(1)的方案。
内容的提问来源于stack exchange,提问作者tailoxyn

