Как работает двоичная кросс-энтропийная потеря на автоэнкодерах?
Я написал ванильный автоэнкодер, используя только Dense
слой. Ниже мой код:
iLayer = Input ((784,))
layer1 = Dense(128, activation='relu' ) (iLayer)
layer2 = Dense(64, activation='relu') (layer1)
layer3 = Dense(28, activation ='relu') (layer2)
layer4 = Dense(64, activation='relu') (layer3)
layer5 = Dense(128, activation='relu' ) (layer4)
layer6 = Dense(784, activation='softmax' ) (layer5)
model = Model (iLayer, layer6)
model.compile(loss='binary_crossentropy', optimizer='adam')
(trainX, trainY), (testX, testY) = mnist.load_data()
print ("shape of the trainX", trainX.shape)
trainX = trainX.reshape(trainX.shape[0], trainX.shape[1]* trainX.shape[2])
print ("shape of the trainX", trainX.shape)
model.fit (trainX, trainX, epochs=5, batch_size=100)
Вопросы:
1) softmax
обеспечивает распределение вероятностей. Понял. Это означает, что у меня будет вектор 784 значений с вероятностью от 0 до 1. Например, [ 0,02, 0,03..... до 784 пунктов], суммирование всех 784 элементов дает 1.
2) Я не понимаю, как двоичная кроссентропия работает с этими значениями. Двоичная кросс-энтропия для двух значений выхода, верно?
1 ответ
В контексте автоэнкодеров ввод и вывод модели одинаков. Таким образом, если входные значения находятся в диапазоне [0,1], то допустимо использовать sigmoid
как функция активации последнего слоя. В противном случае вам нужно использовать соответствующую функцию активации для последнего слоя (например, linear
который по умолчанию).
Что касается функции потерь, то она снова возвращается к значениям входных данных. Если входные данные находятся только между нулями и единицами (а не значения между ними), то binary_crossentropy
приемлемо в качестве функции потерь. В противном случае вам нужно использовать другие функции потери, такие как 'mse'
(т.е. среднеквадратическая ошибка) или 'mae'
(т.е. средняя абсолютная ошибка). Обратите внимание, что в случае входных значений в диапазоне [0,1]
ты можешь использовать binary_crossentropy
, как это обычно используется (например, учебник по автоэнкодеру Keras и этот документ). Однако не ожидайте, что величина потерь станет нулевой, так как binary_crossentropy
не возвращает ноль, когда и прогноз, и метка не равны нулю или единице (независимо от того, равны они или нет). Вот видео от Hugo Larochelle, где он объясняет функции потерь, используемые в автоэнкодерах (часть об использовании binary_crossentropy
с входами в диапазоне [0,1] начинается в 5:30)
Конкретно, в вашем примере вы используете набор данных MNIST. Поэтому по умолчанию значения MNIST являются целыми числами в диапазоне [0, 255]. Обычно вам нужно сначала нормализовать их:
trainX = trainX.astype('float32')
trainX /= 255.
Теперь значения будут в диапазоне [0,1]. Так sigmoid
может быть использован в качестве функции активации и любой из binary_crossentropy
или же mse
как функция потерь.
Зачем binary_crossentropy
можно использовать, даже когда истинные значения меток (т. е. основание) находятся в диапазоне [0,1]?
Обратите внимание, что мы пытаемся минимизировать функцию потерь при обучении. Таким образом, если функция потерь, которую мы использовали, достигает своего минимального значения (которое не обязательно должно быть равно нулю), когда прогноз равен истинной метке, тогда это приемлемый выбор. Давайте проверим, что это так для кросс-энтропии бинрей, которая определяется следующим образом:
bce_loss = -y*log(p) - (1-y)*log(1-p)
где y
является истинным ярлыком и p
это прогнозируемое значение Давайте рассмотрим y
как исправить и посмотреть, какое значение p
минимизирует эту функцию: нам нужно взять производную по p
(Я предположил, log
естественная логарифмическая функция для простоты расчетов):
bcd_loss_derivative = -y*(1/p) - (1-y)*(-1/(1-p)) = 0 =>
-y/p + (1-y)/(1-p) = 0 =>
-y*(1-p) + (1-y)*p = 0 =>
-y + y*p + p - y*p = 0 =>
p - y = 0 => y = p
Как видите, двоичная кросс-энтропия имеет минимальное значение, когда y=p
т.е. когда истинная метка равна предсказанной метке, и это именно то, что мы ищем.