loss functions

一些常见的损失函数调包就行,复杂的得自己写。损失函数中没有可训练的参数,因此通常直接使用torch.nn.functional中的函数即可。例如一些简单的损失函数:

1
2
3
4
import torch.nn as nn
cls_criterion = nn.CrossEntropyLoss()
dist_criterion = nn.MSELoss() # Use L2 loss function
hinge_criterion = nn.HingeEmbeddingLoss()

还可以参照pytorch-metric-learning这个库

Sigmoid

  • 准确的来说他不是损失函数,是激活函数,用来提升非线性的,但是后面常用,e.g. softmax中有,因此先学习一下。
Sigmoid数学公式
Sigmoid2

nll_loss

负对数似然损失函数(Negtive Log Likehood),对应多分类问题: \[ nll\_loss = -\frac{1}{N}\Sigma_{i=1}^N \mathcal{y}_i (logsoftmax) \] 其中\(y_i\)是==one_hot==编码后的数据标签,NLLLoss()得到的结果即是\(y_i\)与logsoftmax()激活后的结果相乘再求均值再取反。(实际在用封装好的函数时,传入的标签无需进行one_hot编码)

1
2
3
4
5
6
7
8
target = torch.tensor([0, 2, 3, 1, 4])
one_hot = F.one_hot(target).float()
>>> print(one_hot)
tensor([[1., 0., 0., 0., 0.],
[0., 0., 1., 0., 0.],
[0., 0., 0., 1., 0.],
[0., 1., 0., 0., 0.],
[0., 0., 0., 0., 1.]])

Softmax

argmax->softargmax->softmax而来,目的是为了找到一个数列中的最大值,在分类任务中找到概率做大的那个类就是分类的结果。softmax是指数标准化函数,又称为归一化指数函数,将多个神经元的输出,映射到 (0,1) 范围内的K维向量,并且归一化保证和为1,从而使得多分类的概率之和也刚好为1。数学原理如下: \[ Softmax(\mathcal{z}_i)=\frac{\exp (\mathcal{z}_i)}{\Sigma_j \exp (\mathcal{z}_j)} \] \(\mathcal{z}_j\)非常大或者非常小的时候就会导致指数计算出现上溢出和下溢出的问题。那么就可以统一对z的取值进行修改,比如减去\(c=max(z)\),这样就不会上溢出了。但是还存在下溢出,通过数值计算中的等式变换避免下溢出的情况,即使用log函数进行变换。实际计算softmax的方式就变成如下logsoftmax形式,同时保证和为1. \[ \begin{align} Log(Softmax(\mathcal{z}_i))&=Log (\frac{\exp (\mathcal{z}_i-c)}{\Sigma_j \exp (\mathcal{z}_j-c)}) \ &= (\mathcal{z}_i-c)-Log(\Sigma_j \exp(\mathcal{z}_j)-c) \end{align} \]

Binary Cross-Entropy

用于二分类任务,针对每个输入样本,计算预测的概率和真实标签之间的不相关性。torch.nn.BCELoss\[ L = -\left(y_{\text{true}} \cdot \log(y_{\text{pred}}) + (1 - y_{\text{true}}) \cdot \log(1 - y_{\text{pred}})\right) \] \(y_{true}\)表示真实二值标签,要么0要么1,\(y_{pred}\)表示正确类的预测概率,可以先用sigmoid将每个神经元输出的logits值归一化到[0,1]区间成为概率,这里不保证所有的值加起来等于1 。函数输入是(B,C)的向量矩阵,表示B个样本、C个类别和(B,C)个二值标签。

Cross-Entropy loss

交叉熵主要用于多分类任务。torch.nn.CrossEntropyLoss()。交叉熵公式表示如下: \[ H(p,q)=-\Sigma_i P(i)\log Q(i) \] 发现\(H(p,q)\)的计算不依赖于\(P\)矩阵,而仅仅与\(P\)的真实类别的index有关。

当input满足一定条件时,nll_loss和torch.nn.CrossEntropyLoss()是等价的。交叉熵是定义在两个one-hot向量之间的,更具体地说是定义在两个概率向量之间nll是定义在一个模型上的,取决于模型本身可以取不同的形式。步骤:1)将预测的值通过softmax进行归一化保证无上溢出问题;2)再log运算保证无下溢出问题;3)最后与真值计算负对数似然损失。

pytorch官网给出了很好的解释:

  • 实际代码实现中就是将nnl_loss和log_softmax(可以认为就是归一化得到0-1概率值的过程)的结果进行了结合。

  • 不需要对输入的标签进行==one_hot==编码,只需要输入对应的真实标签==(标量)==,内部自动one_hot。

  • 还可以在计算误差是对每个类别进行加权,只需要传入一个权重矩阵就行。

  • 传入的logits值不需要进行归一化但是实际使用来看,还是归一化比较好),也不需要是正数,或者加起来和为1。

  • 输出的结果依据input来,如果是一个C,那么输出就是一个标量,如果传入的是一个batch的数据,那么输出就是B个值。其他见官方说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
>>> import torch
>>> import torch.nn.functional as F
>>> import torch.nn as nn
>>> x = torch.randn(5, 5)
>>> target = torch.tensor([0, 2, 3, 1, 4]) # 标签 这里还有一个torch.tensor与torch.Tensor的知识点https://blog.csdn.net/weixin_40607008/article/details/107348254
>>> one_hot = F.one_hot(target).float() # 对标签进行one_hot编码
>>> softmax = torch.exp(x)/torch.sum(torch.exp(x), dim = 1).reshape(-1, 1)
>>> logsoftmax = torch.log(softmax)
>>> nllloss = -torch.sum(one_hot*logsoftmax)/target.shape[0]
>>> nllloss
tensor(1.8566)
###下面用torch.nn.function实现一下以验证上述结果的正确性
>>> logsoftmax = F.log_softmax(x, dim = 1)
>>> nllloss = F.nll_loss(logsoftmax, target) # 无需对标签做one_hot编码
>>> nllloss
tensor(1.8566)
###最后我们直接用torch.nn.CrossEntropyLoss验证一下以上两种方法的正确性
>>> cross_entropy = F.cross_entropy(x, target)
>>> cross_entropy
tensor(1.8566) #发现是一样的

Triplet loss

公式详见点云定位的docx文档。torch.nn.TripletMarginLoss

需要注意正负样本的选择,有不同的方式,比较常见的有两种:

  • 一种是off-line提前计算好,这种方式需要依赖数据集中的其他信息,例如坐标,因此还是属于有监督学习的范畴;

  • 一种是online利用网络提取的特征进行动态分类,如困难样本挖掘,这种方式训练会耗时一些,但是性能是最最优的。

  • 该函数支持多个负样本的计算,其实就是循环,如果把每个负样本的损失计算单独拎出来,结果是一样的。

1
2
3
4
criterion = nn.TripletMarginLoss(margin=margin_value, p=2, reduction='sum')
for n in range(negCount):
negIx = (torch.sum(negCounts[:i]) + n).item()
loss += criterion(anchor[i: i + 1], positives[i: i + 1], negatives[negIx:negIx + 1])

InfoNCE

全称:Information Noise-Contrastive Estimation。 是Noise-Contrastive Estimation的改进版。最初是在MoCo一文中了解到的。因为MoCo将多模态学习表达为了字典查询问题,因此可以这么说InfoNCE loss can also be interpreted as a kind of classification, where you have K-1 negative classes and 1 positive class

  • 目的是为了通过优化的方式最大化多模态特征之间的互信息,从而使得隐向量表达多个模态之间的公有表征。The 。
  • 相比NCE 损失,可以避免图像数量太多导致的softmax无法计算问题。
  • 其使用mini-batch内的其他样本直接作为负样本。常见于对比学习的loss中,对比学习中假设一个anchor对应一个postive,那么这种方式就存在一些问题,比如恰好找到了相邻位置的正样本,使得所谓的负样本其实是正样本来的。因此有一些工作对此进行了改进,如CWCL。

在多模态对比学习任务中,优化Info-NCE 损失函数可以理解为最大化两个模态互信息的下界,使得隐藏层更能包含两个模态的共有信息。公式表达如下: \[ \mathcal{L}_{Info\_NCE}=-log \Large( \frac{\exp (q \cdot k ^+ /\tau)}{\exp (q \cdot k ^+ /\tau)+\Sigma_{k^-}\exp (q \cdot k ^- /\tau)}) \] \(q,k^+,k^-\),分别表示query、positive,negatives的特征,负样本可有多个。特征向量之间的点乘表示两个特征之间的相似性。使用了softmax的思路进行标准化,实际使用时:就是准备好正负样本对之后,使用Cross-Entropy进行分类的。

实际问题

title:loss functions

author:AmazingHao

link:http://whu-lyh.github.io/blogs/2023/12/27/loss-functions/

publish time:2023-12-27

update time:2024-01-10

| visits
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×