添加自定义Layer报错TypeError:继承tf.keras.layers.Layer仍无效
问题解决:自定义层添加时报
TypeError 核心错误原因
你在model.add(New_Layer)这一行传入的是类本身,而非该类的实例对象。Keras要求添加到模型的必须是Layer的实例,不能直接传类定义。
修复步骤
实例化自定义层
把model.add(New_Layer)改为model.add(New_Layer(context=你的上下文对象)),比如你需要传入一个包含文件名的字典实例:context={"file_name": "sample.jpg"}。补全
call方法未完成代码call方法里new_image =后没有赋值,会触发语法错误,需要补全图像加载逻辑,示例如下:# 加载并预处理图像 new_image = tf.keras.preprocessing.image.load_img(file_name, target_size=(299,299)) new_image = tf.keras.preprocessing.image.img_to_array(new_image) new_image = tf.expand_dims(new_image, axis=0) # 匹配batch维度 # 对新图像做和主干网络一致的特征提取,保证维度匹配 new_image = conv_base(new_image) new_image = tf.keras.layers.GlobalAveragePooling2D()(new_image)修正预训练模型冻结逻辑
原代码会把整个conv_base设为不可训练,正确的冻结前n-20层的写法是:conv_base.trainable = True for layer in conv_base.layers[:-20]: layer.trainable = False
修复后完整代码示例
import tensorflow as tf from tensorflow.keras.optimizers import Adam # 初始化预训练模型 conv_base = tf.keras.applications.InceptionResNetV2(weights=None, include_top=False, input_shape=(299,299,3)) conv_base.trainable = True # 冻结前n-20层 for layer in conv_base.layers[:-20]: layer.trainable = False class New_Layer(tf.keras.layers.Layer): def __init__(self, context, **kwargs): super(New_Layer, self).__init__(**kwargs) self.context = context # 把conv_base作为层的属性,避免call方法中引用外部变量 self.conv_base = conv_base def call(self, inputs): feature_map = inputs file_name = self.context.get('file_name') print(file_name) # 加载并处理新图像 new_image = tf.keras.preprocessing.image.load_img(file_name, target_size=(299,299)) new_image = tf.keras.preprocessing.image.img_to_array(new_image) new_image = tf.expand_dims(new_image, axis=0) # 提取新图像特征,保证和输入feature_map维度一致 new_image = self.conv_base(new_image) new_image = tf.keras.layers.GlobalAveragePooling2D()(new_image) return tf.concat([feature_map, new_image], axis=-1) # 实例化上下文对象 context = {"file_name": "your_image_path.jpg"} # 构建模型 model = tf.keras.Sequential() model.add(conv_base) model.add(tf.keras.layers.GlobalAveragePooling2D()) model.add(New_Layer(context=context)) # 传入层实例而非类 model.add(tf.keras.layers.Dense(7, activation='softmax')) model.summary() model.compile(optimizer=Adam(learning_rate=0.001), loss='categorical_crossentropy', metrics=['accuracy'])
额外说明
如果需要动态传入每个样本的文件名(而非固定值),Sequential模型无法满足,建议改用函数式API:
input_image = tf.keras.Input(shape=(299,299,3)) input_file_name = tf.keras.Input(shape=(), dtype=tf.string) # 主干特征提取 x = conv_base(input_image) x = tf.keras.layers.GlobalAveragePooling2D()(x) # 动态加载并处理新图像的Lambda层 def process_image(file_name): new_image = tf.io.read_file(file_name) new_image = tf.image.decode_jpeg(new_image, channels=3) new_image = tf.image.resize(new_image, (299,299)) new_image = tf.keras.applications.inception_resnet_v2.preprocess_input(new_image) new_image = conv_base(new_image) return tf.keras.layers.GlobalAveragePooling2D()(new_image) new_feature = tf.keras.layers.Lambda(process_image)(input_file_name) x = tf.concat([x, new_feature], axis=-1) output = tf.keras.layers.Dense(7, activation='softmax')(x) model = tf.keras.Model(inputs=[input_image, input_file_name], outputs=output)
内容的提问来源于stack exchange,提问作者Pepeeeee
相关产品推荐
相关产品推荐

