错误使用
1、构建模型:
import tensorflow as tf
import collections
from efficientnet import tfkeras
class MyModel(tf.keras.Model):
def __init__(self, height=None,width=None,channel=None):
super(MyModel,self).__init__()
self.inputshape = tf.keras.layers.InputLayer(input_shape=(height,width,channel))
self.effnet = tfkeras.EfficientNetB0(
include_top=False,
weights='imagenet',
input_shape=(height,width,channel)
)
self.pool = tf.keras.layers.GlobalAveragePooling2D(name="GlobalAP")
self.dense3 = tf.keras.layers.Dense(512,activation="relu",kernel_initializer="he_normal")
self.dense4 = tf.keras.layers.Dense(6,activation="softmax")
def call(self, input):
# x = self.resnet50(input)
# print(x.shape)
x = self.inputshape(input)
x = self.effnet(x)
print(x)
x = self.pool(x)
x = self.dense3(x)
self.out = self.dense4(x)
return self.out
2、调用已训练模型中间层输出
for index, (train_index, valid_index) in enumerate(kfold.split(train_data,label)):
print("========= %d =========="%index)
x_train, x_valid, y_train, y_valid = X_train[train_index], X_train[valid_index], Y_train[train_index], Y_train[valid_index]
md = model.MyModel(width, height, channel)
# =======================================================================
## 获取中间结果
get_GlobalAveragePooling = tf.keras.backend.function([md.layers[0].input,
tf.keras.backend.learning_phase()], [md.GlobalAP.output])
# =======================================================================
checkpoint_path = "training/weights-{epoch:02d}-{val_acc:.5f}.ckpt"
checkpoint_dir = os.path.dirname(checkpoint_path)
optimizer = tf.keras.optimizers.Adam(lr=0.001)
md.compile(optimizer,loss="categorical_crossentropy",metrics=["accuracy"])
call_backs = [
tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss',
min_lr=0.0000001,
cooldown=1,
verbose=1,),
tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_path,
save_best_only=True,
monitor="val_acc",
verbose=1,
mode="max",
save_weights_only=True,
period=3,),
]
md.fit(x_train,y_train,batch_size=batch_size,epochs=100,shuffle=True,verbose=2,
validation_data=(x_valid,y_valid),callbacks=call_backs)
# # 加载最新模型
latest = tf.train.latest_checkpoint(checkpoint_dir)
md.load_weights(latest)
# =======================================================================
# 获取中间层结果输出
# output in test mode = 0
GlobalAP_layer_output = get_GlobalAveragePooling([x_train, 0])[0]
GlobalAP_layer_output1 = get_GlobalAveragePooling([x_valid, 0])[0]
# =======================================================================
分析:如果使用以上代码获取已训练模型的中间层输出,则会报以下几种类型错误:
(1)AttributeError: The layer has never been called and thus has no defined output shape.
(2)Keras AttributeError 'NoneType' object has no attribute '_inbound_nodes'.
(3)AttributeError: Layer "GlobalAP" has no inbound nodes.
(4)tf.keras.backend.function Layer ' + self.name + ' has no inbound nodes.
网上也有很多解决方案,都直指输入层未定义,参考layer has no inbound nodes. 通过网上的说法及个人思考,发现自定义MyModel模型是通过 fit 函数来直接调用 call() 函数的,这样才能保持tensorflow图层中每层都是相连的。然而,这里获取中间层的定义是这样的:
get_GlobalAveragePooling = tf.keras.backend.function([md.layers[0].input,
tf.keras.backend.learning_phase()], [md.GlobalAP.output])
其中 md.layers[0]、md.GlobalAP是直接获取的MyModel类中__init__()定义的层,这些层并没有输入层,即
# md.GlobalAP.output 相当于下面代码
self.pool = tf.keras.layers.GlobalAveragePooling2D(name="GlobalAP")
md.GlobalAP.output == self.pool.output
这样理解的话,才会发生以上错误。
构建模型及调用中间层结果
for index, (train_index, valid_index) in enumerate(kfold.split(train_data,label)):
print("========= %d =========="%index)
x_train, x_valid, y_train, y_valid = X_train[train_index], X_train[valid_index],
Y_train[train_index], Y_train[valid_index]
# 构建模型
efficientNet = tfkeras.EfficientNetB3(
include_top=False,
weights='imagenet',
input_shape=(width, height,channel)
)
globalAP = tf.keras.layers.GlobalAveragePooling2D(name="GlobalAP")
x_in = tf.keras.layers.Input(shape=(width, height, channel),name="x_in")
x = x_in
x = efficientNet(x)
x = globalAP(x)
x = tf.keras.layers.Dense(512,activation="relu",kernel_initializer="he_normal")(x)
x = tf.keras.layers.Dense(6,activation="softmax")(x)
md = tf.keras.Model(x_in,x)
checkpoint_path = "training/weights-{epoch:02d}-{val_acc:.5f}.ckpt"
checkpoint_dir = os.path.dirname(checkpoint_path)
optimizer = tf.keras.optimizers.Adam(lr=0.001)
md.compile(optimizer,loss="categorical_crossentropy",metrics=["accuracy"])
call_backs = [
tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss',
min_lr=0.0000001,
cooldown=1,
verbose=1,),
tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_path,
save_best_only=True,
monitor="val_acc",
verbose=1,
mode="max",
save_weights_only=True,
period=3,),
]
md.fit(x_train,y_train,batch_size=batch_size,epochs=100,shuffle=True,verbose=2,
validation_data=(x_valid,y_valid),callbacks=call_backs)
# # 加载最新模型
latest = tf.train.latest_checkpoint(checkpoint_dir)
md.load_weights(latest)
# =======================================================================
## 获取中间结果
get_GlobalAveragePooling = tf.keras.backend.function([md.x_in.input,
tf.keras.backend.learning_phase()], [md.globalAP.output])
## 或者
# get_GlobalAveragePooling = tf.keras.backend.function([x_in,
# tf.keras.backend.learning_phase()], [globalAP.output])
# =======================================================================
# =======================================================================
# 获取中间层结果输出
# output in test mode = 0
GlobalAP_layer_output = get_GlobalAveragePooling([x_train, 0])[0]
GlobalAP_layer_output1 = get_GlobalAveragePooling([x_valid, 0])[0]
# =======================================================================
从构建模型可以看出,每层定义的时候都有输入层,相当于整个图层都是连通的,才不会发生以上错误。
这篇博客主要记录tensorflow获取中间层结果的错误及个人对错误的理解,如有不对请指教。
参考:
1、如何获取中间层的输出?
2、The layer has never been called and thus has no defined output shape.