Keras将功能模型转换为模型子类

时间:2019-07-01 02:38:07

标签: python tensorflow keras

我正在尝试使用Keras 模型子类来重写功能模型,但是在新的模型子类中,摘要生成无法正常工作。

作为参考,这里是功能模型及其输出。

filters = 32

# placeholder for inputs
inputs = Input(shape=[16, 16, 16, 12])  

# L-hand side of UNet
conv1 = DoubleConv3D(filters*1)(inputs)
pool1 = MaxPooling3D()(conv1)
...

# middle bottleneck
conv5 = DoubleConv3D(filters*5)(pool4)

# R-hand side of UNet
rsdc6 = ConcatConv3D(filters*4)(conv5, conv4)
conv6 = DoubleConv3D(filters*4)(rsdc6)
...

# sigmoid activation
outputs = Conv3D(1, (1, 1, 1), activation='sigmoid')(conv9)

model = Model(inputs=[inputs], outputs=[outputs])
model.summary()
Layer (type)                    Output Shape         Param #     Connected to                     
==================================================================================================
input_29 (InputLayer)           (None, 16, 16, 16, 1 0                                            
__________________________________________________________________________________________________
conv3d_111 (Conv3D)             (None, 16, 16, 16, 3 10400       input_29[0][0]                   
__________________________________________________________________________________________________
...

模型子类如下:

class UNet3D(Model):
    def __init__(self, **kwargs):
        super(UNet3D, self).__init__(name="UNet3D", **kwargs)        
        self.filters = 32

    def __call__(self, inputs):

        # L-hand side of UNet
        conv1 = DoubleConv3D(self.filters*1)(inputs)
        pool1 = MaxPooling3D()(conv1)
        ...

        # middle bottleneck
        conv5 = DoubleConv3D(self.filters*5)(pool4)

        # R-hand side of UNet
        rsdc6 = ConcatConv3D(self.filters*4)(conv5, conv4)
        conv6 = DoubleConv3D(self.filters*4)(rsdc6)
        ...

        # sigmoid activation
        outputs = Conv3D(1, (1, 1, 1), activation='sigmoid')(conv9)
        return outputs

unet3d = UNet3D()
unet3d.build(Input(shape=[None, None, None, 1]))
unet3d.summary()

但是,摘要不输出参数的层和数量,而是给出

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
Total params: 0
Trainable params: 0
Non-trainable params: 0
_________________________________________________________________

起初,我认为这是一个错误,没有在调用摘要之前调用build,并试图在第一个卷积层之前显式调用该函数并添加一个InputLayer,如本{ {3}}。但是,这两种解决方案都无法将汇总生成固定在模型子类上。

1 个答案:

答案 0 :(得分:0)

通过查看以下example,我找到了解决此模型子分类问题的方法。应该归功于该回购协议的作者。

创建将Keras Functional转换为Model子类的一种方法是创建并调用一个复制模型初始化的函数,例如Model(inputs=[inputs], outputs=[outputs])。在这里,我们使用_build函数。

class UNet3D(Model):
    def __init__(self, **kwargs):

        # Initialize model parameters.
        self.filters = 32
        ...

        # Initialize model.
        self._build(**kwargs)

    def __call__(self, inputs):

        # L-hand side of UNet
        conv1 = DoubleConv3D(self.filters*1)(inputs)
        pool1 = MaxPooling3D()(conv1)
        ...

        # middle bottleneck
        conv5 = DoubleConv3D(self.filters*5)(pool4)

        # R-hand side of UNet
        rsdc6 = ConcatConv3D(self.filters*4)(conv5, conv4)
        conv6 = DoubleConv3D(self.filters*4)(rsdc6)
        ...

        # sigmoid activation
        outputs = Conv3D(1, (1, 1, 1), activation='sigmoid')(conv9)
        return outputs

    def _build(self, **kwargs):
        """
        Replicates Model(inputs=[inputs], outputs=[outputs]) of functional model.
        """
        # Replace with shape=[None, None, None, 1] if input_shape is unknown.
        inputs  = Input(shape=[16, 16, 16, 12])
        outputs = self.__call__(inputs)
        super(UNet3D, self).__init__(name="UNet3D", inputs=inputs, outputs=outputs, **kwargs) 

unet3d = UNet3D()
unet3d.summary()