什么是惩罚幅度和符号差异的良好损失函数
Posted
技术标签:
【中文标题】什么是惩罚幅度和符号差异的良好损失函数【英文标题】:What would be a good loss function to penalize the magnitude and sign difference 【发布时间】:2018-11-15 14:46:51 【问题描述】:我需要训练一个模型来预测一个标量值,重要的是让预测值与真实值的方向相同,同时平方误差最小。
什么是损失函数的好选择?
例如:
假设预测值为-1,真实值为1。两者之间的损失应该比3和1之间的损失大很多,即使(3, 1)和(-的平方误差) 1, 1) 相等。
非常感谢!
【问题讨论】:
您可以创建任何自定义逻辑。您预计 (3,1) 和 (-1,1) 的损失有多大差异? @AkashGoyal 我不确定两者之间的差异有多大,但我希望 (-1, 1) 的惩罚高于 (3, 1)。现在我的做法是,如果符号有差异,则在常规平方误差的末尾添加一个常数,否则添加 0。谢谢您的 cmets。 【参考方案1】:结果证明这是一个非常有趣的问题 - 感谢您提出这个问题!首先,请记住,您希望您的损失函数完全由微分运算定义,以便您可以通过它进行反向传播。这意味着任何旧的任意逻辑都不一定会这样做。重申您的问题:您希望找到两个变量的可微函数,当这两个变量取不同符号的值时,该函数会急剧增加,而当它们具有相同符号时会增加得更慢。此外,您希望控制这些值相对于彼此急剧增加的方式。因此,我们想要具有两个可配置常量的东西。我开始构建一个满足这些需求的函数,但后来想起了一个你可以在任何高中几何教科书中找到的函数:elliptic paraboloid!
标准制定不符合签署协议对称的要求,所以我不得不介绍一个rotation。上图就是结果。请注意,当符号不一致时,它会急剧增加,而当它们一致时,它会变得不那么急剧,并且控制此行为的输入常量是可配置的。下面的代码是定义和绘制损失函数所需的全部内容。我认为我以前从未使用过几何形式作为损失函数 - 非常简洁。
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
def elliptic_paraboloid_loss(x, y, c_diff_sign, c_same_sign):
# Compute a rotated elliptic parabaloid.
t = np.pi / 4
x_rot = (x * np.cos(t)) + (y * np.sin(t))
y_rot = (x * -np.sin(t)) + (y * np.cos(t))
z = ((x_rot**2) / c_diff_sign) + ((y_rot**2) / c_same_sign)
return(z)
c_diff_sign = 4
c_same_sign = 2
a = np.arange(-5, 5, 0.1)
b = np.arange(-5, 5, 0.1)
loss_map = np.zeros((len(a), len(b)))
for i, a_i in enumerate(a):
for j, b_j in enumerate(b):
loss_map[i, j] = elliptic_paraboloid_loss(a_i, b_j, c_diff_sign, c_same_sign)
fig = plt.figure()
ax = fig.gca(projection='3d')
X, Y = np.meshgrid(a, b)
surf = ax.plot_surface(X, Y, loss_map, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
plt.show()
【讨论】:
非常感谢您提供的详细说明!我还没有在我的训练模型中实现这个损失函数,但它看起来很有希望。更重要的是,您的解释成功地扩展了我对损失函数如何工作以及如何合成它们的理解。真的很感激。训练后我会回来告诉你它在模型中的表现。 嗨@JustinFletcher。我假设上面示例代码中的“x”和“y”分别代表真相和预测,发现损失函数在应该为 0 时给 (-5, -5) 的惩罚为 50。然后我意识到损失函数仅在 (0, 0) 处有一个最佳点,而我们期望 y = x 上的任何点都应该是最佳的。还是我误解了“x”和“y”? 嘿伊桑。你是对的,这个描述并不完整。函数 elliptic_paraboloid_loss 是一个比例因子,可以应用于您选择的任何损失函数。它可以用来缩放任何损失函数。在您的情况下,标准回归损失(平方误差)将是合适的。要看到确实如此,请注意,当值为 (-5, -5) 时,SE 为 0。0 倍椭圆抛物面损失 (50) 仍然为 0。抱歉不清楚。 有没有办法使这种缩放适合凸优化?上述函数是凸函数,不能将一个凸函数乘以另一个凸函数(平方损失/绝对损失)作为损失函数 @Michael 你能进一步优化它吗?我对这种方法非常感兴趣,因为我面临着类似的损失函数标准。【参考方案2】:据我了解,您当前的损失函数类似于:
loss = mean_square_error(y, y_pred)
你可以做的是在你的损失中添加另一个组件,这是一个惩罚负数并且对正数不做任何事情的组件。你可以选择一个系数来决定你想要惩罚它的程度。为此,我们可以像使用负形 ReLU 一样使用。像这样的:
让我们将此组件称为“Neg_ReLU”。那么,你的损失函数将是:
loss = mean_squared_error(y, y_pred) + Neg_ReLU(y_pred)
例如,如果您的结果是 -1,那么总错误将是:
mean_squared_error(1, -1) + 1
如果你的结果是 3,那么总错误是:
mean_squared_error(1, -1) + 0
(见上面的函数如何 Neg_ReLU(3) = 0 和 Neg_ReLU(-1) = 1。
如果你想惩罚更多的负值,那么你可以添加一个系数:
coeff_negative_value = 2
loss = mean_squared_error(y, y_pred) + coeff_negative_value * Neg_ReLU
现在负值受到更多惩罚。
我们可以这样构建 ReLU 负函数:
tf.nn.relu(tf.math.negative(value))
总结一下,最终你的总损失将是:
coeff = 1
Neg_ReLU = tf.nn.relu(tf.math.negative(y))
total_loss = mean_squared_error(y, y_pred) + coeff * Neg_ReLU
【讨论】:
以上是关于什么是惩罚幅度和符号差异的良好损失函数的主要内容,如果未能解决你的问题,请参考以下文章