【Pytorch】Loss Function

1 Loss 介绍

在机器学习中,损失函数是代价函数的一部分,而代价函数则是目标函数的一种类型。

Loss function,即损失函数:用于定义单个训练样本与真实值之间的误差;
Cost function,即代价函数:用于定义单个批次/整个训练集样本与真实值之间的误差;
Objective function,即目标函数:泛指任意可以被优化的函数。

KL散度 = 交叉熵 - 熵

回归损失:用于预测连续的值。如预测房价、年龄等。
分类损失:用于预测离散的值。如图像分类,语义分割等。
排序损失:用于预测输入数据之间的相对距离。如行人重识别。

pytorch里的weight decay相当于l2正则

2 常见 Loss

L1 loss

L o s s ( p r e d , y ) = ∣ y − p r e d ∣ Loss( pred , y ) = | y - pred | Loss(pred,y)=ypred

import torch
input = torch.randn(3, 5, requires_grad=True)
target = torch.randn(3, 5)
mae_loss = torch.nn.L1Loss()
output = mae_loss(input, target)

等价于

for i in range(3):
	for j in range(5):
		result += abs(input[i][j] - target[i][j])
result /= 15

L2 loss

L o s s ( p r e d , y ) = ∑ ∣ y − p r e d ∣ 2 Loss( pred , y ) = \sum| y - pred |^2 Loss(pred,y)=ypred2

input = torch.randn(3, 5, requires_grad=True)
target = torch.randn(3, 5)
mse_loss = torch.nn.MSELoss()
output = mse_loss(input, target)

等价于

for i in range(3):
	for j in range(5):
		result += (input[i][j] - target[i][j])**2
result /= 15

Negative Log-Likelihood(NLL)

它的特性是惩罚预测准确而预测概率不高的情况

l o s s ( p r e d , y ) = − ( l o g p r e d ) loss( pred, y) = - (log pred) loss(pred,y)=(logpred)

注:NLL 要求网络最后一层使用 softmax 作为激活函数。通过 softmax 将输出值映射为每个类别的概率值。

# size of input (N x C) is = 3 x 5
input = torch.randn(3, 5, requires_grad=True)
# every element in target should have 0 <= value < C
target = torch.tensor([1, 0, 4])
m = torch.nn.LogSoftmax(dim=1)
nll_loss = torch.nn.NLLLoss()
output = nll_loss(m(input), target)

补充

Softmax 函数常用的用法是指定参数 dim
1)dim=0:对每一列
2)dim=1:对每一行

LogSoftmax 对 softmax 的结果进行 log,即 Log(Softmax(x))

logsoftmax 解决函数 overflow 和 underflow,加快运算速度,提高数据稳性定。
防止溢出

Binary Cross-Entropy

import torch
a = torch.randn(3,3)
target = torch.FloatTensor([[0,1,1],
                            [0,0,1],
                            [1,0,1]])

"compute torch without sigmoid"
loss2 = torch.nn.BCEWithLogitsLoss()
print(loss2(a, target))

"compute torch with sigmoid"
s = a.sigmoid()
loss1 = torch.nn.BCELoss()
print(loss1(s, target))

"compute yourself"
loss_mul = 0
for i in range(3):
    for j in range(3):
        x = target[i][j]*torch.log(s[i][j]) + (1-target[i][j])*torch.log(1-s[i][j])
        loss_mul += x

print(-loss_mul/9)

Cross-Entropy

交叉熵损失函数的与 logsoftmax+NLL 损失函数结果一致

l o s s ( p r e d , y ) = − ∑ y l o g p r e d loss( pred, y) = - \sum ylogpred loss(pred,y)=ylogpred

input = torch.randn(3, 5, requires_grad=True)
target = torch.empty(3, dtype=torch.long).random_(5) # 0~4
cross_entropy_loss = torch.nn.CrossEntropyLoss()
output = cross_entropy_loss(input, target)

等价于

m = torch.nn.LogSoftmax(dim=1)
nll_loss = torch.nn.NLLLoss()
output = nll_loss(m(input), target)

Hinge Embedding

l o s s ( p r e d , y ) = m a x ( 0 , 1 − y ∗ p r e d ) loss(pred, y) = max(0, 1 - y * pred ) loss(pred,y)=max(0,1ypred)

其中 y 为 1 或 -1。

应用场景:

  • 分类问题,特别是在确定两个输入是否不同或相似时。
  • 学习非线性嵌入或半监督学习任务。
input = torch.randn(3, 5, requires_grad=True)
target = torch.randn(3, 5)
hinge_loss = torch.nn.HingeEmbeddingLoss()
output = hinge_loss(input, target)

Margin Ranking Loss

l o s s ( p r e d , y ) = m a x ( 0 , − y ∗ ( p r e d 1 − p r e d 2 ) + m a r g i n ) loss(pred, y) = max(0, -y*(pred1 - pred2) + margin) loss(pred,y)=max(0,y(pred1pred2)+margin)
标签张量 y(包含 1 或 -1)。

当 y == 1 时,第一个输入将被假定为更大的值。它将排名高于第二个输入。如果 y == -1,则第二个输入将排名更高。

应用场景:排名问题

input_one = torch.randn(3, requires_grad=True)
input_two = torch.randn(3, requires_grad=True)
target = torch.randn(3).sign() # 1 or -1

ranking_loss = torch.nn.MarginRankingLoss()
output = ranking_loss(input_one, input_two, target)

Triplet Margin Loss

L o s s ( a , p , n ) = m a x 0 , d ( a i , p i ) − d ( a i , n i ) + m a r g i n Loss (a, p, n) = max{0, d(ai, pi) - d(ai, ni) + margin} Loss(a,p,n)=max0,d(ai,pi)d(ai,ni)+margin

三元组由 a (anchor),p (正样本) 和 n (负样本)组成.

应用场景:

  • 确定样本之间的相对相似性
  • 用于基于内容的检索问题
anchor = torch.randn(100, 128, requires_grad=True)
positive = torch.randn(100, 128, requires_grad=True)
negative = torch.randn(100, 128, requires_grad=True)
triplet_margin_loss = torch.nn.TripletMarginLoss(margin=1.0, p=2)
output = triplet_margin_loss(anchor, positive, negative)

在这里插入图片描述
图片来源 一文理解Ranking Loss/Margin Loss/Triplet Loss

KL Divergence Loss

计算两个概率分布之间的差异。

l o s s ( p r e d , y ) = y ∗ ( l o g y − p r e d ) loss (pred, y) = y*( log y - pred) loss(pred,y)=y(logypred)

输出表示两个概率分布的接近程度。如果预测的概率分布与真实的概率分布相差很远,就会导致很大的损失。如果 KL Divergence 的值为零,则表示概率分布相同。

应用场景:

  • 逼近复杂函数
  • 多类分类任务
  • 确保预测的分布与训练数据的分布相似
input = torch.randn(2, 3, requires_grad=True)
target = torch.randn(2, 3)
kl_loss = torch.nn.KLDivLoss(reduction = 'batchmean')
output = kl_loss(input, target)

下面手动对比计算一下

import torch
import torch.nn as nn

batch_size = 32
embedding = 3*128*128

random_q = torch.randn(batch_size, embedding)
random_p = torch.randn(batch_size, embedding)

# generate random probabilities
q = nn.functional.softmax(random_q, dim=-1)
p = nn.functional.softmax(random_p, dim=-1)

k1_loss = nn.KLDivLoss(reduction="batchmean")
loss = k1_loss(q.log(), p)
print(loss)

# equivalent to the following calculation, log = log e
loos_pointwise = p*(p.log() - q.log())
loss = loos_pointwise.sum(dim=-1).mean()
print(loss)

"""
tensor(1.0018)
tensor(1.0018)
"""

3 Loss 设计

神经网络中,设计loss function有哪些技巧?

作者:Alan Huang
https://www.zhihu.com/question/268105631/answer/335246543

Multi-task learning 还需要解决的是 Gradient domination 的问题。这个问题产生的原因是不同任务的 loss 的梯度相差过大, 导致梯度小的 loss 在训练过程中被梯度大的 loss 所带走。

如果一开始就给不同的 Loss 进行加权, 让它们有相近的梯度, 是不是就能训练的好呢? 结果往往不是这样的。 不同的loss, 他们的梯度在训练过程中变化情况也是不一样的;而且不同的 loss, 在梯度值相同的时候, 它们在 task 上的表现也是不同的。在训练开始的时候,虽然 balance 了, 但是随着训练过程的进行, 中间又发生 gradient domination 了。 所以要想解决这个问题, 还是要合适地对不同 loss 做合适的均衡。

如果A和B单独训练, 他们在收敛的时候的梯度大小分别记为 Grad_a, Grad_b, 那么我们只需要在两个任务一起训练的时候, 分别用各自梯度的倒数(1/Grad_a, 1/Grad_b)对两个任务做平衡, 然后统一乘一个scalar就可以了。(根据单任务的收敛时候的loss梯度去确定multi-task训练中不同任务的权重。)

作者:刘诗昆
https://www.zhihu.com/question/268105631/answer/333738561

Gradient balancing method 一定需要建立在网络设计足够好的基础上,不然光凭平衡梯度并不会对网络泛化能力有着显著的改变。

自定义 loss pytorch 代码

class MyLoss(torch.nn.Moudle):
    def __init__(self):
        super(MyLoss, self).__init__()
        
    def forward(self, x, y):
        loss = torch.mean((x - y) ** 2)
        return loss

4 softmax 及其变体

声明:学习笔记,摘抄来自网络

在这里插入图片描述
soft softmax loss

在这里插入图片描述
知识蒸馏里面的

Large-Margin Softmax Loss(L-softmax)
m是一个控制距离的变量,它越大训练会变得越困难,因为类内不可能无限紧凑
在这里插入图片描述
在这里插入图片描述

作者的实现是通过一个 LargeMargin 全连接层+softmax loss来共同实现,可参考代码。

angular softmax loss(A-softmax)

large margin softmax loss的基础上添加了两个限制条件||W||=1和b=0,使得预测仅取决于W和x之间的角度θ

L2-constrained softmax loss

在这里插入图片描述

上面式就是将其归一化到固定值α。实际训练的时候都不需要修改代码,只需要添加L2-norm层与scale层,如下图。

在这里插入图片描述
scale 更有利于优化

additive margin softmax loss
在这里插入图片描述
在这里插入图片描述
就是把L-Softmax的乘法改成了减法,同时加上了尺度因子s。作者这样改变之后前向后向传播变得更加简单。其中W和f都是归一化过的,作者在论文中将m设为0.35。

argface additive angular margin

在这里插入图片描述

在这里插入图片描述


hardmax 中,真正最大的那个数,一定是以1(100%) 的概率被选出来,其他的值根本一点机会没有。但是在 softmax 中,所有的值都有机会被作为最大值选出来。只不过,由于 softmax 的 “马太效应”,次大的数,即使跟真正最大的那个数差别非常少,在概率上跟真正最大的数相比也小了很多。

“softmax 的作用是把 一个序列,变成概率。” 这个概率不是别的,而是被选为 max 的概率。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

cross entropy 是用来衡量两个概率分布之间的距离的,softmax能把一切转换成概率分布,那么自然二者经常在一起使用。但是你只需要简单推导一下,就会发现,softmax + cross entropy 就好像

“往东走五米,再往西走十米”,

在这里插入图片描述
在这里插入图片描述

cross_entropy = log_softmax + nll_loss

在这里插入图片描述

作者:董鑫
链接:https://www.zhihu.com/question/294679135/answer/885285177
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

5 Loss 异常

来自 loss问题汇总(不收敛、震荡、nan)

在这里插入图片描述
错误数据

通过设置 batch_size = 1,shuffle = False 一步一步地将sample定位到了所有可能的脏数据,删掉

弱化场景,将你的样本简化,各个学习率等参数采用典型配置,比如10万样本都是同一张复制的,让这个网络去拟合,如果有问题,则是网络的问题。否则则是各个参数的问题。

附录A——激活函数

A1 mish

在这里插入图片描述
在这里插入图片描述

def mish(x):
    return x * torch.tanh(torch.nn.functional.softplus(x))
x = torch.arange(start=-10, end=10, step=0.01)
y = mish(x) 
plt.plot(x.numpy(), y.numpy())
plt.title("mish")
plt.savefig("mish.png")
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值