F.smooth_l1_loss, F.cross_entropy ,F.binary_cross_entropy 计算细节的探究

本文深入探讨了机器学习中常见的损失函数,包括Smooth L1 Loss、Cross Entropy、Binary Cross Entropy及其变种,通过代码实现帮助读者理解其工作原理及应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  网络训练的时候,都会遇到一些常用的loss函数,很多常用的loss函数被封装的很好,但是我在使用的时候,总是觉得像黑盒子,知道函数的大概形式,有些细节不了解,因此挑了几个常用的loss函数进行了重新,这样能够更深刻的理解。
  另外,很多在loss层面上进行改进的论文,例如GIOU, Focalloss以及GHM_loss,如果基本loss都不是很理解的话,这些改进的loss的paper读起来也很艰难。

1、F.smooth_l1_loss

在这里插入图片描述

import torch
import torch.nn.functional as F
# 自己设计的smooth_l1_loss
def smooth_l1_loss(a, b):
    loss_part1 = torch.abs(a - b)
    loss_part2 = loss_part1 ** 2
    loss_part2 = loss_part2 * 0.50
    loss2 = torch.where(loss_part1 >= 1, loss_part1 - 0.5, loss_part2)
    #下面是统计每个预测框的loss
    #loss2 = torch.sum(loss2, dim = 1) 
    #最终返回的是所有预测框的loss
    loss2 = torch.sum(loss2)
    return loss2

def test_smmoth_l1_loss():
    loc_p = torch.tensor([1, 5, 3, 0.5])
    loc_t = torch.tensor([4, 1, 0, 0.4])
    loss_1 = F.smooth_l1_loss(loc_p, loc_t, size_average=False)
    print ("F.smooth_l1_loss:", loss_1)
    loss_2 = smooth_l1_loss(loc_p, loc_t)
    print ("smooth_l1_loss:", loss_2)

输出结果为:
F.smooth_l1_loss: tensor(8.5050)
smooth_l1_loss: tensor(8.5050)

2、F.cross_entropy

在这里插入图片描述

交叉熵:它主要刻画的是实际输出(概率)与期望输出(概率)的距离,也就是交叉熵的值越小,两个概率分布就越接近。假设概率分布p为期望输出,概率分布q为实际输出, H(p,q) 为交叉熵,则H(p,q)=−∑x(p(x)logq(x))H(p,q) = -\sum_x(p(x)logq(x))H(p,q)=x(p(x)logq(x))

pytroch 中的cross_entropy是将softmax和cross_entropy结合到一起计算的

def cross_entropy(input, target):
    loss_part1 = torch.sum(input.exp(), dim = 1).log()
    y_onehot = torch.zeros(input.shape, dtype=input.dtype)
    # (int dim, Tensor index, Number value)
    y_onehot.scatter_(1, target.unsqueeze(1), 1)
    loss_part2 = torch.sum(input * y_onehot, dim = 1) * -1
    loss = loss_part1 + loss_part2
    return torch.mean(loss)

def test_cross_entropy():
    input = torch.tensor([[-1.4694, -2.2030, 2.4750],
                         [-1.0823, -0.5950, -1.4115]])
    target = torch.tensor([0, 2])
    loss_1 = F.cross_entropy(input, target)
    print("F.cross_entropy:", loss_1)
    loss_2 = cross_entropy(input, target)
    print("cross_entropy:", loss_2)

test_cross_entropy()

F.cross_entropy: tensor(2.7550)
cross_entropy: tensor(2.7550)

3、F.binary_cross_entropy

def binary_cross_entropy(input, target):
    bce = -(target * torch.log(input) + (1.0 - target) * torch.log(1.0 - input))
    return torch.mean(bce)

def test_binary_cross_entropy():
    input = torch.tensor([[1.4271, -1.8701],
                          [-1.1962, -2.0440],
                          [-0.4560, -1.4295]])
    target = torch.tensor([[1., 0.],
                           [1., 0.],
                           [0., 1.]])

    loss_1 = F.binary_cross_entropy(F.sigmoid(input), target)
    print("F.binary_cross_entropy:", loss_1)
    loss_2 = binary_cross_entropy(F.sigmoid(input), target)
    print("binary_cross_entropy:", loss_2)

F.binary_cross_entropy: tensor(0.6793)
binary_cross_entropy: tensor(0.6793)

4、binary_cross_entropy_with_logits

binary_cross_entropy 和 sigmoid 合并到一起

def test_binary_cross_entropy():
    input = torch.tensor([[1.4271, -1.8701],
                          [-1.1962, -2.0440],
                          [-0.4560, -1.4295]])
    target = torch.tensor([[1., 0.],
                           [1., 0.],
                           [0., 1.]])

    loss_1 = F.binary_cross_entropy(F.sigmoid(input), target)
    print("F.binary_cross_entropy:", loss_1)

    loss_2 = F.binary_cross_entropy_with_logits(input, target)
    print("F.binary_cross_entropy_with_logits:", loss_2)

F.binary_cross_entropy: tensor(0.6793)
F.binary_cross_entropy_with_logits: tensor(0.6793)

import torch import torch.nn as nn import torch.nn.functional as F import numpy as np from scipy.ndimage import distance_transform_edt class AdaptiveCombinedLoss(nn.Module): def __init__(self, initial_weights=[0.3, 0.2, 0.3, 0.2], learnable=True): """ 自适应组合损失函数 :param initial_weights: 初始权重 [dice, jaccard, focal, boundary] :param learnable: 是否启用可学习权重 """ super(AdaptiveCombinedLoss, self).__init__() self.learnable = learnable # 初始化权重参数 if learnable: self.weights = nn.Parameter(torch.tensor(initial_weights, dtype=torch.float32)) else: self.weights = torch.tensor(initial_weights, dtype=torch.float32) # 初始化各损失组件 self.dice_loss = DiceLoss() self.jaccard_loss = JaccardLoss() self.focal_loss = FocalLoss() self.boundary_loss = BoundaryLoss() def forward(self, pred, target): # 计算各损失分量 dice = self.dice_loss(pred, target) jaccard = self.jaccard_loss(pred, target) focal = self.focal_loss(pred, target) boundary = self.boundary_loss(pred, target) # 应用权重归一化 if self.learnable: weights = F.softmax(self.weights, dim=0) else: weights = F.softmax(self.weights, dim=0) # 加权组合损失 total_loss = weights[0] * dice + weights[1] * jaccard + weights[2] * focal + weights[3] * boundary # 动态调整策略:当Dice系数高时强化边界损失 with torch.no_grad(): current_dice = 1 - dice.item() if current_dice > 0.85: weights[3] *= 1.5 # 增强边界损失权重 elif current_dice < 0.4: weights[2] *= 1.2 # 强化Focal Loss处理困难样本 return total_loss, {'dice': dice.item(), 'jaccard': jaccard.item(), 'focal': focal.item(), 'boundary': boundary.item(), 'weights': weights.detach().cpu().numpy()} class DiceLoss(nn.Module): """Dice系数损失函数""" def __init__(self, smooth=1e-5): super(DiceLoss, self).__init__() self.smooth = smooth def forward(self, pred, target): pred = torch.sigmoid(pred) # 计算交集和并集 intersection = (pred * target).sum() union = pred.sum() + target.sum() # 计算Dice系数 dice = (2. * intersection + self.smooth) / (union + self.smooth) return 1 - dice class JaccardLoss(nn.Module): """Jaccard (IoU) 损失函数""" def __init__(self, smooth=1e-5): super(JaccardLoss, self).__init__() self.smooth = smooth def forward(self, pred, target): pred = torch.sigmoid(pred) # 计算交集和并集 intersection = (pred * target).sum() total = (pred + target).sum() union = total - intersection # 计算IoU iou = (intersection + self.smooth) / (union + self.smooth) return 1 - iou class FocalLoss(nn.Module): """Focal Loss 用于处理类别不平衡""" def __init__(self, alpha=0.25, gamma=2.0, reduction='mean'): super(FocalLoss, self).__init__() self.alpha = alpha self.gamma = gamma self.reduction = reduction def forward(self, pred, target): # 计算二元交叉熵 bce_loss = F.binary_cross_entropy_with_logits(pred, target, reduction='none') # 计算概率 pred_prob = torch.sigmoid(pred) # Focal Loss计算 p_t = target * pred_prob + (1 - target) * (1 - pred_prob) modulating_factor = (1.0 - p_t) ** self.gamma # 应用alpha平衡 alpha_factor = target * self.alpha + (1 - target) * (1 - self.alpha) # 组合Focal Loss focal_loss = modulating_factor * alpha_factor * bce_loss if self.reduction == 'mean': return focal_loss.mean() elif self.reduction == 'sum': return focal_loss.sum() else: return focal_loss class BoundaryLoss(nn.Module): """边界损失函数 - 增强边缘分割精度""" def __init__(self, theta0=3, theta=5): super(BoundaryLoss, self).__init__() self.theta0 = theta0 # 边界区域阈值 self.theta = theta # 距离变换参数 def compute_dtm(self, img): """计算距离变换图 (Distance Transform Map)""" fg_mask = img.cpu().numpy() > 0.5 dtm = np.zeros_like(fg_mask, dtype=np.float32) for b in range(img.shape[0]): # 批处理维度 for c in range(img.shape[1]): # 通道维度 dtm_np = distance_transform_edt(fg_mask[b, c]) dtm[b, c] = dtm_np return torch.from_numpy(dtm).to(img.device) def forward(self, pred, target): # 计算边界区域 boundary_region = self.compute_dtm(1 - target) < self.theta0 # 计算距离变换图 dtm = self.compute_dtm(target) # 计算边界损失 pred_sigmoid = torch.sigmoid(pred) boundary_loss = torch.mean(torch.abs(pred_sigmoid[boundary_region] - target[boundary_region]) * torch.exp(-dtm[boundary_region] / self.theta)) return boundary_lossCrossEntropyLoss() 添加到上面的自适应组合损失函数中
最新发布
08-01
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值