我一直在Pytorch中试验L1和MSE损失,并注意到L1Loss的性能更好,因为它对异常值更健壮。我发现SmoothL1Loss似乎是两全其美。我知道它的行为类似于错误小于1的MSELoss,否则类似于L1Loss。我的数据集只包含0到1之间的值。因此,最大可能的错误是1。这是否意味着函数的行为与MSELoss相同?无论如何,是否有可能调整阈值以更好地解决我的问题?

最佳答案

是的,在这种情况下,它的行为就像torch.nn.MSELoss一样,总共被称为Huber Loss

由于其性质,threshold并没有多大意义,让我们看一下为什么会这样的示例:

怎么运行的

让我们比较在1.0MSELoss情况下大于SmoothL1Loss的错误。假设我们的绝对误差(|f(x) - y|)是10MSELoss将赋予它100的值(或者在实现50的情况下为pytorch),而SmoothL1Loss仅给出该10的值,因此对于大型模型而言,它不会付出太多代价错误。

如果值小于1.0,则SmoothL1Loss惩罚模型小于L1Loss。例如。 0.5将成为0.5*0.5,因此,对于Huber来说是0.25,对于0.5L1Loss

这不是“两全其美”,它取决于您的追求。 Mean Squared Error-放大较大的错误,而对较小的错误轻描淡写,L1Loss将错误赋予“相等”的权重。

自定义损失功能

尽管通常不会这样做,但是您可以根据自己的目标使用任何损失函数(阈值在这里实际上没有意义)。例如,如果您希望较小的错误更加严重,则可以执行以下操作:

import torch

def fancy_squared_loss(y_true, y_pred):
    return torch.mean(torch.sqrt(torch.abs(y_true - y_pred)))


对于值0.2,您将得到~0.447,对于0.5 ~0.7,依此类推。实验并检查手头任务是否存在任何特定的损失函数,尽管我认为这些实验不太可能显着提高L1Loss的价值。

自定义阈值

如果您确实想为MSELossL1Loss设置自定义阈值,则可以自己实现:

import torch

class CustomLoss:
    def __init__(self, threshold: float = 0.5):
        self.threshold = threshold

    def __call__(self, predicted, true):
        errors = torch.abs(predicted - true)
        mask = errors < self.threshold
        return (0.5 * mask * (errors ** 2)) + ~mask * errors


低于threshold的所有内容都将变为MSELoss,高于上方的所有内容均具有L1Loss

关于python - 针对特定情况实现SmoothL1Loss,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/60252902/

10-11 13:04