首页 > 解决方案 > 保存子类 keras/Tensorflow 模型时的输入兼容性问题,但转换为 tensorflow lite 然后保存工作

问题描述

我有一个用 Keras/Tensorflow 构建的子类网络。在训练期间,如果 val loss 小于以前,我希望保存模型。培训按预期进行。但是,在保存模型时,它会引发错误。

in assert_input_compatibility
raise ValueError('Input ' + str(input_index) + ' of layer ' +

ValueError:conv2d_11 层的输入 0 与层不兼容::预期 min_ndim=4,发现 ndim=3。收到的完整形状:[64、64、64]

期望 4 个维度是正确的。毕竟,那是网络的输入。据推测,它删除了批次维度。

class BasicBlock(tf.keras.Model):
def __init__(self, ncIn, ncOut, batchNorm_type=0, strides=(1,1), downSample=None, dynamic=True):
    super(BasicBlock, self).__init__(dynamic=True)
    self.ncIn = ncIn
    self.ncOut = ncOut
    self.conv_1 = Conv2D(ncOut, kernel_size=(3,3), strides=(1,1), padding="same", use_bias=False)
    self.conv_2 = Conv2D(ncOut, kernel_size=(3,3), strides=(1,1), padding="same", use_bias=False) 
    self.shortcuts = Conv2D(ncOut, kernel_size=(1,1), strides=(1,1), use_bias=False) 
    if batchNorm_type == 0:
        self.bn = BatchNormalization()
    else:
        self.bn = tfa.layers.InstanceNormalization()
@tf.function
def test(self, ncIn, ncOut, out, out_shortcut, x):
    if ncIn != ncOut:
        out += out_shortcut
    else:
        out += x
    return out
def call(self, inputs):
        x = inputs[0]
        #print(x.shape)
        out = self.conv_1(x)
        out = self.bn(out)
        out = Activation('relu')(out) 
        out = self.conv_2(out)
        out = self.bn(out)
        
        out_shortcut = self.shortcuts(x)
        #out = test(self.ncIn, self.ncOut, out, out_shortcut, x)
        #print(f'{out_shortcut.shape} : {out.shape}, {x.shape}')
        
        #out = tf.cond(tf.constant(self.ncOut != self.ncIn, dtype=tf.bool), lambda: tf.add(out, out_shortcut), lambda: tf.add(out, x))
        #X
        out = self.test(self.ncIn, self.ncOut, out, out_shortcut, x)
        #if self.ncIn != self.ncOut:
        #    out += self.shortcuts(x)
        #else: 
        #    out += x
        out = Activation('relu')(out)
        return out

这是子类模型,self.conv_1(x) 是收到错误的地方。不过,这是更大网络的一部分。

(1, 512, 512, 16)
(1, 256, 256, 16)
(1, 256, 256, 16)
(1, 128, 128, 16)
(1, 128, 128, 32)
(1, 64, 64, 32)
(1, 64, 64, 64)
(1, 32, 32, 64)
(1, 32, 32, 155)
(1, 64, 64, 64)
(1, 128, 128, 32)
(1, 256, 256, 16)

这些是 print 语句中 model.build() 期间输入 x 的可能形状。它下降然后上升的原因是因为它是沙漏架构的一部分。

就好像它删除了批次维度(因此为 64、64、64)。奇怪的是,这在训练期间不会发生,而且它似乎成功地为之前的输入断言了形状。

我为什么要保存?- 因为这允许我将其转换为 tensorflow lite。

经过大量的形状调试打印后,我有了另一个线索。保存过程会运行一些检查。它似乎做的第一件事就是向网络传递一些东西,该网络的批处理维度为 (None, , , )。这将成功完成并退出网络。在此之后,它检查从一层到下一层的输入,看它们是否兼容。那就是它失败的地方。就好像当它做那个检查时,它完全消除了批量维度的想法。这可能是一个错误吗?

此外,由于最终目标是将 keras 模型转换为可以在 c++ 中导入和推断的 tensorflow lite 模型,并且直接从 keras 保存模型不起作用。我尝试先将模型转换为 tf.lite 然后保存,这很有效*。为什么这行得通,而反之则不行?

*它有效,但它会引发两个警告,我不确定如何解释,或者它们是否确实会在以后引起问题

2021-03-17 08:39:34.011889: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:316] Ignored output_format.

2021-03-17 08:39:34.012001: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:319] Ignored drop_control_dependency.    

我正在使用 TensorFlow 2.4

标签: pythontensorflowkeras

解决方案


推荐阅读