Пользовательские метрики Keras возвращает NAN - PullRequest
0 голосов
/ 01 сентября 2018

Я хочу дополнительно разбить выходные классы на меньшее количество сегментов в задаче классификации. У меня есть 4 выходных класса (то есть 0, 1, 2, 3). Но во время тренировок я также хочу отслеживать точность для 2 классов:

  • относиться к 0 & 1 как к классу 0
  • относиться к 2 и 3 как к классу 1

Для этого я создал новую метрику и скомпилировал ее с моделью:

def new_classes_acc(y_true, y_pred):
  actual = tf.floor( y_true / 2 )
  predicted = tf.floor( y_pred / 2 )
  return K.categorical_crossentropy(actual, predicted)

Скомпилировал это так:

model.compile(loss='categorical_crossentropy', optimizer=optimizer, metrics=['accuracy', new_classes_acc])

Я получаю nan в качестве значения точности. Как правильно это сделать?

1 Ответ

0 голосов
/ 01 сентября 2018

Поскольку существует 4 класса, и вы установили categorical_crossentropy в качестве потерь, то метки закодированы как горячие и будут иметь форму (n_samples, 4). Поэтому сначала вам нужно найти истинные и предсказанные классы, используя функцию argmax, а затем использовать функцию floor (далее вы хотите создать метрику, а не функцию потерь; поэтому вам не следует использовать K.categorical_crossentropy):

from keras import backend as K
import tensorflow as tf

def custom_metric(y_true, y_pred):
    tr = tf.floor(K.argmax(y_true, axis=-1) / 2)
    pr = tf.floor(K.argmax(y_pred, axis=-1) / 2)
    return K.cast(K.equal(tr, pr), K.floatx())

Теперь давайте проверим это. Сначала мы создаем простую модель и компилируем ее:

model = Sequential()
model.add(Dense(4, activation='softmax', input_shape=(2,)))

model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy', custom_metric])

Затем мы создаем фиктивные данные:

import numpy as np
data = np.array([1, 2]).reshape(1, 2)

и использовать нашу модель для прогнозирования меток для данных:

print(model.predict(data))
# prints: [0.04662106, 0.8046941 , 0.07660434, 0.0720804 ] 

Таким образом, второй класс имеет наибольшую вероятность и будет предсказанной меткой. Теперь, рассматривая пользовательскую метрику, которую мы определили, учитывая либо [1, 0, 0, 0], либо [0, 1, 0, 0] как истинные метки, пользовательская метрика должна дать нам 1 (то есть 100%). Давайте подтвердим это:

true_labels = np.array([1, 0, 0, 0]).reshape(1,4)
print(model.evaluate(data, true_labels))    # gives: [3.0657029151916504, 0.0, 1.0]  

Первый элемент возвращаемого списка соответствует потерям, второй - accuracy, а третий - нашей пользовательской метрике. Как видите, точность равна нулю (поскольку истинный класс - это класс один, а прогнозируемый класс - класс два), а пользовательский показатель равен 1, как и ожидалось.

И другой случай:

true_labels = np.array([0, 1, 0, 0]).reshape(1,4)
print(model.evaluate(data, true_labels))    # gives: [0.21729297935962677, 1.0, 1.0]

Здесь точность равна единице (поскольку истинные и прогнозируемые классы являются классом два), а пользовательская метрика также равна единице. Далее вы можете подтвердить это для оставшихся двух случаев [0, 0, 1, 0] и [0, 0, 0, 1] как истинных меток; оба должны возвращать ноль для значения пользовательской метрики.


Бонус: что делать, если метки редкие, то есть 0, 1, 2 и 3? Затем вы можете использовать метод keras.np_utils.to_categorical() для быстрого их кодирования, а затем использовать пользовательскую метрику, определенную выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...