首页 > 解决方案 > 使用多输入输出 Tensorflow 模型子类验证/测试更差的指标

问题描述

我已经被这个错误困扰了一段时间了。我有一个中等大小的 Tensorflow 模型,有 4 个输入和 2 个输出。我的意图是对其进行细微的结构更改并比较指标。为了保存旧的模型定义并尽可能多地重用代码,我选择采用模型子类化路径,直接扩展模型类。这样我就可以继承和重用图层。我通过模型传递数据,该模型tf.data.Dataset是用于输入输出的字典元组,例如{'input_1': <INPUT_1_TENSOR>, 'input_2', ...}, {'output_1': <OUTPUT_1_TENSOR>, 'output_2'}.

但是,当我执行模型子类化方法时,会弹出一个非常奇怪的错误(错误?)。简而言之,即使看起来训练正在发挥作用(我可以看到训练指标上升),验证指标在每个 epoch 之后都会变得越来越差。当我删除 Model 子类并直接定义 Model 时,不会发生这种情况。我认为两者之间的一切都是平等的(优化器、损失、指标、没有回调)。我的模型类如下所示。

class MyModel(Model):
    def __init__(self, **kwargs):
        super(MyModel, self).__init__(**kwargs)
       
        # Input layers
        self.input_1 = Input(shape=(6), dtype=tf.uint32, name='input_1')
        self.input_2 = Input(shape=(6), dtype=tf.uint32, name='input_2')
        self.input_3 = Input(shape=(1,), dtype=tf.uint32, name='input_3')
        self.input_4 = Input(shape=(1,), dtype=tf.uint32, name='input_4')

        # Define rest of layers (no custom layers here)
        # ....
        # ....
        # ....
        

    def call(self, inputs, training=True, mask=None):
        # WE ASSUME THAT THE INPUTS ARE PASSED IN AS DICTIONARIES WITH THE KEYS:
        # [input_1, input_2, input_3, input_4]
        input_1, input_2, input_3, input_4 = inputs['input_1'], inputs['input_2'], \
                                                             inputs['input_3'], inputs['input_4']
        
        # Pass through all the layers define in __init__() and grab the two outputs.
        # ....
        # ....
        # ....

        return {'output_1': output_1, 'output_2': output_2}

    def build(self, input_shapes=None):
        """
        I had to define this because it wouldn't let me do .summary() before .fit().
        """
        input_list = {'input_1': self.input_1,
                      'input_2': self.input_2,
                      'input_3': self.input_3,
                      'input_4': self.input_4}
        return Model(inputs=input_list, outputs=self.call(input_list))

然后真正适合,我做

model = MyModel(...)
model.build().summary()
optimizer = Adam(learning_rate=0.01)
model.compile(optimizer=optimizer, loss='sparse_categorical_crossentropy', loss_weights=[1., 1.],
                           metrics=['accuracy'])
model.fit(train_dataset,
          epochs=3,
          verbose=1,
          validation_data=vali_dataset)

正如我之前所说,如果我将这些东西call()移出课堂并以这种方式创建模型对象,那么训练就会正常进行,并且验证指标会按预期发生变化。

我还可以删除 Model 子类并定义一个常规类calL(),用它替换build_model()返回 Model 对象而不是输出字典。这也运行良好。它可以称为解决方案,但认为它不应该是必要的,并且违背了能够扩展 Model 类的目的。唯一的问题是模型子类。

除了这个Stack Overflow 问题之外,我也找不到任何关于使用具有多个输入和输出的模型子类化的综合文档。

所以总结一下:

关于错误可能在哪里或从哪里开始的任何想法?

谢谢!

标签: python-3.xtensorflowmachine-learningdeep-learningtensorflow2.0

解决方案


推荐阅读