You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

添加自定义Layer报错TypeError:继承tf.keras.layers.Layer仍无效

问题解决:自定义层添加时报TypeError

核心错误原因

你在model.add(New_Layer)这一行传入的是类本身,而非该类的实例对象。Keras要求添加到模型的必须是Layer的实例,不能直接传类定义。

修复步骤

  1. 实例化自定义层
    把model.add(New_Layer)改为model.add(New_Layer(context=你的上下文对象)),比如你需要传入一个包含文件名的字典实例:context={"file_name": "sample.jpg"}。

  2. 补全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)
    
  3. 修正预训练模型冻结逻辑
    原代码会把整个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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 08:29:57