bert系列第二篇:几个损失函数

本文详细介绍了几种常见的损失函数,包括L1-Loss(MAE)、MSE(L2 Loss)、nllloss(negative-log-loss)和crossentropy。通过公式解析与实例计算,阐述了它们在不同场景下的应用,指出交叉熵损失函数在多分类问题中的重要性,并解释了NLLLoss实际上与交叉熵的关联。

L1-Loss(MAE)

L o s s ( x , y ) = 1 N ∑ i ( ∣ x i − y i ∣ ) Loss(x,y)=\frac{1}{N} \sum_{i}( |x_i-y_i|) Loss(x,y)=N1i(xiyi)

简单而言,就是两个向量的绝对值的误差。 默认求平均,可以设置为sum。
也是mean absolute error(MAE)

举例而言:

 loss = nn.L1Loss()
    '''
    L1 Loss
    '''
    predict_ar = [0,2,3]
    target_ar = [2,2,3]
    input = torch.FloatTensor(predict_ar)
    input.requires_grad = True
    target = torch.FloatTensor(target_ar)
    output = loss(input, target)
    print(output)

结果则是0.667

MSE(L2 Loss)

这个也容易理解,则是平方误差。 mean squared error。

 loss = nn.MSELoss()
    '''
    L1 Loss
    '''
    predict_ar = [0, 2, 3]
    target_ar = [2, 2, 3]

    input = torch.FloatTensor(predict_ar)
    input.requires_grad = True
    target = torch.FloatTensor(target_ar)

    output = loss(input, target)
    print(output)

这个结果应该是4/3= 1.333

nllloss=negative-log-loss

https://pytorch.org/docs/stable/generated/torch.nn.NLLLoss.html#torch.nn.NLLLoss

The negative log likelihood loss. It is useful to train a classification problem with C classes.

这个loss有点不是非常容易理解,它主要的目标是衡量分类问题里,标签和真值的差异,只是用了log和取负。

那么如何计算呢?

loss(input, class) = -input[class]

你没有看错,就是这么简单。
input=[-1.233, 2.657, 0.534], 真实标签为2(class=2),则loss为-0.534

但实际上,大部分情况,input需要做log_softmax喂给NLLLoss。

能否举个例子

def nll_loss():
    #input = torch.rand(3,3)
    input = torch.FloatTensor([[0.8065, 0.5920, 0.1936],
        [0.0985, 0.5246, 0.6277],
        [0.7537, 0.4928, 0.3823]
                               ])

    #每一行是一个预测结果, 分为三类;
    # 如果我们的真值是[0,2,1]类别,那么nllloss如何计算?

    #预处理logsoftmax
    ls = nn.LogSoftmax(dim=1) #行操作;
    input = ls(input)
    target = torch.tensor([0,2,1])

    # 手算
    loss_manual =(0.8539+0.9127+1.1611)/3

    print("input:",input)
    print("target:", target)

    print("loss_manual:",loss_manual)
    # 机算
    loss_f = nn.NLLLoss()
    loss_value = loss_f(input,target)
    print("loss_value:",loss_value.numpy())

最好的例子就是看代码。
输出结果:

input: tensor([[-0.8539, -1.0684, -1.4668],
        [-1.4419, -1.0158, -0.9127],
        [-0.9002, -1.1611, -1.2716]])
target: tensor([0, 2, 1])
loss_manual: 0.9758999999999999
loss_value: 0.97590446

crossentropy

计算公式: H ( p , q ) = − ∑ ∀ x p ( x ) log ⁡ ( q ( x ) ) H(p,q) = -\sum_{\forall x} p(x) \log(q(x)) H(p,q)=xp(x)log(q(x))

大部分计算的公式
J = − 1 N ( ∑ i = 1 N y i ⋅ log ⁡ ( y ^ i ) ) J = - \frac{1}{N}\left(\sum_{i=1}^{N} \mathbf{y_i} \cdot \log(\mathbf{\hat{y}_i})\right) J=N1(i=1Nyilog(y^i))

为何交叉熵可以评估多分类?

A就是数据的真实分布: p(x)
B就是模型从训练数据上学到的分布:q(x)
交叉熵可以很好的表示分布的差异,所以利用最小化交叉熵来达到拟合分布。
具体细节可以参考:https://www.zhihu.com/question/65288314

仔细思考上面的nllloss

将输入经过softmax激活函数之后,再计算其与target的交叉熵损失。即该方法将nn.LogSoftmax()和 nn.NLLLoss()进行了结合。严格意义上的交叉熵损失函数应该是nn.NLLLoss()。

仔细观察下面的官网的公式(是不是有softmax的影子,是不是有log,是不是还有nll操作(x[class]).
loss ⁡ ( x , class ) = − log ⁡ ( exp ⁡ ( x [ class ⁡ ] ) ∑ j exp ⁡ ( x [ j ] ) ) \operatorname{loss}(x, \text {class})=-\log \left(\frac{\exp (x[\operatorname{class}])}{\sum_{j} \exp (x[j])}\right) loss(x,class)=log(jexp(x[j])exp(x[class]))

我们利用上面的例子验证一下结果:

def nll_loss():
    #input = torch.rand(3,3)
    raw_input = torch.FloatTensor([[0.8065, 0.5920, 0.1936],
        [0.0985, 0.5246, 0.6277],
        [0.7537, 0.4928, 0.3823]
                               ])

    #每一行是一个预测结果, 分为三类;
    # 如果我们的真值是[0,2,1]类别,那么nllloss如何计算?

    #预处理logsoftmax
    ls = nn.LogSoftmax(dim=1) #行操作;
    input = ls(raw_input)
    target = torch.tensor([0,2,1])

    # 手算
    loss_manual =(0.8539+0.9127+1.1611)/3

    print("input:",input)
    print("target:", target)

    print("loss_manual:",loss_manual)
    # 机算
    loss_f = nn.NLLLoss()
    loss_value = loss_f(input,target)
    print("loss_value:",loss_value.numpy())

    loss_f_crossentropy = nn.CrossEntropyLoss()
    loss_ce = loss_f_crossentropy(raw_input,target)
    print("loss_ce:", loss_ce.numpy())

输出结果:

input: tensor([[-0.8539, -1.0684, -1.4668],
        [-1.4419, -1.0158, -0.9127],
        [-0.9002, -1.1611, -1.2716]])
target: tensor([0, 2, 1])
loss_manual: 0.9758999999999999
loss_value: 0.97590446
loss_ce: 0.97590446

总结

  1. loss是评估预测和真值的距离,目标是最小化,这样拟合的分布则更加精准。过拟合不再本篇讨论范畴。
  2. 不同的loss可以更好的衡量两个分布的举例,从而拟合更好。
  3. L1,L2非常容易理解
  4. NLLloss是最小化负对数似然函数,和交叉熵本质上是一致的,交叉熵函数里多了一个logsoftmax的过程,其实是分布概率化。
  5. 如此看来,基本上交叉熵就够了。NLLLoss基本不会太用,毕竟交叉熵里有了logsoftmax也有了类别差异的计算。
  6. loss ⁡ ( x , class ) = − log ⁡ ( exp ⁡ ( x [ class ⁡ ] ) ∑ j exp ⁡ ( x [ j ] ) ) \operatorname{loss}(x, \text {class})=-\log \left(\frac{\exp (x[\operatorname{class}])}{\sum_{j} \exp (x[j])}\right) loss(x,class)=log(jexp(x[j])exp(x[class])) 这个公式是核心。

参考文献

  • https://pytorch.org/docs/stable/nn.html#loss-functions
  • https://www.zhihu.com/question/65288314
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值