什么是惩罚幅度和符号差异的良好损失函数
What would be a good loss function to penalize the magnitude and sign difference
我处于需要训练模型来预测标量值的情况,重要的是要使预测值与真实值方向相同,同时误差平方和最小。
为此选择什么损失函数比较好?
例如:
假设预测值为-1,真实值为1。两者之间的损失应该比3和1之间的损失大很多,即使(3, 1)和的平方误差(-1, 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()
据我了解,您当前的损失函数类似于:
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, and 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
我处于需要训练模型来预测标量值的情况,重要的是要使预测值与真实值方向相同,同时误差平方和最小。
为此选择什么损失函数比较好?
例如:
假设预测值为-1,真实值为1。两者之间的损失应该比3和1之间的损失大很多,即使(3, 1)和的平方误差(-1, 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()
据我了解,您当前的损失函数类似于:
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, and 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