33

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

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

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']) 
+1

Если это мультиклассируют проблема, вы должны использовать 'categorical_crossentropy'. Также метки необходимо преобразовать в категориальный формат. См. ['To_categorical'] (https://keras.io/utils/np_utils/) для этого. Также см. Определения категориальных и бинарных кроссентропий [здесь] (http://deeplearning.net/software/theano/library/tensor/nnet/nnet.html#theano.tensor.nnet.nnet.binary_crossentropy). –

+0

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

+0

думаю. Если вы используете категориальные ярлыки, то есть один горячий вектор, то вы хотите 'категориальный_crossentropy'. Если у вас есть два класса, они будут представлены как «0, 1» в бинарных меток и «10, 01» в формате категориальной метки. –

ответ

22

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

Точность, вычисленная с помощью th е 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']) 

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

Почему? Если вы проверите metrics source code, Keras не определит одну метрику точности, а несколько разных, среди которых binary_accuracy и categorical_accuracy. Что происходит under the hood, так это то, что вы выбрали бинарную кросс-энтропию как функцию потерь и не указали определенную метрику точности, Keras (ошибочно ...) сообщает, что вас интересует binary_accuracy, и это то, что он возвращает - в то время как на самом деле вас интересует categorical_accuracy.

Давайте проверим, что это так, используя MNIST CNN example в 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 

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

3

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

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

20

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

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. Это фактическая причина этого странного поведения, поскольку в случае мультиклассификации такая нормализация вредит тренировке.

EDIT 2:

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

+0

Помог ли мой ответ? –

+1

Это очень правдоподобное объяснение. Но я не уверен, что это действительно главная причина. Потому что я также наблюдал за * несколькими * моих учеников, работая над этим странным поведением при применении двоичного-X-ent вместо cat-X-ent (что является ошибкой). И это правда, даже когда тренируется только 2 эпохи! Использование class_weight с инверсным классом не помогло. Может быть, строгая настройка скорости обучения поможет, но значения по умолчанию, похоже, благоприятствуют использованию bin-X-ent. Я думаю, что этот вопрос заслуживает большего количества исследований ... – xtof54

+0

Проверьте мое обновление. –

8

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

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

+0

Я видел подобное поведение и на первой итерации. – dolbi

+0

Ну, это замечательный ** улов - спасибо! – desertnaut

5

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

  • для binary_crossentropy: сигмовидная активация, скалярные целевая
  • для categorical_crossentropy: SoftMax активации, один горячим кодируются целевой
+1

Вы уверены, что скалярная цель для binary_crossentropy. Похоже, вы должны использовать «многоструйную» кодированную цель (например, [0 1 0 0 1 1]). – Dmitry

+0

Несомненно. См. Https://keras.io/losses/#usage-of-loss-functions, он говорит: «при использовании потери категориальной_кронтропии ваши цели должны быть в категориальном формате (например, если у вас есть 10 классов, цель для каждого образец должен быть 10-мерным вектором, который является нулевым числом, ожидаемым для 1 при индексе, соответствующем классу выборки). –

+1

Но мы говорим о бинарности-скроссантропии - не категориальной_кронтропии. – Dmitry

0

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

0

Все зависит от типа проблемы классификации, с которой вы имеете дело. Существуют три основные категории;

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

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

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

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

бинарный кросс-энтропия определяется как таковую: binary cross-entropy и категоричны кросс-энтропия определяется как таковую: categorical cross-entropy

+0

Ваш ответ мне кажется очень правдоподобным, но ... Я попытался ответить на @desertnaut и сделал это: с функцией потери binary_crossentropy и metrcis до категориальной_accurency. У меня есть более высокая точность, которая использует функцию потери категориальной_процессорности и метрики точности - и я не могу объяснить, что... – Metal3d