Реализация пользовательской функции потери WARP в Keras / Tensorflow с ошибкой: LookupError: Градиент для операции не определен - PullRequest
0 голосов
/ 05 мая 2019

Я создаю пользовательскую функцию потери - я сделал другие до этой, которые работают нормально. Тем не менее, я сталкиваюсь с ошибкой на градиентах:

LookupError: Градиент не определен для операции 'loss / target_global_pool_loss / while / RandomShuffle' (тип операции: RandomShuffle)

Я не уверен, так ли это, как я обрабатываю вещи в цикле tenorflow, однако, если я открываю терминал Python, я получаю значение с плавающей точкой:

import tensorflow as tf
import warp_loss
a = [0,1,0,1,1,1,0,0,1]
b = [0.5,0.5,0.3,0.7,0.8,0.9,0.,0.2,0.2]
a = tf.constant(a)
b = tf.constant(b)
sess = tf.InteractiveSession()
loss = warp_loss(a,b)
loss.eval()
0.41588834
loss
<tf.Tensor 'while_3/Exit_1:0' shape=() dtype=float32>
def warp_loss(y_true, y_pred):
    """
    Implementation of the WARP loss function

    Arguments:
    y_true -- true labels, required when you define a loss in Keras, you don't need it in this function.
    y_pred -- prediction values 0-1.

    Returns:
    loss -- real number, value of the loss
    """

    neg_mask  = tf.where(tf.equal(y_true, 0), tf.ones_like(y_pred), tf.zeros_like(y_pred))

    # Get positive and negative scores   
    positives = tf.boolean_mask(y_pred,y_true)
    negatives = tf.boolean_mask(y_pred,neg_mask)

    loss = tf.constant(0, dtype=tf.float32)
    p    = tf.constant(0)

    # Loop all positives
    while_condition = lambda p, loss: tf.less(p, tf.shape(positives)[0])
    def sampling(p, loss):
        # Simulate random sampling without resampling
        shuffled  = tf.random.shuffle(negatives)

        # If no negative above positive, low loss
        sample_i  = tf.cond( tf.keras.backend.sum(K.cast(K.greater(shuffled, positives[p]), K.floatx())) > 0, lambda: tf.cast(tf.argmax(K.cast(K.greater(shuffled, positives[p]), K.floatx())), tf.float32) , lambda: tf.cast(-1, tf.float32 ) )

        # Every positive is equally wanted (therefore -1 foregoes to the investigated positive class)
        L = tf.log(tf.cast(tf.shape(negatives)[0],tf.float32)/(sample_i+1.))
        distance = tf.cast(shuffled[tf.cast(sample_i,tf.int32)], tf.float32)-tf.cast(positives[p], tf.float32)

        # Sum up loss
        individual_loss  = tf.cond( sample_i >= 0 , lambda: L*distance , lambda: tf.cast(0, tf.float32 ) )

        return [tf.add(p, 1), tf.add(loss, individual_loss)]

    _, loss = tf.while_loop(while_condition, sampling, [p, loss])

    return loss

Я ожидал, что мой вывод будет просто плавающим значением, как и другие мои функции потерь.

Мой вход - это i, j, каналы, а выход - двоичный список потенциальных классов. Я делаю train_on_batch по 1 выборке на партию (здесь это не получается):

 File "train.py", line 319, in <module>
    batch_out = model.train_on_batch(np.array([npzobj['features']]), np.array([npzobj['targets']]))
  File "/lib/python3.5/site-packages/keras/engine/training.py", line 1216, in train_on_batch
    self._make_train_function()
  File "/lib/python3.5/site-packages/keras/engine/training.py", line 509, in _make_train_function
    loss=self.total_loss)
  File "/lib/python3.5/site-packages/keras/legacy/interfaces.py", line 91, in wrapper
    return func(*args, **kwargs)
  File "/lib/python3.5/site-packages/keras/optimizers.py", line 184, in get_updates
    grads = self.get_gradients(loss, params)
  File "/lib/python3.5/site-packages/keras/optimizers.py", line 89, in get_gradients
    grads = K.gradients(loss, params)
  File "/lib/python3.5/site-packages/keras/backend/tensorflow_backend.py", line 2757, in gradients
    return tf.gradients(loss, variables, colocate_gradients_with_ops=True)
  File "/lib/python3.5/site-packages/tensorflow/python/ops/gradients_impl.py", line 664, in gradients
    unconnected_gradients)
  File "/lib/python3.5/site-packages/tensorflow/python/ops/gradients_impl.py", line 923, in _GradientsHelper
    (op.name, op.type))
LookupError: No gradient defined for operation 'loss/target_global_pool_loss/while/RandomShuffle' (op type: RandomShuffle)

1 Ответ

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

Очевидно, что случайное перемешивание не имеет градиента, однако, решение этой проблемы обойти Ядро GPU для tf.random_shuffle решило мою проблему.

shuffled  = tf.gather(negatives, tf.random.shuffle(tf.range(tf.shape(negatives)[0])))

# Instead of

shuffled  = tf.random.shuffle(negatives)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...