разработать пользовательскую функцию потерь в Керасе (по индексу элементов в тензорах в Керасе) - PullRequest
0 голосов
/ 30 января 2019

Оригинальный вопрос

Я пытаюсь создать собственную функцию потерь в Керасе.Функция целевых потерь аналогична «mean_squared_error» в Kears и представлена ​​ниже.

y_true и y_pred имеют форму [batch_size, system_size], а system_size является целым числом, например, system_size = 5. Элементыв y_true и y_pred находятся в области [-1, 1].Прежде чем рассчитать потери, мне нужно изменить знак y_pred для каждого образца в соответствии со знаком максимального абсолютного значения y_true и соответствующего значения в y_pred. Для каждого образца мне нужно сначала выбрать индекс максимального абсолютного значения (предположим, что индекс равен i).Если y_pred [:, i] имеет тот же знак, что и y_true [:, i], тогда потеря является нормальным «mean_squared_error».Если знак y_pred [:, i] имеет знак отличающийся от y_true [:, i], все элементы этого образца в y_pred умножаются на -1.

Я попытался использовать следующую функцию, чтобыопределить потери.Однако это не работает.

def normalized_mse(y_true, y_pred):

    y_pred = K.l2_normalize(y_pred, axis = -1) # normalize the y_pred

    loss_minus = K.square(y_true - y_pred)
    loss_plus = K.square(y_true + y_pred) 

    loss = K.mean(tf.where(tf.greater(
                            tf.div(y_true[:, K.argmax(K.abs(y_true), axis = -1))],
                            y_pred[:, K.argmax(K.abs(y_true), axis = -1))]), 0), 
                       loss_minus, loss_plus), axis = -1)

    return loss

Если я заменю «K.argmax (K.abs (y_true), axis = -1))» на целое число, то функция будет работать хорошо.Кажется, что эта команда для выбора индекса максимального абсолютного значения в y_pred проблематична.

Вы когда-нибудь сталкивались с такими проблемами?Не могли бы вы дать мне несколько советов и указаний по этой проблеме?

Большое спасибо.

Эльвин

Решено

Благодаря руководству @AnnaKrogager проблема была решена.Как было указано ниже, K.argmax возвращает тензор вместо целого числа.Согласно ответу @ AnnaKrogager, я изменил функцию потерь на

def normalized_mse(y_true, y_pred):

    y_pred = K.l2_normalize(y_pred, axis = -1)
    y_true = K.l2_normalize(y_true, axis = -1)

    loss_minus = K.square(y_pred - y_true)
    loss_plus = K.square(y_pred + y_true)

    index = K.argmax(K.abs(y_true), axis = -1)
    y_true_slice = tf.diag_part(tf.gather(y_true, index, axis = 1))
    y_pred_slice = tf.diag_part(tf.gather(y_pred, index, axis = 1))

    loss = K.mean(tf.where(tf.greater(tf.div(y_true_slice, y_pred_slice), 0), 
                       loss_minus, loss_plus), axis = -1)

    return loss

. Чтобы проверить это, я определил еще одну функцию с numpy

def normalized_mse_numpy(y_true, y_pred):
    import operator

    batch_size = y_true.shape[0]
    sample_size = y_true.shape[1]
    loss = np.zeros((batch_size))

    for i in range(batch_size):
        index = np.argmax(abs(y_true[i, :]))
        y_pred[i, :] = y_pred[i, :]/linalg.norm(y_pred[i, :])
        y_true[i, :] = y_true[i, :]/linalg.norm(y_true[i, :])

        sign_flag = y_true[i, index] / y_pred[i, index]
        if sign_flag < 0:
           for j in range(sample_size):
               loss[i] = loss[i] + (y_true[i, j] + y_pred[i, j])**2
        else:
           for j in range(sample_size):
               loss[i] = loss[i] + (y_true[i, j] - y_pred[i, j])**2

        loss[i] = loss[i] / SystemSize

     return loss

SystemSize = 5
batch_size = 10
sample_size = 5
y_true = 100 * np.random.rand(batch_size, sample_size)
y_pred = 100 * np.random.rand(batch_size, sample_size)

numpy_result = normalized_mse_numpy(y_true, y_pred)
keras_result = K.eval(normalized_mse(K.variable(y_true), K.variable(y_pred)))

print(numpy_result.sum())
0.9979743490342015

print(keras_result.sum())
0.9979742

numpy_result - keras_result
array([ 4.57889131e-08,  1.27995520e-08,  5.66398740e-09,  1.07868497e-08,
    4.41975839e-09,  7.89889471e-09,  6.68819598e-09,  1.05113101e-08,
   -9.91241045e-09, -1.20345756e-09])

Мне также полезен ответ от Yu-Янг в Реализация пользовательской функции потерь в кератах с разными размерами для y_true и y_pred .

Обратите внимание, что tf.gather () не поддерживает 'axis' в некоторых тензорных потоках ранних версийНапример, 1.0.1.Работает в 1.11.0.Если версия тензорного потока мала, вы можете получить ошибку "collect () получила неожиданный аргумент ключевого слова 'axis'" .

1 Ответ

0 голосов
/ 31 января 2019

Проблема в том, что K.argmax(K.abs(y_pred), axis = -1)) - это тензор, а не целое число, и поэтому срезы не работают.Вместо этого вы можете использовать tf.gather для нарезки:

index = K.argmax(K.abs(y_true), axis = -1)
y_true_slice = tf.diag_part(tf.gather(y, index, axis=1))

Это эквивалентно y_true[:,index].

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