Керрас бинарных crossentropy против категоричности crossentropy производительности?


Я пытаюсь обучить 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 58

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

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

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

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

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

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

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

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

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

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

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

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

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

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