tensorflow获取模型中间层结果及错误tf.keras.backend.function Layer ‘ + self.name + ‘ has no inbound nodes.

错误使用

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.

 

你可能感兴趣的:(深度学习,tensorflow,tensorflow)