Пользовательская функция потерь в керасе - проблема с реализацией с использованием K.minimum - PullRequest
1 голос
/ 04 октября 2019

Я пытаюсь реализовать пользовательскую функцию потерь в кератах для задачи «Частичное изучение меток». В моем учебном наборе каждому учебному экземпляру назначается набор из двух ярлыков кандидатов, только один из которых является правильным. Для этой цели я хочу использовать функцию потерь, которая во время обучения будет рассчитывать потери для каждой метки и выбирать потери с минимальным значением. Упрощенная версия этой функции будет выглядеть примерно так:

def custom_loss(y_true, y_pred):
num_labels = tf.reduce_sum(y_true) # [0,1,0,0,1]
if num_labels > 1: #create 2 seperate vectors
    y_true_1 = ?  # [0,1,0,0,0]
    y_true_2 = ?  # [0,0,0,0,1]
    loss_1 =  K.categorical_crossentropy(y_true_1, y_pred)
    loss_2 =  K.categorical_crossentropy(y_true_2, y_pred)
    loss = minimum(loss_1, loss_2)
else:
    loss = K.categorical_crossentropy(y_true, y_pred)

return loss

Я пытался сделать это так:

y_true = tf.constant([1., 0., 0., 0., 1., 0., 0., 0., 0.])
y_pred = tf.constant([.9, .05, .05, .5, .89, .6, .05, .01, .94])

def custom_loss(y_true, y_pred):

def train_loss():

    y_train_copy = tf.Variable(0, dtype=y_true.dtype)
    y_train_copy = tf.assign(y_train_copy, y_true, validate_shape=False)

    label_cls = tf.where(tf.equal(y_true,1))
    raplace = tf.Variable([0.]) #Variable
    y_true_1 = tf.compat.v1.scatter_nd_update(y_train_copy, [label_cls[0]], raplace)  # [0,1,0,0,0]
    y_true_2 = tf.compat.v1.scatter_nd_update(y_train_copy, [label_cls[1]], raplace)  # [0,0,0,0,1]
    loss_1 =  K.categorical_crossentropy(y_true_1, y_pred)
    loss_2 =  K.categorical_crossentropy(y_true_2, y_pred)
    min_loss = tf.minimum(loss_1, loss_2)           

    return min_loss      

num_labels = tf.reduce_sum(y_true) # [0,1,0,0,1]
loss = tf.cond(num_labels > 1, 
               lambda: train_loss(), 
               lambda: K.categorical_crossentropy(y_true, y_pred)) #

return loss

loss = custom_loss(y_true, y_pred)

with tf.Session() as sess:
    tf.global_variables_initializer().run()
    print(sess.run(loss))

Проблема в том, что по какой-то причине, независимо от того, как я пытаюсьчтобы получить минимум из двух потерь, я получаю 0.0, даже когда loss_1 и loss_2 определенно не равны 0

Есть идеи почему? или лучшая идея для реализации этой функции?

1 Ответ

1 голос
/ 04 октября 2019

Нет необходимости создавать y_train_copy переменную. Я упрощаю ваш код и выводим min (loss_1, loss_2).

y_true = tf.constant([1., 0., 0., 0., 1., 0., 0., 0., 0.])
y_pred = tf.constant([.9, .05, .05, .5, .89, .6, .05, .01, .94])

def custom_loss(y_true, y_pred):

    def train_loss():
        label_cls = tf.where(tf.equal(y_true, 1.))
        y_true_1 = tf.squeeze(tf.one_hot(label_cls[0], tf.size(y_true)), axis=0)
        y_true_2 = tf.squeeze(tf.one_hot(label_cls[1], tf.size(y_true)), axis=0)
        loss_1 =  K.categorical_crossentropy(y_true_1, y_pred)
        loss_2 =  K.categorical_crossentropy(y_true_2, y_pred)
        min_loss = tf.minimum(loss_1, loss_2)           
        return min_loss      

    num_labels = tf.reduce_sum(y_true) 
    loss = tf.cond(num_labels > 1, 
                   lambda: train_loss(), 
                   lambda: K.categorical_crossentropy(y_true, y_pred)) #

    return loss

loss = custom_loss(y_true, y_pred)

with tf.Session() as sess:
    print(sess.run(loss))

Обновления:

Ошибка вашего кода использует tf.scatter_nd_update(), это изменит значениеy_train_copy на месте. Если вы запустите min_loss, он выполнит y_true_1 и y_true_2 вместе. y_true_2 всегда будет зивером. Тогда ваш min_loss всегда равен нулю. Если вы запустите loss_2 один, вы увидите, что loss_2 не ноль, потому что вы не выполнили y_true_1.

Лучшим выбором будет tf.scatter_nd. Вы можете сделать это,

y_true = tf.constant([1., 0., 0., 0., 1., 0., 0., 0., 0.])
y_pred = tf.constant([.9, .05, .05, .5, .89, .6, .05, .01, .94])

label_cls = tf.where(tf.equal(y_true, 1.))
idx1, idx2 = tf.split(label_cls,2)

raplace = tf.constant([1.])
y_true_1 = tf.scatter_nd(tf.cast(idx1, dtype=tf.int32), raplace, [tf.size(y_true)]) 
y_true_2 = tf.scatter_nd(tf.cast(idx2, dtype=tf.int32), raplace, [tf.size(y_true)])  


loss_1 =  K.categorical_crossentropy(y_true_1, y_pred)
loss_2 =  K.categorical_crossentropy(y_true_2, y_pred)
min_loss = tf.minimum(loss_1, loss_2)

with tf.Session() as sess:
    print(sess.run(min_loss))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...