Оцените метрику по всем пакетам в tensorflow.

Вопрос или проблема

Я написал метрику для tensorflow, которая представляет собой площадь под кривой точности-отзыва слева от порога отзыва=0.3. Реализация выглядит следующим образом (обратите внимание, что меня интересует только нулевое предсказание последнего временного шага в окне):

   def auprc_left_of_recall(y_true, y_pred, recall_threshold=0.3):

    y_true = y_true[:, -1, 0]
    y_pred = y_pred[:, -1, 0]

    recall_threshold = tf.constant(recall_threshold)

    indices = tf.argsort(y_pred, direction='DESCENDING')
    sorted_y_true = tf.gather(y_true, indices)

    cum_true_positives = K.cumsum(sorted_y_true)
    cum_false_positives = K.cumsum(1 - sorted_y_true)
    total_positives = K.sum(sorted_y_true)

    precision = cum_true_positives / (cum_true_positives + cum_false_positives + K.epsilon())
    recall = cum_true_positives / (total_positives + K.epsilon())

    before_mask = recall < recall_threshold
    after_mask = recall >= recall_threshold

    idx_before = tf.reduce_max(tf.where(before_mask))
    idx_after = tf.reduce_min(tf.where(after_mask))

    recall_before = recall[idx_before]
    recall_after = recall[idx_after]
    precision_before = precision[idx_before]
    precision_after = precision[idx_after]

    interpolated_precision = precision_before + (precision_after - precision_before) * (recall_threshold - recall_before) / (recall_after
     - recall_before)

    precision_left = tf.concat([tf.boolean_mask(precision, before_mask), [interpolated_precision]], axis=0)
    recall_left = tf.concat([tf.boolean_mask(recall, before_mask), [recall_threshold]], axis=0)

    precision_left = tf.concat([[1.0], precision_left], axis=0)
    recall_left = tf.concat([[0.0], recall_left], axis=0)

    recall_diff = recall_left[1:] - recall_left[:-1]
    avg_precision = (precision_left[1:] + precision_left[:-1]) / 2
    area = tf.reduce_sum(recall_diff * avg_precision)

    return area

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

Как бы я реализовал метрику, которая оценивает ровно то, что делает метрика выше, но по меткам и предсказаниям всех партий сразу?

.

Ответ или решение

Для оценки метрики, основанной на площади под кривой «Precision-Recall» (PR) на всех партиях данных в TensorFlow, необходимо модифицировать ваш существующий код таким образом, чтобы он учитывал все данные, а не только данные одной партии. Это позволит вам получить адекватное значение вашей метрики при разбиении данных на батчи.

Основные моменты для реализации

  1. Сбор данных за все батчи: Вам нужно будет агрегировать предсказания и истинные значения классов по всем батчам в единую структуру. В TensorFlow это можно сделать, используя функцию tf.TensorArray или другие подходящие конструкции для хранения.

  2. Корректное вычисление метрики: Вместо того чтобы вычислять метрику на уровне каждой партии, следует собрать все предсказания и истинные метки в один массив, а затем применять к ним вашу функцию, сохранив логику вычисления площади под кривой PR.

  3. Применение на этапе обучения или тестирования: Убедитесь, что ваша метрика обновляется после каждой эпохи или в конце тестирования.

Шаги для модификации кода

Вот пример того, как можно реализовать вашу метрику auprc_left_of_recall для работы с предсказаниями и истинными значениями всех батчей:

import tensorflow as tf
from tensorflow.keras import backend as K

class AUPRC(tf.keras.metrics.Metric):

    def __init__(self, name='auprc', recall_threshold=0.3, **kwargs):
        super(AUPRC, self).__init__(name=name, **kwargs)
        self.recall_threshold = recall_threshold
        self.precisions = self.add_weight(name='precisions', initializer='zeros')
        self.recalls = self.add_weight(name='recalls', initializer='zeros')
        self.total_count = self.add_weight(name='total_count', initializer='zeros')

    def update_state(self, y_true, y_pred, sample_weight=None):
        # Сбор всех предсказаний
        y_true = y_true[:, -1, 0]
        y_pred = y_pred[:, -1, 0]

        # выполнение логики из вашей функции
        area = self.compute_auprc(y_true, y_pred, self.recall_threshold)

        # Обновление состояния
        self.precisions.assign_add(area)
        self.total_count.assign_add(1)

    def result(self):
        return self.precisions / self.total_count

    def reset_states(self):
        self.precisions.assign(0)
        self.total_count.assign(0)

    def compute_auprc(self, y_true, y_pred, recall_threshold):
        # Здесь вставьте вашу реализацию вычисления AUPRC
        # ...

        return area  # возвращаем рассчитанную площадь под кривой

# Пример использования при компиляции модели
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=[AUPRC()])

Пояснение к коду

  1. Класс метрики: Определен новый класс AUPRC, который наследуется от tf.keras.metrics.Metric. В данном классе мы храним состояния метрики — сумму значений и количество батчей.

  2. Обновление состояния: Метод update_state агрегирует предсказания и истинные значения для каждой партии и сохраняет их для последующего использования в вычислениях.

  3. Вычисление результата: Метод result возвращает среднее значение площади под кривой PR за все батчи.

  4. Сброс состояния: Метод reset_states сбрасывает значения метрики после завершения одной эпохи или тестирования, чтобы избежать накопления значений с предыдущих эпох.

С помощью этой структуры вы сможете корректно агрегировать оценки по всем батчам и получить точное значение вашей метрики. Это обеспечит более предсказуемые результаты при работе с тестовыми и валидационными данными.

Оцените материал
Добавить комментарий

Капча загружается...