【pytorch】nn.CrossEntropyLoss & nn.BCELoss & nn.BCEWithLogitsLoss

nn.CrossEntropyLoss

torch.nn.CrossEntropyLoss(weight=None, size_average=None, ignore_index=- 100, reduce=None, reduction='mean', label_smoothing=0.0)

计算 logitstarget 之间的交叉熵。

  • logits:不需要是标准化后的数据(也就是不需要和为 1 ),假设输入维度为 N x H x W x C
  • traget:对应输入维度应当是 N x H x W每个值表示了真值类别的 index

【pytorch】nn.CrossEntropyLoss & nn.BCELoss & nn.BCEWithLogitsLoss_第1张图片

patameters:

  • weight:类别的权重。如若需要,它应当是一个一维张量,表示了 C 个类别的权重。在训练集不平衡时很有效。
  • reduction:[‘none’, ‘mean’, ‘sum’],默认为 ‘mean’
    • none:直接输出 tensor 形式的 tensor
    • mean:输出 loss 的平均值
    • sum:输出 loss 的和
  • size_average、reduce:已弃用
  • ingore_index:在计算loss时,忽略某个或某些类。

举个例子

import torch
import torch.nn as nn

def crossEntropyLoss(output,target):
    criterion = nn.CrossEntropyLoss(reduction='mean')
    return criterion(output,target)

if __name__ == "__main__":
	output = torch.tensor([[5,5],[2,8]],dtype=torch.float32)
    target = torch.tensor([0,1]).long()
    print("cross:{}".format(crossEntropyLoss(output,target)))

nn.BCELoss

torch.nn.BCELoss(weight=None, size_average=None, reduce=None, reduction='mean')

计算 inputtarget 之间的二元交叉熵。只能解决二分类问题一般与nn.sigmoid()一起用。

  • input:维度不定,
  • target:维度应与 logit 相同,值应当在 [0, 1]
    【pytorch】nn.CrossEntropyLoss & nn.BCELoss & nn.BCEWithLogitsLoss_第2张图片

patameters

  • weight:一个 batch 的损失的权重。可以手动调整每个 batch 的权重
  • reduction:[‘none’, ‘mean’, ‘sum’],默认为 ‘mean’
    • none:直接输出 tensor 形式的 tensor
    • mean:输出 loss 的平均值
    • sum:输出 loss 的和
  • size_average、reduce:已弃用

举个例子

import torch
import torch.nn as nn

def bceLoss(output,target):
    criterion = nn.BCELoss(reduction='mean')
    output = torch.sigmoid(output)
    print("output: {}".format(output))
    return criterion(output,target)   


if __name__ == "__main__":
    output = torch.tensor([[3],[2]],dtype=torch.float32) 	# 每个样本属于该类的分数
    targer = torch.tensor([[1],[0]],dtype=torch.float32) 	# ground truth
    print(bceLoss(output,targer).item())

二元交叉熵作多标签分类问题(相当于多个二分类问题)

ATTENTION

  • 当xn=0/1时,会有精度问题,见下图:
    【pytorch】nn.CrossEntropyLoss & nn.BCELoss & nn.BCEWithLogitsLoss_第3张图片
    解决方法:没有理解,下次理解

nn.CrossEntropyLoss & nn.BCELoss

在做二分类任务时,nn.CrossEntropyLoss = torch.softmax + nn.BCELoss 但是在单个二分类任务中,torch.softmax + nn.BCELoss没有什么意义。

  • 对于nn.BCELoss来说,在图像分割前景和后景时,每个样本对应的 target 为 1 或 0 ,前者表示属于前景,后者表示属于后景。(因为不属于前景的一定属于后景,所以可以用一个类别来表示)
  • 对于nn.CrossEntropyLoss来说,在图像分割前景和后景时,每个样本对应的 target 为 [1,0] 或 [0,1] ,前者表示属于前景,后者表示属于后景。(虽然p(前景)+p(后景)=1,但是必须将前景和后景分为两类来做,因为如果只用一个类别的话,那么每个像素对应的 logits 就只有一个值,这样经过 softmax 后,值永远为 1 ,模型无法收敛!)
import torch
import torch.nn as nn

output = torch.tensor([[5,5],[2,8]],dtype=torch.float32) 	# 2x2 图像 作为输入
output = torch.softmax(output,dim=-1) 	# 按行进行 softmax
print(output)
target = torch.tensor([[[0,1],[1,0]]).float() 	# 表示个每个像素点的类别真值
bce=nn.BCELoss()
print("bce:{}".format(bce(output,target)))

# 如果用 nn.CrossEntropyLoss 计算:
'''
	由于上文中 softmax 是按行来计算的,所以输入应当转换为 [[5,5],[5,5],[8,2],[2,8]]
'''
output = torch.tensor([[5,5],[5,5],[8,2],[2,8]],dtype=torch.float32)
target = torch.tensor([0,1,1,0]).long()
print("cross:{}".format(crossEntropyLoss(output,target)))

# output
tensor([[0.5000, 0.5000],
        [0.0025, 0.9975]])
bce:3.347815990447998
cross:3.347811698913574

nn.BCEWithLogitsLoss

torch.nn.BCEWithLogitsLoss(weight=None, size_average=None, reduce=None, reduction='mean', pos_weight=None)

nn.BCEWithLogitsLoss = nn.sigmoid + nn.BCELoss

这个版本在数值上比使用普通 Sigmoid + BCELoss 更稳定,因为通过将操作组合到一个层中,我们利用了 log-sum-exp 技巧来实现数值稳定性。
【pytorch】nn.CrossEntropyLoss & nn.BCELoss & nn.BCEWithLogitsLoss_第4张图片

patameters:

  • weight:一个 batch 的损失的权重。可以手动调整每个 batch 的权重
  • reduction:[‘none’, ‘mean’, ‘sum’],默认为 ‘mean’
    • none:直接输出 tensor 形式的 tensor
    • mean:输出 loss 的平均值
    • sum:输出 loss 的和
  • size_average、reduce:已弃用
  • pos_weight:对正样本的权重,是一个与类别数等长的向量

举个例子

output = torch.tensor([[3],[2]],dtype=torch.float32)
    target = torch.tensor([[1],[0]],dtype=torch.float32)
    loss2=nn.BCEWithLogitsLoss()
    print("BCEWithLogitsLoss:",loss2(output,target)) 	# 不需要sigmoid

ATTENTION

  • 为什么通过设置nn.BCEWithLogitsLoss的参数pos_weight可以影响recall和precision?
    • 在二分类问题中,BCEWithLogitsLoss通常用于计算sigmoid输出的二进制交叉熵损失。这个损失函数的计算方式会受到正负样本不平衡的影响,这意味着在训练集中,某些类别的样本数可能比其他类别的样本数更多或更少。
      当正负样本不平衡时,模型可能会倾向于预测具有更多样本的类别,导致较少的类别的预测效果不佳。为了解决这个问题,可以使用pos_weight参数来平衡正负样本之间的权重差异,从而调整模型在预测不同类别时的重要性。
      设置pos_weight参数的值通常是通过计算正样本数和负样本数之间的比率来确定的。如果正样本的数量少于负样本,则可以将pos_weight设置为负样本数除以正样本数的比率,以加权损失函数的正样本部分,从而使模型更关注正样本的预测。反之亦然。
      通过调整pos_weight参数,模型可以更加关注某些类别的预测,从而提高这些类别的准确率和召回率。(来自chatgpt)

你可能感兴趣的:(pytorch,深度学习,python)