构建DeepLabV3+模型时遇ValueError:输出张量需为TensorFlow Layer输出
DeepLabV3+构建时TensorFlow输入输出ValueError排查
问题现象
构建DeepLabV3+模型时触发以下ValueError:
ValueError: Functional模型的输出张量必须是TensorFlow `Layer`的输出(需包含历史层元数据)。找到: <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f5c1c3b6310>
错误原因
代码中convolution_block函数的返回值使用了TensorFlow原生激活函数tf.nn.relu(x),这不是Keras Layer的输出,因此该张量不携带_keras_history元数据。Keras Functional模型要求所有构成模型的张量都必须来自Keras Layer的输出,否则无法追踪层之间的依赖关系。
修复方案
将convolution_block中的tf.nn.relu(x)替换为Keras的layers.ReLU()层调用,确保返回的是带有层元数据的张量。
完整修正代码
import os import cv2 import numpy as np from glob import glob from scipy.io import loadmat import matplotlib.pyplot as plt import tensorflow as tf from tensorflow import keras from tensorflow.keras import layers !gdown https://drive.google.com/uc?id=1B9A9UCJYMwTL4oBEo4RZfbMZMaZhKJaz !unzip -q instance-level-human-parsing.zip #Organizing the dataset IMAGE_SIZE = 512 BATCH_SIZE = 4 NUM_CLASSES = 20 DATA_DIR = "./instance-level_human_parsing/instance-level_human_parsing/Training" NUM_TRAIN_IMAGES = 1000 NUM_VAL_IMAGES = 50 train_images = sorted(glob(os.path.join(DATA_DIR, "Images/*")))[:NUM_TRAIN_IMAGES] train_masks = sorted(glob(os.path.join(DATA_DIR, "Category_ids/*")))[:NUM_TRAIN_IMAGES] val_images = sorted(glob(os.path.join(DATA_DIR, "Images/*")))[ NUM_TRAIN_IMAGES : NUM_VAL_IMAGES + NUM_TRAIN_IMAGES ] val_masks = sorted(glob(os.path.join(DATA_DIR, "Category_ids/*")))[ NUM_TRAIN_IMAGES : NUM_VAL_IMAGES + NUM_TRAIN_IMAGES ] def read_image(image_path, mask=False): image = tf.io.read_file(image_path) if mask: image = tf.image.decode_png(image, channels=1) image.set_shape([None, None, 1]) image = tf.image.resize(images=image, size=[IMAGE_SIZE, IMAGE_SIZE]) else: image = tf.image.decode_png(image, channels=3) image.set_shape([None, None, 3]) image = tf.image.resize(images=image, size=[IMAGE_SIZE, IMAGE_SIZE]) image = image / 127.5 - 1 return image def load_data(image_list, mask_list): image = read_image(image_list) mask = read_image(mask_list, mask=True) return image, mask def data_generator(image_list, mask_list): dataset = tf.data.Dataset.from_tensor_slices((image_list, mask_list)) dataset = dataset.map(load_data, num_parallel_calls=tf.data.AUTOTUNE) dataset = dataset.batch(BATCH_SIZE, drop_remainder=True) return dataset train_dataset = data_generator(train_images, train_masks) val_dataset = data_generator(val_images, val_masks) print("Train Dataset:", train_dataset) print("Val Dataset:", val_dataset) #Building the model def convolution_block( block_input, num_filters=256, kernel_size=3, dilation_rate=1, padding="same", use_bias=False, ): x = layers.Conv2D( num_filters, kernel_size=kernel_size, dilation_rate=dilation_rate, padding="same", use_bias=use_bias, kernel_initializer=keras.initializers.HeNormal(), )(block_input) x = layers.BatchNormalization()(x) # 替换原生relu为Keras ReLU层 return layers.ReLU()(x) def DilatedSpatialPyramidPooling(dspp_input): dims = dspp_input.shape x = layers.AveragePooling2D(pool_size=(dims[-3], dims[-2]))(dspp_input) x = convolution_block(x, kernel_size=1, use_bias=True) out_pool = layers.UpSampling2D( size=(dims[-3] // x.shape[1], dims[-2] // x.shape[2]), interpolation="bilinear", )(x) out_1 = convolution_block(dspp_input, kernel_size=1, dilation_rate=1) out_6 = convolution_block(dspp_input, kernel_size=3, dilation_rate=6) out_12 = convolution_block(dspp_input, kernel_size=3, dilation_rate=12) out_18 = convolution_block(dspp_input, kernel_size=3, dilation_rate=18) x = layers.Concatenate(axis=-1)([out_pool, out_1, out_6, out_12, out_18]) output = convolution_block(x, kernel_size=1) return output def DeeplabV3Plus(image_size, num_classes): model_input = keras.Input(shape=(image_size, image_size, 3)) resnet50 = keras.applications.ResNet50( weights="imagenet", include_top=False, input_tensor=model_input ) x = resnet50.get_layer("conv4_block6_2_relu").output x = DilatedSpatialPyramidPooling(x) input_a = layers.UpSampling2D( size=(image_size // 4 // x.shape[1], image_size // 4 // x.shape[2]), interpolation="bilinear", )(x) input_b = resnet50.get_layer("conv2_block3_2_relu").output input_b = convolution_block(input_b, num_filters=48, kernel_size=1) x = layers.Concatenate(axis=-1)([input_a, input_b]) x = convolution_block(x) x = convolution_block(x) x = layers.UpSampling2D( size=(image_size // x.shape[1], image_size // x.shape[2]), interpolation="bilinear", )(x) model_output = layers.Conv2D(num_classes, kernel_size=(1, 1), padding="same")(x) return keras.Model(inputs=model_input, outputs=model_output) model = DeeplabV3Plus(image_size=IMAGE_SIZE, num_classes=NUM_CLASSES) model.summary()
说明
修改后的convolution_block函数使用layers.ReLU()(x)替代tf.nn.relu(x),确保每个卷积块的输出都是Keras Layer的产物,携带必要的层历史元数据,从而满足Functional模型的构建要求。
内容的提问来源于stack exchange,提问作者Ambroze kweronda
相关产品推荐
相关产品推荐

