Подтвердить что ты не робот

Keras binary_crossentropy vs categorical_crossentropy performance?

Я пытаюсь обучить Си-Эн-Эн классифицировать текст по темам. Когда я использую двоичную кроссентропию, я получаю точность ~ 80%, а с категориальной кроссентропией - ~ 50%.

Я не понимаю, почему это так. Это проблема мультикласса, не означает ли это, что я должен использовать категорическую перекрестную энтропию и что результаты с двоичной перекрестной энтропией бессмысленны?

model.add(embedding_layer)
model.add(Dropout(0.25))
# convolution layers
model.add(Conv1D(nb_filter=32,
                    filter_length=4,
                    border_mode='valid',
                    activation='relu'))
model.add(MaxPooling1D(pool_length=2))
# dense layers
model.add(Flatten())
model.add(Dense(256))
model.add(Dropout(0.25))
model.add(Activation('relu'))
# output layer
model.add(Dense(len(class_id_index)))
model.add(Activation('softmax'))

Затем я скомпилирую его, используя categorical_crossentropy в качестве функции потерь:

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

или

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

Ответ 1

Причина этого очевидного несоответствия между категориальной и двоичной кросс-энтропией заключается в том, что @xtof54 уже сообщило в своем ответе, а именно:

Точность, вычисленная с помощью метода evaluate Keras, просто неверна при использовании binary_crossentropy с более чем 2 метками

Я хотел бы подробнее остановиться на этом, продемонстрировать реальную проблему, объяснить ее и предложить решение проблемы.

Это поведение не ошибка; основная причина - довольно тонкий и недокументированный вопрос о том, как Keras фактически угадывает, какую точность использовать, в зависимости от выбранной вами функции потерь, когда вы просто включаете metrics=['accuracy'] в компиляцию модели. Другими словами, пока ваш первый вариант компиляции

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

действительно, ваш второй:

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

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

Это почему? Если вы проверите исходный код метрики, Keras определит не одну метрику точности, а несколько разных, среди них binary_accuracy и categorical_accuracy. Что происходит под капотом, так это то, что, поскольку вы выбрали двоичную кросс-энтропию в качестве функции потерь и не указали конкретную метрику точности, Керас (ошибочно...) делает вывод, что вас интересует binary_accuracy, и это то, что она возвращает. - хотя на самом деле вы заинтересованы в categorical_accuracy.

Давайте проверим, что это так, используя пример MNIST CNN в Keras со следующей модификацией:

model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])  # WRONG way

model.fit(x_train, y_train,
          batch_size=batch_size,
          epochs=2,  # only 2 epochs, for demonstration purposes
          verbose=1,
          validation_data=(x_test, y_test))

# Keras reported accuracy:
score = model.evaluate(x_test, y_test, verbose=0) 
score[1]
# 0.9975801164627075

# Actual accuracy calculated manually:
import numpy as np
y_pred = model.predict(x_test)
acc = sum([np.argmax(y_test[i])==np.argmax(y_pred[i]) for i in range(10000)])/10000
acc
# 0.98780000000000001

score[1]==acc
# False    

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

from keras.metrics import categorical_accuracy
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=[categorical_accuracy])

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

# Keras reported accuracy:
score = model.evaluate(x_test, y_test, verbose=0) 
score[1]
# 0.98580000000000001

# Actual accuracy calculated manually:
y_pred = model.predict(x_test)
acc = sum([np.argmax(y_test[i])==np.argmax(y_pred[i]) for i in range(10000)])/10000
acc
# 0.98580000000000001

score[1]==acc
# True    

Настройка системы:

Python version 3.5.3
Tensorflow version 1.2.1
Keras version 2.0.4

ОБНОВЛЕНИЕ: После моего сообщения я обнаружил, что эта проблема уже была определена в этом ответе.

Ответ 2

Все зависит от типа проблемы классификации, с которой вы имеете дело. Есть три основных категории;

  • бинарная классификация (два целевых класса)
  • мультиклассовая классификация (более двух эксклюзивных целей)
  • Классификация мульти-этикетка (более двух неисключительных целей), в которой несколько целевых классы могут быть в то же самое время

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

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

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

двоичная кросс-энтропия определяется как таковая: двоичная кросс-энтропия и категориальная кросс-энтропия определяются как таковые: категориальная кросс-энтропия

Ответ 3

Я наткнулся на "перевернутую" проблему - у меня были хорошие результаты с категориальной_кронтропией (с 2 классами) и бедной с binary_crossentropy. Кажется, что проблема связана с неправильной функцией активации. Правильные настройки:

  • для binary_crossentropy: активация сигмоида, скалярная цель
  • для categorical_crossentropy: активация softmax, цель с одним горячим кодированием

Ответ 4

Это действительно интересный случай. На самом деле в вашей установке верно следующее утверждение:

binary_crossentropy = len(class_id_index) * categorical_crossentropy

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

  • В начале наиболее частый класс доминирует над потерей - поэтому сеть учится прогнозировать в основном этот класс для каждого примера.
  • После того, как он узнал самый частый шаблон, он начинает распознавать менее частые классы. Но когда вы используете adam - скорость обучения намного меньше, чем в начале обучения (из-за природы этого оптимизатора). Это замедляет обучение и предотвращает вашу сеть, например. оставляя слабый локальный минимум менее возможным.

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

class_weight = 1 / class_frequency

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

EDIT:

Собственно - я проверил, что хотя в случае математики:

binary_crossentropy = len(class_id_index) * categorical_crossentropy

должен выполняться - в случае keras это не так, потому что keras автоматически нормализует все выходы, суммируя до 1. Это фактическая причина этого странного поведения, поскольку в случае мультиклассификации такая нормализация вредит тренировке.

Ответ 5

Прокомментировав ответ @Marcin, я более тщательно проверил один из кодов моих учеников, где обнаружил такое же странное поведение, даже после всего 2 эпох! (Так что объяснение @Marcin в моем случае было не очень вероятным).

И я обнаружил, что ответ на самом деле очень прост: точность, вычисленная с помощью метода evaluate Keras, просто неверна, если используется двоичная_кросцентропия с более чем 2 метками. Вы можете проверить это, пересчитав точность самостоятельно (сначала вызовите метод Keras "предсказать", а затем вычислите число правильных ответов, возвращаемых предикатом): вы получите истинную точность, которая намного ниже, чем у Keras "оценивает" один.

Ответ 6

простой пример под настройкой мультикласса, чтобы проиллюстрировать

Предположим, у вас есть 4 класса (закодированный onehot) и ниже только один прогноз

true_label = [0,1,0,0] Forecast_label = [0,0,1,0]

при использовании categoryorical_crossentropy точность равна 0, она заботится только о том, правильно ли вы понимаете соответствующий класс.

однако при использовании binary_crossentropy точность рассчитывается для всех классов, для этого прогноза она будет равна 50%. и окончательный результат будет означать индивидуальную точность для обоих случаев.

Рекомендуется использовать categoryorc_crossentropy для задачи с несколькими классами (классы являются взаимоисключающими), но binary_crossentropy для задачи с несколькими метками.

Ответ 7

Поскольку это проблема с несколькими классами, вам нужно использовать категориальную_крестность, бинарная кросс-энтропия будет давать фиктивные результаты, скорее всего, будет оценивать только первые два класса.

50% для многоклассовой проблемы могут быть довольно хорошими, в зависимости от количества классов. Если у вас есть n классов, то 100/n - это минимальная производительность, которую вы можете получить, выведя произвольный класс.

Ответ 8

Взгляните на уравнение, которое вы можете найти, что двоичная кросс-энтропия не только наказывает эти метки = 1, прогнозируемые = 0, но и метку = 0, прогнозируемые = 1.

Однако категорическая перекрестная энтропия только наказывает эти метки = 1, но предсказывает = 1. Поэтому мы предполагаем, что существует только ОДНА метка, положительная.

Ответ 9

при использовании categorical_crossentropy потери, ваши цели должны быть в категорической форме (например, если у вас есть 10 классов, цель для каждого образца должна быть 10-мерный вектор, все-нули для 1 на индекс, соответствующий классу, кроме пример).

Ответ 10

Вы передаете целевой массив формы (x-dim, y-dim), используя в качестве потерь categorical_crossentropy. categorical_crossentropy ожидает, что цели будут двоичными матрицами (1 с и 0 с) формы (выборки, классы). Если ваши цели являются целочисленными классами, вы можете преобразовать их в ожидаемый формат с помощью:

from keras.utils import to_categorical
y_binary = to_categorical(y_int)

В качестве альтернативы вы можете использовать вместо этого функцию потерь sparse_categorical_crossentropy, которая ожидает целочисленные цели.

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

Ответ 11

В этой ссылке кратко объяснены различные потери http://faroit.com/keras-docs/1.2.2/objectives/ enter image description here

Итак, насколько я знаю, математически,

  1. бинарная кросс-энтропия для двух классов (каждый из которых является горячим закодированным вектором), usu. вместе с сигмоидом

binary_loss = -y * log (y_pre) - (1 -y) * log (1 -y _pre)

  1. Категориальная кросс-энтропия для N классов (каждый из которых является горячим закодированным вектором), usu. вместе с сигмоидом

categoryor__loss = -sigma (j: 1 ~ N) [y (j) * log (y_pre (j)) + (1 -y (j)) * log (1 -y _pre (j))]

  1. kullback_leibler_divergence (также известный как отрицательное логарифмическое правдоподобие или NLL), usu. вместе с Softmax

NLL_lost = -sigma (j: 1 ~ N) [y (j) * log (y_pre (j))]

Обратите внимание, что y и y_pre в NLL НЕ являются закодированными векторами с одним "горячим", где y и y_pre являются желаемыми и обучаемыми выходами соответственно. Пожалуйста, исправьте меня, если я ошибаюсь.

Может ли кто-нибудь любезно объяснить редкую категоричную перекрестную энтропию?

На самом деле я настраиваю автоэнкодер. Пример Keras принимает mse, и вход и выход ранжируются от [0 1]. (https://keras.io/examples/mnist_denoising_autoencoder/) Но в действительности автоэнкодер имеет тенденцию реконструировать входное изображение. Таким образом, если диапазон ввода [0 255]/255, то есть имеется 256 возможностей. Разве мы не можем использовать NLL? Я немного запутался здесь.

Большое спасибо.

Ответ 12

Двоичный_кроссцентроп (y_target, y_predict) не требуется применять в задаче двоичной классификации. ,

В исходном коде binary_crossentropy() фактически использовалась функция nn.sigmoid_cross_entropy_with_logits(labels=target, logits=output). И в документации сказано, что:

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