自定义 keras 真阳性指标是否应始终 return 整数?

Should a custom keras true positive metric always return an integer?

我正在使用非标准数据集,其中我的 y_true 是(批次 x 5 x 1),y_pred 是(批次 x 5 x 1)。如果 y_true[i] > 0. 的任何值,则批处理样本 i 为“真”,如果 y_pred[i] >= b 其中 b 是介于 0 和 1 之间的阈值,则预测为“真”。

我已经定义了这个自定义 keras 指标来计算一批中的真阳性数:

def TP(threshold=0.0):

    def TP_(Y_true, Y_pred):

        Y_true = tf.where(Y_true > 0., tf.ones(tf.shape(Y_true)), tf.zeros(tf.shape(Y_true)))
        Y_pred_true = tf.where(Y_pred >= threshold, tf.ones(tf.shape(Y_pred)), tf.zeros(tf.shape(Y_pred)))

        Y_true = K.sum(Y_true, axis=1)
        Y_pred_true = K.sum(Y_pred_true, axis=1)

        Y_true = tf.where(Y_true > 0., tf.ones(tf.shape(Y_true)), tf.zeros(tf.shape(Y_true)))
        Y_pred_true = tf.where(Y_pred_true > 0., tf.ones(tf.shape(Y_pred_true)), tf.zeros(tf.shape(Y_pred_true)))

        Y = tf.math.add(Y_true, Y_pred_true)
        tp = tf.where(Y == 2, tf.ones(tf.shape(Y)), tf.zeros(tf.shape(Y)))
        tp = K.sum(tp)

        return tp

    return TP_

训练时,我有时会得到非整数值。这是因为 keras 正在对所有批次的值取平均值吗?

我对真阴性、假阳性和假阴性有类似的自定义指标。训练期间所有这四个值的总和应该是整数吗?

两部分回答:是的,指标是批次的平均值。您将看到与内置指标相同的行为,例如 tensorflow.keras.metrics.TruePositive,但在每个纪元结束时它将是一个整数。

但是,您没有为您的指标保留状态,因此 TensorFlow 只是采用您返回的指标的平均值。考虑像这样子类化 tf.keras.metrics.Metric

class TP(tf.keras.metrics.Metric):
    
    def __init__(self, threshold=0.5, **kwargs):
        super().__init__(**kwargs)

        self.threshold = threshold
        self.true_positives = self.add_weight(name='true_positives', initializer='zeros',
                                              dtype=tf.int32)

    def update_state(self, y_true, y_pred, sample_weight=None):

        y_true = tf.where(y_true > self.threshold,
                          tf.ones(tf.shape(y_true)),
                          tf.zeros(tf.shape(y_true)))
        y_pred_true = tf.where(y_pred >= self.threshold,
                               tf.ones(tf.shape(y_pred)),
                               tf.zeros(tf.shape(y_pred)))

        y_true = K.sum(y_true, axis=1)
        y_pred_true = K.sum(y_pred_true, axis=1)

        y_true = tf.where(y_true > self.threshold, tf.ones(tf.shape(y_true)),
                          tf.zeros(tf.shape(y_true)))
        y_pred_true = tf.where(y_pred_true > self.threshold,
                               tf.ones(tf.shape(y_pred_true)),
                               tf.zeros(tf.shape(y_pred_true)))

        Y = tf.math.add(y_true, y_pred_true)
        tp = tf.where(Y == 2, tf.ones(tf.shape(Y), dtype=tf.int32),
                      tf.zeros(tf.shape(Y), dtype=tf.int32))
        tp = K.sum(tp)
        self.true_positives.assign_add(tp)

    def result(self):
        return self.true_positives

    def get_config(self):
        return {'threshold': self.threshold}