TensorFlow:“NotImplementedError:当子类化`Model` 类时,你应该实现一个`call` 方法”

问题描述

在“PWCDCNet.py”中,我定义了以下人工神经网络:

class Conv2D(tfk.layers.Layer):
    def __init__(self,filters,kernel_size,strides,name=None,padding=1,dilation_rate=1):
    super(Conv2D,self).__init__(name=name)
    
    self.conv_out = tfk.layers.Conv2D(filters=filters,kernel_size=kernel_size,strides=strides,padding='same',kernel_initializer='he_normal',dilation_rate=dilation_rate,activation=tfk.layers.LeakyReLU(0.1))

    def call(self,inputs):
        return self.conv_out(inputs)

class DeConv2D(tfk.layers.Layer):
    def __init__(self,kernel_size=4,strides=2,name=None):
        super(DeConv2D,self).__init__(name=name)
    
    self.deconv_out = tfk.layers.Conv2DTranspose(filters=filters,name=name)

    def call(self,inputs):
        return self.deconv_out(inputs)


def CostVolumn(c1,warp,search_range,name='cost_volumn'):

    padded_lvl = tf.pad(warp,[[0,0],[search_range,search_range],[0,0]])
    _,h,w,_ = tf.unstack(tf.shape(c1))
    max_offset = search_range * 2 + 1

    cost_vol = []
    for y in range(0,max_offset):
        for x in range(0,max_offset):
            slice = tf.slice(padded_lvl,y,x,[-1,-1])
            cost = tf.reduce_mean(c1 * slice,axis=3,keepdims=True)
            cost_vol.append(cost)
    cost_vol = tf.concat(cost_vol,axis=3)
    cost_vol = tf.nn.leaky_relu(cost_vol,alpha=0.1,name=name)

    return cost_vol

class PredictFlow(tfk.layers.Layer):
    def __init__(self,name=None):
        super(PredictFlow,self).__init__()

        self.conv_out = tfk.layers.Conv2D(filters=2,kernel_size=3,strides=1,name=name,padding='same')

    def call(self,inputs):
        return self.conv_out(inputs)

class PWCDCNet(tf.keras.Model):
    def __init__(self,max_displacement=4):
        super(PWCDCNet,self).__init__()

        self.conv1a  = Conv2D( 16,name='conv1a')
        self.conv1aa = Conv2D( 16,name='conv1aa')
        self.conv1b  = Conv2D( 16,name='conv1b')
        self.conv2a  = Conv2D( 32,name='conv2a')
        self.conv2aa = Conv2D( 32,name='conv2aa')
        self.conv2b  = Conv2D( 32,name='conv2b')
        self.conv3a  = Conv2D( 64,name='conv3a')
        self.conv3aa = Conv2D( 64,name='conv3aa')
        self.conv3b  = Conv2D( 64,name='conv3b')
        self.conv4a  = Conv2D( 96,name='conv4a')
        self.conv4aa = Conv2D( 96,name='conv4aa')
        self.conv4b  = Conv2D( 96,name='conv4b')
        self.conv5a  = Conv2D(128,name='conv5a')
        self.conv5aa = Conv2D(128,name='conv5aa')
        self.conv5b  = Conv2D(128,name='conv5b')
        self.conv6aa = Conv2D(196,name='conv6aa')
        self.conv6a  = Conv2D(196,name='conv6a')
        self.conv6b  = Conv2D(196,name='conv6b')

        self.LeakyReLU = tfk.layers.LeakyReLU(0.1,name='LeakyReLU')

        self.conv6_0 = Conv2D(128,name='conv6_0')
        self.conv6_1 = Conv2D(128,name='conv6_1')
        self.conv6_2 = Conv2D(96,name='conv6_2')
        self.conv6_3 = Conv2D(64,name='conv6_3')
        self.conv6_4 = Conv2D(32,name='conv6_4')
        self.deconv6 = DeConv2D(2,name='deconv_6')
        self.upfeat6 = DeConv2D(2,name='upfeat_6')

        self.conv5_0 = Conv2D(128,name='conv5_0')
        self.conv5_1 = Conv2D(128,name='conv5_1')
        self.conv5_2 = Conv2D(96,name='conv5_2')
        self.conv5_3 = Conv2D(64,name='conv5_3')
        self.conv5_4 = Conv2D(32,name='conv5_4')
        self.deconv5 = DeConv2D(2,name='deconv_5')
        self.upfeat5 = DeConv2D(2,name='upfeat_5')

        self.conv4_0 = Conv2D(128,name='conv4_0')
        self.conv4_1 = Conv2D(128,name='conv4_1')
        self.conv4_2 = Conv2D(96,name='conv4_2')
        self.conv4_3 = Conv2D(64,name='conv4_3')
        self.conv4_4 = Conv2D(32,name='conv4_4')
        self.deconv4 = DeConv2D(2,name='deconv4')
        self.upfeat4 = DeConv2D(2,name='upfeat4')

        self.conv3_0 = Conv2D(128,name='conv3_0')
        self.conv3_1 = Conv2D(128,name='conv3_1')
        self.conv3_2 = Conv2D(96,name='conv3_2')
        self.conv3_3 = Conv2D(64,name='conv3_3')
        self.conv3_4 = Conv2D(32,name='conv3_4')
        self.deconv3 = DeConv2D(2,name='deconv3')
        self.upfeat3 = DeConv2D(2,name='upfeat3')

        self.conv2_0 = Conv2D(128,name='conv2_0')
        self.conv2_1 = Conv2D(128,name='conv2_1')
        self.conv2_2 = Conv2D(96,name='conv2_2')
        self.conv2_3 = Conv2D(64,name='conv2_3')
        self.conv2_4 = Conv2D(32,name='conv2_4')
        self.deconv2 = DeConv2D(2,name='deconv2')

        self.dc_conv1 = Conv2D(128,dilation_rate=1,name='dc_conv1')
        self.dc_conv2 = Conv2D(128,padding=2,dilation_rate=2,name='dc_conv2')
        self.dc_conv3 = Conv2D(128,padding=4,dilation_rate=4,name='dc_conv3')
        self.dc_conv4 = Conv2D(96,padding=8,dilation_rate=8,name='dc_conv4')
        self.dc_conv5 = Conv2D(64,padding=16,dilation_rate=16,name='dc_conv5')
        self.dc_conv6 = Conv2D(32,name='dc_conv6')

        self.predict_flow6 = PredictFlow(name='predict_flow6')
        self.predict_flow5 = PredictFlow(name='predict_flow5')
        self.predict_flow4 = PredictFlow(name='predict_flow4')
        self.predict_flow3 = PredictFlow(name='predict_flow3')
        self.predict_flow2 = PredictFlow(name='predict_flow2')
        self.dc_conv7 = PredictFlow(name='dc_conv7')

    def call(self,inputs):
        im1 = inputs[:,:,:3]
        im2 = inputs[:,3:]
        c11 = self.conv1b(self.conv1aa(self.conv1a(im1)))
        c21 = self.conv1b(self.conv1aa(self.conv1a(im2)))
        c12 = self.conv2b(self.conv2aa(self.conv2a(c11)))
        c22 = self.conv2b(self.conv2aa(self.conv2a(c21)))
        c13 = self.conv3b(self.conv3aa(self.conv3a(c12)))
        c23 = self.conv3b(self.conv3aa(self.conv3a(c22)))
        c14 = self.conv4b(self.conv4aa(self.conv4a(c13)))
        c24 = self.conv4b(self.conv4aa(self.conv4a(c23)))
        c15 = self.conv5b(self.conv5aa(self.conv5a(c14)))
        c25 = self.conv5b(self.conv5aa(self.conv5a(c24)))
        c16 = self.conv6b(self.conv6a(self.conv6aa(c15)))
        c26 = self.conv6b(self.conv6a(self.conv6aa(c25)))

        ### 6th flow    
        corr6 = CostVolumn(c1=c16,warp=c26,search_range=4)
        x = tf.concat([self.conv6_0(corr6),corr6],3)
        x = tf.concat([self.conv6_1(x),x],3)
        x = tf.concat([self.conv6_2(x),3)
        x = tf.concat([self.conv6_3(x),3)
        x = tf.concat([self.conv6_4(x),3)
    
        flow6 = self.predict_flow6(x)
        up_flow6 = self.deconv6(flow6)
        up_feat6 = self.upfeat6(x)    

        ### 5th flow
        warp5 = bilinear_warp(c25,up_flow6*0.625)
        corr5 = CostVolumn(c1=c15,warp=warp5,search_range=4)

        x = tf.concat([corr5,c15,up_flow6,up_feat6],3)
        x = tf.concat([self.conv5_0(x),3)
        x = tf.concat([self.conv5_1(x),3)
        x = tf.concat([self.conv5_2(x),3)
        x = tf.concat([self.conv5_3(x),3)
        x = tf.concat([self.conv5_4(x),3)
        flow5 = self.predict_flow5(x)
        up_flow5 = self.deconv5(flow5)
        up_feat5 = self.upfeat5(x)

        ### 4th flow
        warp4 = bilinear_warp(c24,up_flow5*1.25)
        corr4 = CostVolumn(c1=c14,warp=warp4,search_range=4)

        x = tf.concat([corr4,c14,up_flow5,up_feat5],3)
        x = tf.concat([self.conv4_0(x),3)
        x = tf.concat([self.conv4_1(x),3)
        x = tf.concat([self.conv4_2(x),3)
        x = tf.concat([self.conv4_3(x),3)
        x = tf.concat([self.conv4_4(x),3)
        flow4 = self.predict_flow4(x)
        up_flow4 = self.deconv4(flow4)
        up_feat4 = self.upfeat4(x)

        ### 3rd flow
        warp3 = bilinear_warp(c23,up_flow4*2.5)
        corr3 = CostVolumn(c1=c13,warp=warp3,search_range=4)
    
        x = tf.concat([corr3,c13,up_flow4,up_feat4],3)
        x = tf.concat([self.conv3_0(x),3)
        x = tf.concat([self.conv3_1(x),3)
        x = tf.concat([self.conv3_2(x),3)
        x = tf.concat([self.conv3_3(x),3)
        x = tf.concat([self.conv3_4(x),3)
        flow3 = self.predict_flow3(x)
        up_flow3 = self.deconv3(flow3)
        up_feat3 = self.upfeat3(x)

        # 2nd flow
        warp2 = bilinear_warp(c22,up_flow3*5.0) 
        corr2 = CostVolumn(c1=c12,warp=warp2,search_range=4)

        x = tf.concat([corr2,c12,up_flow3,up_feat3],3)
        x = tf.concat([self.conv2_0(x),3)
        x = tf.concat([self.conv2_1(x),3)
        x = tf.concat([self.conv2_2(x),3)
        x = tf.concat([self.conv2_3(x),3)
        x = tf.concat([self.conv2_4(x),3)
        flow2 = self.predict_flow2(x)

        x = self.dc_conv4(self.dc_conv3(self.dc_conv2(self.dc_conv1(x))))
        flow2 = flow2 + self.dc_conv7(self.dc_conv6(self.dc_conv5(x)))

        return flow2

这个 ANN 被导入到另一个文件中:

from PWCNet_tf2.PWCDCNet import PWCDCNet
PWC_model = tf.keras.Model(PWCDCNet())
checkpoint = tf.train.Checkpoint(PWC_model)
save_path = checkpoint.save('/some_directories/PWCNet_tf2/checkpoints/0001/tf_ckpt')
checkpoint.restore(save_path)

但如果我尝试:

output =  PWC_model(input)

我收到错误

NotImplementedError: When subclassing the `Model` class,you should implement a `call` method.

我想知道,因为每个层都实现了调用方法,而且整个 ANN 也实现了调用方法。是我导入模型的方式导致的错误吗?

先谢谢大家!

解决方法

错误是我调用的:

PWC_model = tf.keras.Model(PWCDCNet())

代替:

PWC_model = PWCDCNet()