Маскируемая функция потери кроссцентропии softmax - PullRequest
0 голосов
/ 27 мая 2019

Я пытаюсь реализовать потерю softmax_crossentropy в Керасе.Потеря должна учитывать только образцы с метками 1 или 0 и игнорировать образцы с метками -1 (т.е. отсутствующие метки).Я нашел функцию binary_crossentropy, которая делает это, но я не смог реализовать для нее версию softmax.

Вот так выглядит binary_crossentropy:

def binary_crossentropy(y_true, y_pred):
    return K.mean(K.binary_crossentropy(tf.multiply(y_pred, tf.cast(tf.not_equal(y_true, -1), tf.float32)),
                                    tf.multiply(y_true, tf.cast(tf.not_equal(y_true, -1), tf.float32))), axis=-1)

Я пытался изменить функцию K.binary_crossentropy ()с K.categorical_crossentropy, но это дает мне «nan» только при подсчете потерь.

Как я могу реализовать это на Keras (Tensorflow backend)?

EDIT:

@ mujjiga предложил использовать sparse_crossentropy, но я столкнулся с ошибкой при компиляции модели:

Используйте sparse_categorical_crossentropy и boolean_mask

def sparse_crossentropy_masked(y_true, y_pred):
    y_true_masked = tf.boolean_mask(y_true, tf.not_equal(y_true, -1))
    y_pred_masked = tf.boolean_mask(y_pred, tf.not_equal(y_true, -1))
    return K.mean(K.sparse_categorical_crossentropy(y_true_masked, y_pred_masked))

Testcase

y_true = tf.constant(np.array([0.,1.,2., -1]))
y_pred = tf.constant(np.array([[1.,0.,0.], [0.,1.,0.], [0.,0.,1.], [0.,0.,1.]]))
loss_op = sparse_crossentropy_masked(y, y_hat)

y_true_1 = tf.constant(np.array([0.,1.,2.]))
y_pred_1 = tf.constant(np.array([[1.,0.,0.], [0.,1.,0.], [0.,0.,1.]]))
loss_1_op = sparse_crossentropy_masked(y_true_1, y_pred_1)

with tf.Session() as sess:
    loss, loss_1 = sess.run([loss_op, loss_1_op])
    assert loss == loss_1



model.compile(loss=sparse_crossentropy_masked)
### TypeError: int returned non-int (type NoneType

1 Ответ

0 голосов
/ 27 мая 2019

Используйте sparse_categorical_crossentropy и boolean_mask

def sparse_crossentropy_masked(y_true, y_pred):
    y_true_masked = tf.boolean_mask(y_true, tf.not_equal(y_true, -1))
    y_pred_masked = tf.boolean_mask(y_pred, tf.not_equal(y_true, -1))
    return K.mean(K.sparse_categorical_crossentropy(y_true_masked, y_pred_masked))

TestCase

y_true = tf.constant(np.array([0.,1.,2., -1]))
y_pred = tf.constant(np.array([[1.,0.,0.], [0.,1.,0.], [0.,0.,1.], [0.,0.,1.]]))
loss_op = sparse_crossentropy_masked(y, y_hat)

y_true_1 = tf.constant(np.array([0.,1.,2.]))
y_pred_1 = tf.constant(np.array([[1.,0.,0.], [0.,1.,0.], [0.,0.,1.]]))
loss_1_op = sparse_crossentropy_masked(y_true_1, y_pred_1)

with tf.Session() as sess:
    loss, loss_1 = sess.run([loss_op, loss_1_op])
    assert loss == loss_1

Обновление

sparse_categorical_crossentropy похоже, есть ошибка, см. Аналогичную проблему здесь . Таким образом, нам осталось использовать categorical_crossentropy вместо этого, но теперь основную истину следует преобразовать в горячее кодирование. Мы будем обозначать метки, которые не рассматриваются, используя -1 (напечатайте y в приведенном ниже коде, если вы не уверены)

Рабочий пример:

def categorical_crossentropy_masked(y_true, y_pred):
    y_true_masked = tf.boolean_mask(y_true, tf.reduce_any(tf.not_equal(y_true, -1), 1))
    y_pred_masked = tf.boolean_mask(y_pred, tf.reduce_any(tf.not_equal(y_true, -1), 1))
    return K.mean(K.categorical_crossentropy(y_true_masked, y_pred_masked))

inputs = Input(shape=(3,))
outputs = Dense(32, activation='relu')(inputs) 
outputs = Dense(16, activation='relu')(outputs) 
outputs = Dense(3, activation='softmax')(outputs)
model = Model(inputs, outputs)
model.compile(optimizer='adam', loss=[categorical_crossentropy_masked])

x = np.random.randn(100,3)
y = np.random.randint(0,3, size=(100))

y = tf.keras.utils.to_categorical(y)
# make some targets to -1 
y[np.random.randint(0,100, size=(15))] = np.ones((15,y.shape[-1]))*-1.

model.fit(x, y)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...