簡體   English   中英

在Keras中設計自定義損失函數(在Keras中以張量為單位的索引)

[英]design a custom loss function in Keras (on the element index in tensors in Keras)

原始問題

我正在嘗試在Keras中設計自定義損失函數。 目標損失函數類似於Kears中的“ mean_squared_error”,並在下面介紹。

y_true和y_pred的形狀為[batch_size,system_size],並且system_size是整數,例如system_size =5。y_true和y_pred中的元素在[-1,1]的范圍內。 在計算損失之前,我需要根據y_true的最大絕對值的符號和y_pred中的對應值來更改每個樣本的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),軸= -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-Yang的答案中受益: 在y_true和y_pred的大小不同的喀拉拉邦實現自定義損失函數

請注意,tf.gather()在某些早期版本的張量流(例如1.0.1)中不支持“軸”。 它適用於1.11.0。 如果tensorflow版本低,您可能會收到錯誤“ gather()得到了意外的關鍵字參數'axis'”

問題是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]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM