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

keras.backend.function()无法接受model.layers[0].input作为输入张量

问题:适配OpenMax到CIFAR-100时获取模型激活向量报错

尝试将OpenMax的TensorFlow实现适配到CIFAR-100项目,需要获取模型倒数第二层的激活向量,使用了如下函数:

def get_activations(model, layer, X_batch):
    get_activations = K.function(
        [model.layers[0].input, K.learning_phase()],
        [model.layers[layer].output])
    
    activations = get_activations([DataGenerator(X_batch, mode='predict', batch_size=8, augment=False, shuffle=False), 0])[0]
    # print (activations.shape)
    return activations

参数说明:

  • layer:层编号(倒数第二层为-2)
  • X_batch:输入图像批次,形状(597, 32, 32, 3),类型numpy.ndarray

使用Functional API构建的模型:

from tensorflow.keras.layers import Input, GlobalAveragePooling2D, Dropout, Dense
from efficientnet.tfkeras import EfficientNetB0
import tensorflow as tf

height = 224
width = 224
channels = 3
n_classes = 20
input_shape = (height, width, channels)

# 定义输入层
inputs = Input(shape=input_shape, name='input_layer')

# 加载EfficientNetB0
efnb0 = EfficientNetB0(weights='imagenet', include_top=False, input_shape=input_shape)

# 添加后续层
x = efnb0(inputs)
x = GlobalAveragePooling2D()(x)
x = Dropout(0.5)(x)
x = Dense(n_classes, activation='relu')(x)
outputs = Dense(n_classes, activation='softmax')(x)

# 构建模型
model = tf.keras.models.Model(inputs=inputs, outputs=outputs)

model.summary()

模型摘要:

Model: "model_4"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 input_layer (InputLayer)    [(None, 224, 224, 3)]     0         
                                                                 
 efficientnet-b0 (Functional  (None, 7, 7, 1280)       4049564   
 )                                                               
                                                                 
 global_average_pooling2d (G  (None, 1280)             0         
 lobalAveragePooling2D)                                           
                                                                 
 dropout (Dropout)           (None, 1280)              0         
                                                                 
 dense (Dense)               (None, 20)                25620     
                                                                 
 dense_1 (Dense)             (None, 20)                420       
                                                                 
=================================================================
Total params: 4,075,604
Trainable params: 4,033,588
Non-trainable params: 42,016
_________________________________________________________________
None

DataGenerator用于将输入图像调整为(224, 224, 3)形状,但调用K.function()时报错,完整报错栈:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[29], line 74
     72 data = X_train, X_test, y_train, y_test
     73 #create_model(models[child_id], data)
---> 74 create_model(functional_model, data)
     75 for i in range(5):
     76     random_char = np.random.randint(0,len(X_test))

Cell In[28], line 254, in create_model(model, data)
    252 print(f'i, sep_x[i]: {i}, {sep_x[i].shape}')
    253 weibull_model[label[i]] = {}
--> 254 score, fc8 = compute_feature(sep_x[i], model)
    255 mean = compute_mean_vector(fc8)
    256 distance = compute_distances(mean, fc8, sep_y)

Cell In[28], line 131, in compute_feature(x, model)
    128 def compute_feature(x, model):
    129     # output = models[i].layers[-2].output         # define output layer, [-1] is last layer
    130     print(f'shape of sep_x: {x.shape}, {type(x)}')
--> 131     score = get_activations(model, -1, x)
    132     fc8 = get_activations(model, -2, x)
    133     return score, fc8

Cell In[28], line 208, in get_activations(model, layer, X_batch)
    205 def get_activations(model, layer, X_batch):
    206     # print (model.layers[6].output)
    207     X_batch_tensor = tf.convert_to_tensor(X_batch)
--> 208     get_activations = K.function(
    209         [model.layers[0].input, K.learning_phase()],
    210         [model.layers[layer].output])
    212     activations = get_activations([DataGenerator(X_batch, mode='predict', batch_size=8, augment=False, shuffle=False), 0])[0]
    213     # print (activations.shape)

File ~\Python310\lib\site-packages\keras\backend.py:4625, in function(inputs, outputs, updates, name, **kwargs)
   4622 from keras import models
   4623 from keras.utils import tf_utils
-> 4625 model = models.Model(inputs=inputs, outputs=outputs)
   4627 wrap_outputs = isinstance(outputs, list) and len(outputs) == 1
   4629 def func(model_inputs):

File ~\Python310\lib\site-packages\tensorflow\python\trackable\base.py:205, in no_automatic_dependency_tracking.<locals>._method_wrapper(self, *args, **kwargs)
    203 self._self_setattr_tracking = False  # pylint: disable=protected-access
    204 try:
--> 205   result = method(self, *args, **kwargs)
    206 finally:
    207   self._self_setattr_tracking = previous_value  # pylint: disable=protected-access

File ~\Python310\lib\site-packages\keras\engine\functional.py:157, in Functional.__init__(self, inputs, outputs, name, trainable, **kwargs)
    151 # Check if the inputs contain any intermediate `KerasTensor` (not
    152 # created by tf.keras.Input()). In this case we need to clone the `Node`
    153 # and `KerasTensor` objects to mimic rebuilding a new model from new
    154 # inputs.  This feature is only enabled in TF2 not in v1 graph mode.
    155 if tf.compat.v1.executing_eagerly_outside_functions():
    156     if not all(
--> 157         [
    158             functional_utils.is_input_keras_tensor(t)
    159             for t in tf.nest.flatten(inputs)
    160         ]
    161     ):
    162         inputs, outputs = functional_utils.clone_graph_nodes(
    163             inputs, outputs
    164         )
    165 self._init_graph_network(inputs, outputs)

File ~\Python310\lib\site-packages\keras\engine\functional.py:158, in <listcomp>(.0)
    151 # Check if the inputs contain any intermediate `KerasTensor` (not
    152 # created by tf.keras.Input()). In this case we need to clone the `Node`
    153 # and `KerasTensor` objects to mimic rebuilding a new model from new
    154 # inputs.  This feature is only enabled in TF2 not in v1 graph mode.
    155 if tf.compat.v1.executing_eagerly_outside_functions():
    156     if not all(
    157         [
--> 158             functional_utils.is_input_keras_tensor(t)
    159             for t in tf.nest.flatten(inputs)
    160         ]
    161     ):
    162         inputs, outputs = functional_utils.clone_graph_nodes(
    163             inputs, outputs
    164         )
    165 self._init_graph_network(inputs, outputs)

File ~\Python310\lib\site-packages\keras\engine\functional_utils.py:48, in is_input_keras_tensor(tensor)
     32 """Check if tensor is directly generated from `tf.keras.Input`.
     33 
     34 This check is useful when constructing the functional model, since we will
   (...)
     45   ValueError: if the tensor is not a KerasTensor instance.
     46 """
     47 if not node_module.is_keras_tensor(tensor):
--> 48     raise ValueError(_KERAS_TENSOR_TYPE_CHECK_ERROR_MSG.format(tensor))
     49 return tensor.node.is_input

ValueError: Found unexpected instance while processing input tensors for keras functional model. Expecting KerasTensor which is from tf.keras.Input() or output from keras layer call(). Got: 0

已尝试改用Functional API重新训练模型、更新Keras和TensorFlow至最新版本,问题依旧,需排查错误原因。


解决方案

错误核心原因

  1. K.learning_phase()已过时:TF2.x中该API已被弃用,且直接传入0作为学习阶段参数不符合当前Keras的输入规范。
  2. 输入类型错误:调用K.function返回的函数时,传入了DataGenerator实例而非预处理后的张量——K.function需要直接接收numpy数组或tf张量,不能传入生成器对象。

修复后的get_activations函数

改用Keras子模型的方式获取中间层激活向量,兼容TF2.x且逻辑更清晰:

import numpy as np

def get_activations(model, layer_idx, X_batch):
    # 构建以目标层为输出的子模型
    activation_model = tf.keras.models.Model(
        inputs=model.input,
        outputs=model.layers[layer_idx].output
    )
    # 通过生成器处理输入并获取所有批次的激活向量
    datagen = DataGenerator(X_batch, mode='predict', batch_size=8, augment=False, shuffle=False)
    all_activations = []
    for batch in datagen:
        # 假设生成器返回(数据, 标签)格式,取数据部分
        batch_data = batch[0]
        activations = activation_model.predict(batch_data, verbose=0)
        all_activations.append(activations)
    # 拼接所有批次结果
    return np.concatenate(all_activations, axis=0)

简化替代方案(无需生成器)

如果仅需调整图像尺寸,可手动预处理后直接传入:

import cv2
import numpy as np

def preprocess_images(X_batch, target_size=(224,224)):
    processed = []
    for img in X_batch:
        # 调整尺寸并保持通道数
        resized = cv2.resize(img, target_size)
        processed.append(resized)
    return np.array(processed)

def get_activations(model, layer_idx, X_batch):
    activation_model = tf.keras.models.Model(
        inputs=model.input,
        outputs=model.layers[layer_idx].output
    )
    processed_X = preprocess_images(X_batch)
    return activation_model.predict(processed_X, verbose=0)

关键注意事项

  1. 验证层索引:可通过print([layer.name for layer in model.layers])确认目标层的索引,避免因嵌套模型(如EfficientNetB0本身是Functional模型)导致索引错误。
  2. TF2.x最佳实践:尽量避免使用K.function,优先通过子模型或model.predict获取中间层输出,更符合Eager Execution的设计逻辑。

内容的提问来源于stack exchange,提问作者Saeed Aram

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 16:27:00