Значения метрик равны при обучении и тестировании модели.

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

Я работаю над моделью нейронной сети с использованием Python, Keras и TensorFlow в качестве бэкенда. Набор данных содержит две последовательности с результатом, который может быть 1 или 0, и соотношение положительных и отрицательных примеров в датасете составляет 1 к 9. Модель получает две последовательности на входе и выдает вероятность. Сначала у моей модели был слой Dense с одним скрытым узлом и сигмоидной активацией на выходе, но затем я изменил последний слой модели на Dense с двумя скрытыми узлами и функцией активации softmax и изменил результат набора данных с помощью функции Keras to_categorical. После этих изменений метрики модели, которые содержат Accuracy, Precision, Recall, F1 и AUC, все равны и имеют высокое и неправильное значение. Вот реализация, которую я использовал для этих метрик

def recall(y_true, y_pred):
    true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))
    possible_positives = K.sum(K.round(K.clip(y_true, 0, 1)))
    recall = true_positives / (possible_positives + K.epsilon())
    return recall

def precision(y_true, y_pred):
    true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))
    predicted_positives = K.sum(K.round(K.clip(y_pred, 0, 1)))
    precision = true_positives / (predicted_positives + K.epsilon())
    return precision

def f1(y_true, y_pred):
    precisionValue = precision(y_true, y_pred)
    recallValue = recall(y_true, y_pred)
    return 2*((precisionValue*recallValue)/(precisionValue+recallValue+K.epsilon()))

def auc(y_true, y_pred):
    auc = tf.metrics.auc(y_true, y_pred)[1]
    K.get_session().run(tf.local_variables_initializer())
    return auc

а вот результаты обучения

Epoch 1/5
4026/4026 [==============================] - 17s 4ms/step - loss: 1.4511 - acc: 0.9044 - f1: 0.9044 - auc: 0.8999 - precision: 0.9044 - recall: 0.9044
Epoch 2/5
4026/4026 [==============================] - 15s 4ms/step - loss: 1.4573 - acc: 0.9091 - f1: 0.9091 - auc: 0.9087 - precision: 0.9091 - recall: 0.9091
Epoch 3/5
4026/4026 [==============================] - 15s 4ms/step - loss: 1.4573 - acc: 0.9091 - f1: 0.9091 - auc: 0.9083 - precision: 0.9091 - recall: 0.9091
Epoch 4/5
4026/4026 [==============================] - 15s 4ms/step - loss: 1.4573 - acc: 0.9091 - f1: 0.9091 - auc: 0.9090 - precision: 0.9091 - recall: 0.9091
Epoch 5/5
4026/4026 [==============================] - 15s 4ms/step - loss: 1.4573 - acc: 0.9091 - f1: 0.9091 - auc: 0.9085 - precision: 0.9091 - recall: 0.9091

после этого я протестировал свою модель с помощью predict и вычислил метрики с помощью функции precision_recall_fscore_support из sklearn, и я снова получил такой же результат. метрики все равны и имеют высокое значение (0.93), что неверно на основе матрицы неточностей, которую я сгенерировал
введите описание изображения здесь

Что я делаю не так?

Это может происходить по разным причинам:

  • Ваша модель обучается слишком быстро (менее одной эпохи). В этом случае вам нужно увеличить объем набора данных (добавив некоторые данные или аугментации)
  • Ваша функция потерь не работает корректно и возвращает нулевые градиенты при каждом вызове
  • Ваша обучающая модель находится не в режиме обучения
  • Ваши данные загружаются некорректно. Проверьте, какие данные подаются на вход вашей модели

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

Вы можете узнать, как рассчитывать веса классов или вес образцов из этого ответа.

И как вы должны использовать (это фрагменты из моего кода) в Keras:

nn.fit(x_train, y_train, callbacks = [es], epochs=8000, batch_size=64,
       shuffle=True, validation_data=(x_dev, y_dev), 
       sample_weight = sample_weights)

если вы хотите использовать sample_weights. И аналогично,

nn.fit(x_train, y_train, callbacks = [es], epochs=8000, batch_size=64, 
       shuffle=True, validation_data=(x_dev, y_dev),
       class_weight=class_weight)

если вы хотите использовать веса классов. Однако разницы не будет, просто не используйте оба варианта.

Удачи!

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

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

1. Дисбаланс классов

Ваш набор данных имеет очень большой дисбаланс классов (соотношение 1:9), что может вызвать серьезные проблемы с обучением модели. Нейронная сеть может «научиться» игнорировать миноритарный класс (позитивный), просто предсказывая мажоритарный класс (негативный) для всех входных данных. Это приводит к высокой «фальшивой» точности, так как большинство данных поделено по доминирующему классу. Чтобы решить эту проблему, рассмотрите возможность использования весов классов (class weights) или весов выборки (sample weights) при обучении.

Пример кода для указания весов классов:

from sklearn.utils import class_weight
import numpy as np

class_weights = class_weight.compute_class_weight('balanced', 
                                                  np.unique(y_train), 
                                                  y_train)

model.fit(x_train, y_train, class_weight=class_weights, ...)

В Keras можно применять как class_weight, так и sample_weights, но не оба одновременно.

2. Неисправная функция потерь

Проверьте, правильно ли определена ваша функция потерь. Если функция потерь не вычисляет градиенты, модель не сможет учиться. Используйте стандартную функцию потерь для бинарной классификации — binary_crossentropy для бинарных задач, или categorical_crossentropy для многоклассовых проблем.

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

3. Правильная настройка модели

Убедитесь, что ваша модель настроена правильно. Ваша последняя архитектура с двумя выходными нейронами и функцией активации softmax предполагает, что ваш набор данных должен быть в формате категориальных переменных. Убедитесь, что вы правильно преобразовали ваши целевые метки в формат one-hot с помощью to_categorical.

4. Проверка входных данных

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

5. Обучение модели

Как уже было упомянуто в ваших наблюдениях, возможно, модель обучается слишком быстро. Убедитесь, что модель имеет достаточное количество эпох для обучения и что используется механизм остановки по раннему окончанию (early stopping), чтобы предотвратить переобучение.

Заключение

Каждый из этих факторов может значительно повлиять на результаты вашей модели. Работая с дисбалансом классов, убедитесь, что вы корректно применяете веса, проверяете входные данные и оптимизируете вашу архитектуру. Используйте инструменты визуализации, такие как матрицы путаницы, чтобы получить более точное представление о том, как модель работает. Успехов в дальнейшей разработке вашей модели!

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

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