我正在尝试使用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}}。但是,这两种解决方案都无法将汇总生成固定在模型子类上。
答案 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()