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至最新版本,问题依旧,需排查错误原因。
解决方案
错误核心原因
K.learning_phase()已过时:TF2.x中该API已被弃用,且直接传入0作为学习阶段参数不符合当前Keras的输入规范。- 输入类型错误:调用
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)
关键注意事项
- 验证层索引:可通过
print([layer.name for layer in model.layers])确认目标层的索引,避免因嵌套模型(如EfficientNetB0本身是Functional模型)导致索引错误。 - TF2.x最佳实践:尽量避免使用
K.function,优先通过子模型或model.predict获取中间层输出,更符合Eager Execution的设计逻辑。
内容的提问来源于stack exchange,提问作者Saeed Aram
相关产品推荐
相关产品推荐

