首页 > 解决方案 > keras 自定义度量函数如何将 2 个模型输出提供给单个度量评估函数

问题描述

我有一个 CNN 对象检测模型,它有两个头(输出),张量名称'classification''regression'.

我想定义一个同时接受两个输出的度量函数,以便它查看回归预测以决定保留哪些索引并使用这些索引从分类预测中选择张量并计算一些度量。

我当前在此链接的帮助下定义的度量函数:

from tensorflow.python.keras.metrics import MeanMetricWrapper

class Accuracy2(MeanMetricWrapper):

    def __init__(self, name='dummyAccuracy', dtype=None):
        super(Accuracy2, self).__init__(metric_calculator_func, name, dtype=dtype)
        self.true_positives = self.add_weight(name='lol', initializer='zeros')

    @classmethod
    def from_config(cls, config):
        if 'fn' in config:
          config.pop('fn')
        return super(Accuracy2, cls).from_config(config)


    def update_state(self, y_true, y_pred, sample_weight=None):
      print("==@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@===")
      print("Y-True {}".format(y_true))
      print("Y-Pred {}".format(y_pred))
      print("==@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@===")

      update_ops = [self.true_positives.assign_add(1.0)]
      return tf.group(update_ops)

    def result(self):
      return self.true_positives

    def reset_states(self):
      # The state of the metric will be reset at the start of each epoch.
      self.true_positives.assign(0.)

我将模型编译期间称为:

training_model.compile(
    loss={
        'regression'    : regression_loss(),
        'classification': classification_loss()
    },
    optimizer=keras.optimizers.Adam(lr=lr, clipnorm=0.001),
    metrics=[Accuracy2()]
)

tf.estimator.train_and_evaluate期间的屏幕日志是:

信息:张量流:损失 = 0.0075738616,步长 = 31(11.941 秒)

信息:张量流:global_step/sec:4.51218

信息:张量流:损失 = 0.01015341,步长 = 36(1.108 秒)

INFO:tensorflow:将 40 的检查点保存到 /tmp/tmpcla2n3gy/model.ckpt。

信息:张量流:调用 model_fn。==@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=== Tensor("IteratorGetNext:1 ", shape=(?, 120087, 5), dtype=float32, device=/device:CPU:0) Tensor("regression/concat:0", shape=(?, ?, 4), dtype=float32) = =@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=== ==@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=== Tensor("IteratorGetNext:2", shape=(?, 120087, 2), dtype=float32, device=/device:CPU:0) Tensor("classification/concat:0", shape=(?, ?, 1), dtype=float32) ==@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@===

信息:张量流:完成调用 model_fn。

INFO:tensorflow:于 2019-06-24T08:20:35Z 开始评估 INFO:tensorflow:Graph 已完成。2019-06-24 13:50:36.457345: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1512] 添加可见 gpu 设备:0 2019-06-24 13:50:36.457398: I tensorflow/core/common_runtime/ gpu/gpu_device.cc:984] 具有强度 1 边缘矩阵的设备互连 StreamExecutor:2019-06-24 13:50:36.457419: I tensorflow/core/common_runtime/gpu/gpu_device.cc:990] 0 2019-06-24 13 :50:36.457425: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1003] 0: N 2019-06-24 13:50:36.457539: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1115] 创建TensorFlow 设备(/job:localhost/replica:0/task:0/device:GPU:0,内存为 9855 MB)-> 物理 GPU(设备:0,名称:GeForce RTX 2080 Ti,pci 总线 ID:0000:01: 00.0,计算能力:7.5)

信息:张量流:从 /tmp/tmpcla2n3gy/model.ckpt-40 恢复参数

信息:张量流:运行 local_init_op。

信息:张量流:完成运行 local_init_op。

信息:张量流:评估 [10/100]

信息:张量流:评估 [20/100]

信息:张量流:评估 [30/100]

信息:张量流:评估 [40/100]

信息:张量流:评估 [50/100]

信息:张量流:评估 [60/100]

信息:张量流:评估 [70/100]

信息:张量流:评估 [80/100]

信息:张量流:评估 [90/100]

信息:张量流:评估 [100/100]

INFO:tensorflow:在 2019-06-24-08:20:44 完成评估

信息:张量流:为全局步骤 40 保存字典:_focal = 0.0016880237,_smooth_l1 = 0.0,dummyAccuracy = 100.0,global_step = 40,损失 = 0.0016880237

这一行:

==@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@===
Tensor("IteratorGetNext:1", shape=(?, 120087, 5), dtype=float32, device=/device:CPU:0)
Tensor("regression/concat:0", shape=(?, ?, 4), dtype=float32)
==@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@===
==@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@===
Tensor("IteratorGetNext:2", shape=(?, 120087, 2), dtype=float32, device=/device:CPU:0)
Tensor("classification/concat:0", shape=(?, ?, 1), dtype=float32)
==@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@===

显示Accuracy2()被调用两次,首先用于回归,然后用于分类。但我希望它被调用一次,回归分类一起输入

标签: python-3.xtensorflowkerasdeep-learning

解决方案


如果您不需要y_true该指标中的值

这是一个丑陋的答案,但是....

您必须制作一个图层来为您计算指标。使用Lambda

鉴于regOut和是您的输出张量,在模型创建中,而不是像您classOut这样创建模型:Model(inputs, [regOut,classOut])

def metricFunc(modelOutputs):
    regressionOutput = modelOutputs[0]
    classOutput = modelOuptuts[1]

    #calculate metric
    return calculatedMetric


metricTensor = Lambda(metricFunc, name='metric_layer')([regOut,classOut])

使指标成为模型的输出:

model = Model(inputs, [regOut, classOut, metricTensor])

为编译创建一个虚拟损失和一个虚拟指标:

def dummyLoss(true,pred):
    return K.zeros(K.shape(true)[:1])

def dummyMetric(true,pred):
    return pred

在编译中:

model.compile(loss = [regLoss, classLoss, dummyLoss], 
              metrics={'metric_layer':dummyMetric}, 
              optimizer=...)

这也要求您使用虚拟张量进行训练metricTensor

model.fit(x_train, [y_reg,y_class,np.zeros(y_reg.shape[:1])], ...)

推荐阅读