У меня есть сценарий классификации с более чем 10 классами, где один класс является выделенным «мусорным» классом. С CNN я в настоящее время достигаю точности около 96%, что для меня достаточно.
В этом конкретном приложении ложные срабатывания (распознающие «мусор» как любой не-мусорный класс) намного хуже, чем путаница между не-мусорными классами или ложными отрицаниями (распознавание любого не-мусорного класса вместо «мусора»). Чтобы уменьшить эти ложные срабатывания, я ищу подходящую функцию потерь.
Моей первой идеей было использование категорической кроссентропии и добавление значения штрафа при обнаружении ложного срабатывания: (псевдокод)
loss = categorical_crossentropy(y_true, y_pred) + weight * penalty
penalty = 1 if (y_true == "garbage" and y_pred != "garbage") else 0
Моя реализация Keras:
def penalized_cross_entropy(y_true, y_pred, garbage_id=0, weight=1.0):
ref_is_garbage = K.equal(K.argmax(y_true), garbage_id)
hyp_not_garbage = K.not_equal(K.argmax(y_pred), garbage_id)
penalty_ind = K.all(K.stack([ref_is_garbage, hyp_not_garbage], axis=0), axis=0) # logical and
penalty = K.cast(penalty_ind, dtype='float32')
return K.categorical_crossentropy(y_true, y_pred) + weight * penalty
Я пробовал разные значения для weight
, но мне не удалось уменьшить количество ложных срабатываний. Для малых значений штраф не имеет никакого эффекта (как и ожидалось), а для очень больших значений (например, weight = 50
) сеть распознает только один класс.
Является ли мой подход полной чепухой или это теоретически сработает? (Я впервые работаю с нестандартной функцией потерь).
Существуют ли другие / лучшие способы наказания за такие ложноположительные ошибки? К сожалению, большинство статей посвящено бинарной классификации, и я не смог найти много для случая мультикласса.
Edit:
Как указано в комментариях, вышеуказанное наказание не дифференцируемо и, следовательно, не влияет на повышение квалификации. Это была моя следующая попытка:
penalized_cross_entropy(y_true, y_pred, garbage_id=0, weight=1.0):
ngs = (1 - y_pred[:, garbage_id]) # non garbage score (sum of scores of all non-garbage classes)
penalty = y_true[:, garbage_id] * ngs / (1.-ngs)
return K.categorical_crossentropy(y_true, y_pred) + weight * penalty
Здесь комбинированные оценки всех классов без мусора добавляются для всех выборок мини-пакета, которые являются ложноположительными. Для образцов, которые не являются ложными срабатываниями, штраф составляет 0.
Я протестировал реализацию на mnist с небольшой сетью с прямой связью и оптимизатором sgd, используя класс "5" в качестве "мусора":
Только с кроссцентропией точность составляет около 0,9343 и
«ложноположительный показатель» (изображения класса «5» распознаются как нечто иное)
0,0093.
При штрафной перекрестной энтропии (вес 3,0) точность равна 0,9378.
и ложноположительный показатель составляет 0,0016
Так что, очевидно, это работает, однако я не уверен, что это лучший подход. Также оптимизатор adam не работает с этой функцией потерь, поэтому мне пришлось использовать sgd.