1032 0

[经济学基础] Pytorch 常用损失函数拆解 [推广有奖]

  • 3关注
  • 84粉丝

学术权威

93%

还不是VIP/贵宾

-

威望
0
论坛币
395301 个
通用积分
1053.7518
学术水平
25 点
热心指数
23 点
信用等级
10 点
经验
236484 点
帖子
3497
精华
0
在线时间
5965 小时
注册时间
2020-11-11
最后登录
2024-5-1

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币
Pytorch 常用损失函数拆解[url=]来源公众号:Python数据科学[/url]
作者 | 小新 ,编辑 | 极市平台来源 | https://lhyxx.top CrossEntropyLoss

交叉熵损失,是分类任务中最常用的一个损失函数。

理论

直接上理论公式:

其中  是真实标签,  是预测的类分布(通常是使用softmax将模 型输出转换为概率分布), 也就是  与  中的元素分别表示对应类 别的概率。

举个例子,清晰明了:

# 假设该样本属于第二类 # 因为是分布, 所以属于各个类的和为 1pytorch-实现from torch.nn import CrossEntropyLoss

举例:

实际使用中需要注意几点:

  • torch.nn.CrossEntropyLoss(input, target)中的标签target使用的不是one-hot形式,而是类别的序号。形如 target = [1, 3, 2] 表示3个样本分别属于第1类、第3类、第2类。

  • torch.nn.CrossEntropyLoss(input, target)的input是没有归一化的每个类的得分,而不是softmax之后的分布。


举例,输入的形式大概就像相面这种格式:

然后就将他们扔到CrossEntropyLoss函数中,就可以得到损失。

loss = CrossEntropyLoss(input, target)

我们看CrossEntropyLoss函数里面的实现,是下面这样子的:

def forward(self, input, target):
    return F.cross_entropy(input, target, weight=self.weight,
                           ignore_index=self.ignore_index, reduction=self.reduction)

是调用的torch.nn.functional(俗称F)中的cross_entropy()函数。

参数

  • input:预测值,(batch,dim),这里dim就是要分类的总类别数

  • target:真实值,(batch),这里为啥是1维的?因为真实值并不是用one-hot形式表示,而是直接传类别id。

  • weight:指定权重,(dim),可选参数,可以给每个类指定一个权重。通常在训练数据中不同类别的样本数量差别较大时,可以使用权重来平衡。

  • ignore_index:指定忽略一个真实值,(int),也就是手动忽略一个真实值。

  • reduction:在[none, mean, sum]中选,string型。none表示不降维,返回和target相同形状;mean表示对一个batch的损失求均值;sum表示对一个batch的损失求和。


其中参数weight、ignore_index、reduction要在实例化CrossEntropyLoss对象时指定,例如:

loss = torch.nn.CrossEntropyLoss(reduction='none')

我们再看一下F中的cross_entropy的实现

return nll_loss(log_softmax(input, dim=1), target, weight, None, ignore_index, None, reduction)

可以看到就是先调用log_softmax,再调用nll_loss。

log_softmax就是先softmax再取log:

nll_loss 是negative log likelihood loss:

详细介绍见下面torch.nn.NLLLoss,计算公式如下:

例如假设 , class  ,则,class  class

源码中给了个用法例子:

# input is of size N x C = 3 x 5
input = torch.randn(3, 5, requires_grad=True)
# each element in target has to have 0 <= value < C
target = torch.tensor([1, 0, 4])
output = F.nll_loss(F.log_softmax(input), target)
output.backward()

因此,其实CrossEntropyLoss损失,就是softmax + log + nll_loss的集成。

CrossEntropyLoss(input, target) = nll_loss(log_softmax(input, dim=1), target)

CrossEntropyLoss中的target必须是LongTensor类型。

实验如下:

pred = torch.FloatTensor([[2, 1], [1, 2]])
target = torch.LongTensor([1, 0])

loss_fun = nn.CrossEntropyLoss()

loss = loss_fun(pred, target)  
print(loss)  # 输出为tensor(1.3133)
loss2 = F.nll_loss(F.log_softmax(pred, dim=1), target)
print(loss2)  # 输出为tensor(1.3133)

数学形式就是:

torch-nn-BCELoss理论

CrossEntropy损失函数适用于总共有N个类别的分类。当N=2时,即二分类任务,只需要判断是还是否的情况,就可以使用二分类交叉熵损失:BCELoss 二分类交叉熵损失。上公式 (y是真实标签,x是预测值)

其实这个函数就是CrossEntropyLoss的当类别数N=2时候的特例。因为类别数为2,属于第一类的概率为y,那么属于第二类的概率自然就是(1-y)。因此套用与CrossEntropy损失的计算方法,用对应的标签乘以对应的预测值再求和,就得到了最终的损失。

实践torch.nn.BCELoss(x, y)

x形状(batch,*),y形状与x相同。

x与y中每个元素,表示的是该维度上属于(或不属于)这个类的概率。

另外,pytorch中的BCELoss可以为每个类指定权重。通常,当训练数据中正例和反例的比例差别较大时,可以为其赋予不同的权重,weight的形状应该是一个一维的,元素的个数等于类别数。

实际使用如下例,计算BCELoss(pred, target):

pred = torch.FloatTensor([0.4, 0.1])  # 可以理解为第一个元素分类为是的概率为0.4,第二个元素分类为是的概率为0.1。
target = torch.FloatTensor([0.2, 0.8])  # 实际上第一个元素分类为是的概率为0.2,第二个元素分类为是的概率为0.8。
loss_fun = nn.BCELoss(reduction='mean')  # reduction可选 none, sum, mean, batchmean
loss = loss_fun(pred, target)
print(loss)  # tensor(1.2275)

a = -(0.2 * np.log(0.4) + 0.8 * np.log(0.6) + 0.8 * np.log(0.1) + 0.2 * np.log(0.9))/2
print(a)  # 1.2275294114572126

可以看到,计算BCELoss(pred,target)与上面理论中的公式一样。

内部实现

pytorch 中的torch.nn.BCELoss类,实际上就是调用了F.binary_cross_entropy(input, target, weight=self.weight, reduction=self.reduction)

torch.nn.BCEWithLogitsLoss理论

该函数实际上与BCELoss相同,只是BCELoss的输入x,在输入之前需要先手动经过sigmoid激活函数映射到(0, 1)区间,而该函数将sigmoid与BCELoss整合到一起了

也就是先将输入经过sigmoid函数,然后计算BCE损失。

实践torch.nn.BCEWithLogitsLoss(x, y)

x与y的形状要求与BCELoss相同。

pred = torch.FloatTensor([0.4, 0.1])
target = torch.FloatTensor([0.2, 0.8])
loss_fun = nn.BCEWithLogitsLoss(reduction='mean')  # reduction可选 none, sum, mean, batchmean
loss = loss_fun(pred, target)
print(loss)  # tensor(0.7487)

# 上面的过程与下面的过程结果相同
loss_fun = nn.BCELoss(reduction='mean')  # reduction可选 none, sum, mean, batchmean
loss = loss_fun(torch.sigmoid(pred), target)  # 先经过sigmoid,然后与target计算BCELoss
print(loss)  # tensor(0.7487)

可以看出,先对输入pred调用sigmoid,在调用BCELoss,结果就等于直接调用BCEWithLogitsLoss。

torch.nn.L1Loss理论

L1损失很简单,公式如下:

x是预测值,y是真实值。

实践torch.nn.L1Loss(x, y)

x形状:任意形状

y形状:与输入形状相同

pred = torch.FloatTensor([[3, 1], [1, 0]])
target = torch.FloatTensor([[1, 0], [1, 0]])
loss_fun = nn.L1Loss()
loss = loss_fun(pred, target)
print(loss)  # tensor(0.7500)

其中L1Loss的内部实现为:

def forward(self, input, target):
    return F.l1_loss(input, target, reduction=self.reduction)

我们可以看到,其实还是对F.l1_loss的封装。

torch.nn.MSELoss理论

L1Loss可以理解为向量的1-范数,MSE均方误差就可以理解为向量的2-范数,或矩阵的F-范数。

x是预测值,y是真实值。

实践torch.nn.MSELoss(x, y)

x任意形状,y与x形状相同。

pred = torch.FloatTensor([[3, 1], [1, 0]])
target = torch.FloatTensor([[1, 0], [1, 0]])
loss_fun = nn.MSELoss()
loss = loss_fun(pred, target)
print(loss)  # tensor(1.2500)

其中MSELoss内部实现为:

def forward(self, input, target):
    return F.mse_loss(input, target, reduction=self.reduction)

本质上是对F中mse_loss函数的封装。




二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:损失函数 RCH Functional Likelihood Reduction

已有 1 人评分经验 论坛币 收起 理由
linmengmiki + 100 + 100 奖励积极上传好的资料

总评分: 经验 + 100  论坛币 + 100   查看全部评分

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加JingGuanBbs
拉您进交流群

京ICP备16021002-2号 京B2-20170662号 京公网安备 11010802022788号 论坛法律顾问:王进律师 知识产权保护声明   免责及隐私声明

GMT+8, 2024-5-1 23:16