Keras Custom Metric для точности одного класса

Я создаю собственную метрику для измерения точности одного класса в моем наборе данных мультикласса во время обучения. У меня проблемы с выбором класса.

Цели - одна горячая (например: метка класса 0 [1 0 0 0 0]:

from keras import backend as K

def single_class_accuracy(y_true, y_pred):
    idx = bool(y_true[:, 0])              # boolean mask for class 0 
    class_preds = y_pred[idx]
    class_true = y_true[idx]
    class_acc = K.mean(K.equal(K.argmax(class_true, axis=-1), K.argmax(class_preds, axis=-1)))  # multi-class accuracy  
    return class_acc

Проблема заключается в том, что мы должны использовать функции Keras для индексации тензоров. Как создать булевскую маску для тензора? Спасибо.

Ответ 1

Обратите внимание, что, говоря о точности одного класса, можно обратиться к одному из следующих (не эквивалентных) двух значений:

  • точность, которая для класса C является отношением примеров, помеченных классом C, которые, как прогнозируется, имеют класс C.
  • отзыв, который для класса C представляет собой отношение примеров, которые, как предполагается, относятся к классу C, которые на самом деле помечены классом C.

Вместо выполнения сложной индексации вы можете просто полагаться на маскировку для вас вычислений. Предполагая, что мы говорим о точности здесь (изменение на вызов было бы тривиальным).

from keras import backend as K

INTERESTING_CLASS_ID = 0  # Choose the class of interest

def single_class_accuracy(y_true, y_pred):
    class_id_true = K.argmax(y_true, axis=-1)
    class_id_preds = K.argmax(y_pred, axis=-1)
    # Replace class_id_preds with class_id_true for recall here
    accuracy_mask = K.cast(K.equal(class_id_preds, INTERESTING_CLASS_ID), 'int32')
    class_acc_tensor = K.cast(K.equal(class_id_true, class_id_preds), 'int32') * accuracy_mask
    class_acc = K.sum(class_acc_tensor) / K.maximum(K.sum(accuracy_mask), 1)
    return class_acc

Если вы хотите быть более гибким, вы также можете присвоить класс интереса:

from keras import backend as K

def single_class_accuracy(interesting_class_id):
    def fn(y_true, y_pred):
        class_id_true = K.argmax(y_true, axis=-1)
        class_id_preds = K.argmax(y_pred, axis=-1)
        # Replace class_id_preds with class_id_true for recall here
        accuracy_mask = K.cast(K.equal(class_id_preds, interesting_class_id), 'int32')
        class_acc_tensor = K.cast(K.equal(class_id_true, class_id_preds), 'int32') * accuracy_mask
        class_acc = K.sum(class_acc_tensor) / K.maximum(K.sum(accuracy_mask), 1)
        return class_acc
    return fn

И используйте его как:

model.compile(..., metrics=[single_class_accuracy(INTERESTING_CLASS_ID)])