[英]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.