【问题标题】:keras custom metric function how to feed 2 model outputs to a single metric evaluation functionkeras 自定义度量函数如何将 2 个模型输出提供给单个度量评估函数
【发布时间】:2019-11-06 04:00:16
【问题描述】:

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

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

我在 this link 的帮助下定义的当前度量函数:

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 期间的屏幕日志为:

INFO:tensorflow:loss = 0.0075738616,步长 = 31(11.941 秒)

INFO:tensorflow:global_step/sec: 4.51218

INFO:tensorflow:loss = 0.01015341,步长 = 36(1.108 秒)

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

INFO:tensorflow:调用model_fn。 ==@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=== 张量("IteratorGetNext:1", shape=(?, 120087, 5), dtype=float32, device=/device:CPU:0) 张量("regression/concat:0", shape=(?, ?, 4), dtype=float32) ==@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=== ==@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=== 张量("IteratorGetNext:2", shape=(?, 120087, 2), dtype=float32, device=/device:CPU:0) 张量(“分类/连接:0”,形状=(?,?,1),dtype=float32) ==@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@===

INFO:tensorflow:Done 调用 model_fn。

INFO:tensorflow:2019-06-24T08:20:35Z 开始评估 INFO:tensorflow:Graph 已完成。 2019-06-24 13:50:36.457345:我 tensorflow/core/common_runtime/gpu/gpu_device.cc:1512] 添加可见 gpu 设备:0 2019-06-24 13:50:36.457398:我 tensorflow/core/common_runtime/gpu/gpu_device.cc:984] 设备互连 StreamExecutor 与强度 1 边缘矩阵: 2019-06-24 13:50:36.457419:我 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:我 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)

INFO:tensorflow:从 /tmp/tmpcla2n3gy/model.ckpt-40 恢复参数

INFO:tensorflow:Running local_init_op.

INFO:tensorflow:Done running local_init_op。

INFO:tensorflow:Evaluation [10/100]

INFO:tensorflow:Evaluation [20/100]

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

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

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

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

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

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

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

INFO:tensorflow:Evaluation [100/100]

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

INFO:tensorflow:为全局步骤 40 保存字典:_focal = 0.0016880237, _smooth_l1 = 0.0, dummyAccuracy = 100.0, global_step = 40, loss = 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() 被调用了两次,第一次用于回归,然后用于分类。 但我希望它被调用一次,将 regressionclassification 一起输入它

【问题讨论】:

  • 关于我的解决方案的任何 cmet 吗?

标签: python-3.x tensorflow keras deep-learning


【解决方案1】:

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

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

您必须创建一个图层来为您计算指标。使用Lambda:

鉴于 regOutclassOut 是您的输出张量,在创建模型时,您将不会创建像 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])], ...)

【讨论】:

  • 酷!!! metricFunc 函数似乎是个好主意,我可以用它来计算所需的索引并过滤 classification。然后将其作为一个名为 metric_layer 的张量返回,它应该使用 dummyMetric 进行编译。会试试这个。
  • 将等待看看是否有人有更好的解决方案。否则会接受这个。
【解决方案2】:

让我向您展示一种实现此目的的优雅方法。

  • 首先,定义一个包装你的指标的外部函数,这样你就可以传递你的回归张量reg_out

    def metric_func(reg_out):
        def metric(y_true, class_out):
            return your_metric(reg_out, class_out, y_true)
        return metric
    
  • 接下来,通过设置生成它的层的参数name,将您的分类张量命名为class_out。例如:

    class_out = Dense(1, name='class_out')(something)
    
  • 最后,设置model.compile的参数metrics如下:

    model.compile(...,
                  metrics={'class_out': metric_func(reg_out)})
    

【讨论】:

  • 这听起来很酷 :) - 除非 y_true 两个值对指标都是必需的,否则它似乎会起作用。
  • 没错。我从 OP 了解到,计算指标只需要分类标签
  • @rvinas, classification 度量计算需要标签,但选择有效索引需要regression 结果(例如选择 IoU 大于框的索引)
【解决方案3】:

如果您需要指标的两个 y_true 值。

在这种情况下,我们需要展平我们的数据,以便将其连接到一个数组中。 这将需要固定大小的输出。

假设您有 regOutclassOut 作为张量。如果它们是二维的,只需将它们连接起来,否则:

regOut = Flatten()(regOut) #only if regOut is 3D or more
classOut = Flatten()(classOut) #only if classOut is 3D or more

out = Concatenate()([regOut,classOut])

用这个单一的输出制作模型:

model = Model(inputs, out)

对您的数据集执行相同的操作:

y_reg_train = y_reg_train.reshape((y_reg_train.shape[0], -1))
y_class_train = y_clas_trains.reshape((y_class_train.shape[0], -1))
y_train = np.concatenate([y_reg_train, y_class_train], axis=-1)

#same for y_val

然后创建一个将两者分开的指标:

def metric(y_true, y_pred):

    reg_true = y_true[:,:flattened_size_of_reg]
    class_true = y_true[:, flattened_size_of_reg:]
    
    reg_pred = y_pred[:,:flattened_size_of_reg]
    class_pred = y_pred[:, flattened_size_of_reg:]

    #calculate the metric

    return value

使用组合输出进行训练:

model.fit(x_train, y_train, ...)

【讨论】:

  • 太棒了!!连接完全可以,我只需要编写一个损失函数,将 regressionclassification 头分开并将它们提供给各自的损失
猜你喜欢
  • 2018-06-07
  • 1970-01-01
  • 2019-06-17
  • 1970-01-01
相关资源
最近更新 更多