Как использовать собственные метрики проверки в TensorFlow 2

Keras предлагает набор показателей для проверки набора тестовых данных, таких как точность, MSE или AUC. Однако иногда для проверки вашей модели требуется настраиваемая метрика. В этом посте я покажу три разных подхода к реализации ваших метрик и их использованию в Keras.

Если вначале в Keras было всего несколько показателей, сегодня доступно множество других. Для версии Keras в комплекте с TensorFlow 2 все показатели можно найти в tf.keras.metrics.

Использование дополнений tensorflow

Библиотека Tensoflow Addons предоставляет некоторые дополнительные метрики. Перед тем, как приступить к реализации самостоятельно, лучше проверьте, доступна ли там ваша метрика. Чтобы использовать аддоны тензорного потока, просто установите его через pip:

pip install tensorflow-addons

Если вы не нашли там свои показатели, теперь мы можем рассмотреть три варианта. Объекты функций, обратных вызовов и показателей.

Простые функции метрик

Самый простой способ определения показателей в Keras - просто использовать обратный вызов функции. Функция принимает два аргумента. Первый параметр - это истинное значение (y_true), а второй - прогноз модели (y_pred). Во время проверки эти аргументы являются тензорами, поэтому для расчетов мы должны использовать бэкэнд Keras.

import tf.keras.backend as K
def matthews_correlation(y_true, y_pred):
    y_pred_pos = K.round(K.clip(y_pred, 0, 1))
    y_pred_neg = 1 - y_pred_pos

    y_pos = K.round(K.clip(y_true, 0, 1))
    y_neg = 1 - y_pos

    tp = K.sum(y_pos * y_pred_pos)
    tn = K.sum(y_neg * y_pred_neg)

    fp = K.sum(y_neg * y_pred_pos)
    fn = K.sum(y_pos * y_pred_neg)

    numerator = (tp * tn - fp * fn)
    denominator = K.sqrt((tp + fp) * (tp + fn) * (tn + fp) * (tn + fn))

    return numerator / (denominator + K.epsilon())

Использование этой функции с моделями Keras:

model.compile(optimizer='rmsprop',
              loss='binary_crossentropy',
              metrics=[matthews_correlation])

И вызов fit () теперь выводит:

245063/245063 [==============================] - 63s 256us/step - matthews_correlation: 0.0032 - val_matthews_correlation: 0.0039
(Note that the name is the function name, while for validation data there is always the val_ prefix)

Оценка интервала с использованием обратных вызовов

Если вы хотите оценивать модель на отдельном наборе данных каждые N эпох, вы можете использовать настраиваемый обратный вызов. В этом случае используется оценка AUC из scikit-learn.

from sklearn.metrics import roc_auc_score
from tf.keras.callbacks import Callback

class IntervalEvaluation(Callback):
    def __init__(self, validation_data=(), interval=10):
        super(Callback, self).__init__()

        self.interval = interval
        self.X_val, self.y_val = validation_data

    def on_epoch_end(self, epoch, logs={}):
        if epoch % self.interval == 0:
            y_pred = self.model.predict_proba(self.X_val, verbose=0)
            score = roc_auc_score(self.y_val, y_pred)
            print("interval evaluation - epoch: {:d} - score: {:.6f}".format(epoch, score))

Чтобы обучить модель этой настройке оценки, экземпляр объекта передается в Keras в качестве обратного вызова.

ival = IntervalEvaluation(validation_data=(x_validate, y_validate), interval=10)
model.fit(x_train, y_train,
          batch_size=8196,
          epochs=25,
          validation_data=[x_test, y_test],   
          class_weight=class_weight,
          callbacks=[ival],
          verbose=1 )

И результат выглядит так:

interval evaluation - epoch: 0 - score: 0.545038
interval evaluation - epoch: 10 - score: 0.724098
interval evaluation - epoch: 20 - score: 0.731381

Расширить tf.keras.metrics.Metric

И, наконец, можно расширить сам объект метрики. (Кредиты на Geeocode из Stackoverflow)

class CategoricalTruePositives(tf.keras.metrics.Metric):
    def __init__(self, num_classes, batch_size,
                 name="categorical_true_positives", **kwargs):
        super(CategoricalTruePositives, self).__init__(name=name, **kwargs)
        self.batch_size = batch_size
        self.num_classes = num_classes    
        self.cat_true_positives = self.add_weight(name="ctp", initializer="zeros")
    def update_state(self, y_true, y_pred, sample_weight=None):     
        y_true = K.argmax(y_true, axis=-1)
        y_pred = K.argmax(y_pred, axis=-1)
        y_true = K.flatten(y_true)
        true_poss = K.sum(K.cast((K.equal(y_true, y_pred)), dtype=tf.float32))
        self.cat_true_positives.assign_add(true_poss)
    def result(self):
        return self.cat_true_positives

Есть только одно заметное отличие от первого примера. Функция результата возвращается, и метод update_state должен быть переопределен (это место, где происходит вычисление). Он также принимает один дополнительный аргумент (sample_weight). И, наконец, тензор результата возвращается методом re result.

model.compile(optimizer='adam',
              loss='binary_crossentropy',
              metrics=[CategoricalTruePositives(num_classes, batch_size)])

Мы видели три разных способа реализации настраиваемой метрики проверки. Надеюсь, это помогло решить, какой способ подходит для вашего варианта использования, и не забудьте проверить, доступна ли уже ваша метрика в большом количестве предопределенных в tf.keras.metrics.

Этот пост был первоначально опубликован на digital-thinking.de (19 декабря 2018 г.)