原始问题
我正在尝试在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在Implementing custom loss function in keras with different sizes for y_true and y_pred中的回答。
请注意,tf.gather()在某些早期版本的张量流(例如1.0.1)中不支持``轴''。它适用于1.11.0。如果tensorflow版本低,您可能会得到错误"gather() got an unexpected keyword argument 'axis'"。
答案 0 :(得分:0)
问题在于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]
。