Как сделать точечную категориальную потерю кроссэнтропии в Керасе?

У меня есть сеть, которая создает выходной тензор 4D, где значение в каждой позиции в пространственных измерениях (~ пиксель) должно интерпретироваться как вероятности класса для этой позиции. Другими словами, на выходе будет (num_batches, height, width, num_classes). У меня есть ярлыки того же размера, где реальный класс закодирован как горячий. Я хотел бы рассчитать categorical-crossentropy убыток, используя это.

Проблема №1. Функция K.softmax ожидает 2D тензор (num_batches, num_classes)

Проблема №2: я не знаю, как следует объединить убытки от каждой позиции. Правильно ли reshape тензор на (num_batches * height * width, num_classes), а затем вызывать K.categorical_crossentropy для этого? Или, скорее, вызовите K.categorical_crossentropy(num_batches, num_classes) высоту * ширину раз и усредните результаты?


person Alex I    schedule 26.03.2017    source источник
comment
Какой бэкэнд вы используете?   -  person Marcin Możejko    schedule 29.03.2017
comment
@ MarcinMożejko Я использую TensorFlow - могу использовать как API-интерфейс Keras, так и собственные функции TF, все в порядке. Спасибо!   -  person Alex I    schedule 30.03.2017
comment
Я ответил на ваш вопрос :-)   -  person Nassim Ben    schedule 03.04.2017
comment
Чувак, тебе нужно проверить наши ответы, потому что иначе ты выиграешь первый ответ (тот, который ты получил до того, как поднял награду) :)   -  person Marcin Możejko    schedule 05.04.2017


Ответы (4)


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

Вкратце: softmax принимает входные данные в 2D или 3D. Если это 3D-кера, примут такую ​​форму (образцы, временные размеры, количество классов) и применит softmax к последнему. По каким-то странным причинам этого не происходит с тензорами 4D.

Решение: преобразовать результат в последовательность пикселей

reshaped_output = Reshape((height*width, num_classes))(output_tensor)

Затем нанесите softmax

new_output = Activation('softmax')(reshaped_output) 

А затем вы либо изменяете целевые тензоры на 2D, либо просто изменяете этот последний слой в (ширину, высоту, num_classes).

В противном случае я бы попробовал, если бы меня сейчас не было на телефоне, - это использовать TimeDistributed(Activation('softmax')). Но не знаю, сработает ли это ... попробую позже

Надеюсь, это поможет :-)

person Nassim Ben    schedule 01.04.2017

Просто сведите результат к двумерному тензору размера (num_batches, height * width * num_classes). Вы можете сделать это с помощью слоя Flatten. Убедитесь, что ваш y сплющен таким же образом (обычно достаточно вызова y = y.reshape((num_batches, height * width * num_classes))).

Что касается вашего второго вопроса, использование категориальной кроссэнтропии для всех width*height прогнозов по сути то же самое, что и усреднение категориальной кроссэнтропии для каждого width*height прогнозов (по определению категориальной кроссэнтропии).

person oscfri    schedule 27.03.2017
comment
Спасибо! Однако меня смущает (num_batches, height * width * num_classes). Разве это не вычисление перекрестной энтропии, как если бы были образцы num_batches с классами height * width * num_classes каждый? Я почти уверен, что хочу, чтобы каждая точка считалась отдельной выборкой, разве это не то же самое, что изменение формы на (num_batches * height * width, num_classes)? Пожалуйста, дайте мне знать, эквивалентны ли они по математике. - person Alex I; 27.03.2017
comment
Извините, только категориальная кроссэнтропия будет по сути тем же математически. Но использование его вместе с softmax не будет таким же математическим, потому что вывод нормализован, что является ошибкой в ​​моем ответе. Я не думаю, что возможно изменить размер партии входной средней точки в модели. Лучший способ - это, вероятно, найти обходной путь и реализовать свою собственную функцию активации softmax, которая нормализует вывод для каждой из height * width ячеек. - person oscfri; 28.03.2017
comment
Спасибо! Я все еще не понимаю, как перевести это в рабочий код, не могли бы вы попробовать? Я начал баунти :) - person Alex I; 28.03.2017

Вы также можете ничего не reshape и определить как softmax, так и loss самостоятельно. Вот softmax, который применяется к последнему входному измерению (как в tf бэкэнде):

def image_softmax(input):
    label_dim = -1
    d = K.exp(input - K.max(input, axis=label_dim, keepdims=True))
    return d / K.sum(d, axis=label_dim, keepdims=True)

и вот у вас loss (ничего переделывать не надо):

__EPS = 1e-5
def image_categorical_crossentropy(y_true, y_pred):
    y_pred = K.clip(y_pred, __EPS, 1 - __EPS)
    return -K.mean(y_true * K.log(y_pred) + (1 - y_true) * K.log(1 - y_pred))

Никаких дополнительных изменений не требуется.

person Marcin Możejko    schedule 03.04.2017

Кажется, что теперь вы можете просто выполнить softmax активацию на последнем Conv2D слое, а затем указать categorical_crossentropy потерю и тренироваться на изображении без каких-либо уловок с изменением формы или какой-либо новой функции потерь. Я пробовал переоснащать фиктивным набором данных, и он хорошо работает. Попробуйте ~!

inp = keras.Input(...)
# define your model here
out = keras.layers.Conv2D(classes, (1, 1), activation='softmax') (...)
model = keras.Model(inputs=[inp], outputs=[out], name='unet')
model.compile(loss='categorical_crossentropy',
                      optimizer='adam',
                      metrics=['accuracy'])
model.fit(tensor4d, tensor4d)

Вы также можете скомпилировать, используя sparse_categorical_crossentropy, а затем тренироваться с выходом формы (samples, height, width), где каждый пиксель в выходных данных соответствует метке класса: model.fit(tensor4d, tensor3d)

Идея состоит в том, что softmax и categorical_crossentropy будут применены к последней оси (вы можете проверить keras.backend.softmax и keras.backend.categorical_crossentropy doc).

PS. Я использую keras от tensorflow.keras (тензорный поток 2)

Обновление: я тренировался на моем реальном наборе данных, и он тоже работает.

person off99555    schedule 14.12.2019