Keras binary crossentropy vs категориальная производительность кроссентропии?

Я пытаюсь обучить CNN классифицировать текст по темам. Когда я использую binary_crossentropy, я получаю ~80% acc, с categorical_crossentrop я получаю ~50% acc.

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

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'))

затем

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

или

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

7 ответов


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

точность, вычисленная с помощью метода Keras "evaluate", просто проста неправильно при использовании 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. Что происходит?--31-->под капотом это так, поскольку вы выбрали двоичную перекрестную энтропию в качестве функции потерь и не указали конкретную метрику точности, Keras (ошибочно...) делает вывод, что вы заинтересованы в the binary_accuracy, и это то, что он возвращает-в то время как на самом деле вы заинтересованы в categorical_accuracy.

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

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

обновление: после моего поста я обнаружил, что эта проблема уже была идентифицирована в ответ.


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

binary_crossentropy = len(class_id_index) * categorical_crossentropy

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

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

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

class_weight = 1 / class_frequency

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

EDIT:

На Самом Деле - Я проверил, что хоть в случае математики:

binary_crossentropy = len(class_id_index) * categorical_crossentropy

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


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

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

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

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


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

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

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

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

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

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


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

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


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