欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

pytorch--自定义loss(-log BinaryCrossEntropy FocalLoss)

程序员文章站 2024-03-14 21:47:47
...
  1. 负log loss;
  2. binary crossentropy;
  3. focal loss;

网上找到的loss写的都普遍复杂,我自己稍微写的逻辑简单一点。

if inputs.is_cuda and not self.alpha.is_cuda:
            self.alpha = self.alpha.cuda()

focal loss

focal loss仔细实践起来可以分为两种情况,一种是二分类(sigmoid**)的时候,还有一种情况就是多分类(softmax**)的时候。

二分类focal loss

pytorch--自定义loss(-log BinaryCrossEntropy FocalLoss)

class FocalLoss(nn.Module):
    """ -[alpha*y*(1-p)^gamma*log(p)+(1-alpha)(1-y)*p^gamma*log(1-p)] loss"""

    def __init__(self, gamma, alpha=None , onehot=False):
        super(FocalLoss, self).__init__()
        self.alpha = alpha
        self.gamma = gamma
        self.onehot = onehot


    def forward(self, inputs, targets):
        """

        :param input: onehot
        :param target: 默认是onehot以后
        :return:
        """
        N = inputs.size(0)
        C = inputs.size(1)
        inputs = torch.clamp(inputs, min=0.001, max=1.0)  ##将一个张量中的数值限制在一个范围内,如限制在[0.1,1.0]范围内,可以避免一些运算错误,如预测结果q中元素可能为0
        if inputs.is_cuda and not self.alpha.is_cuda:
            self.alpha = self.alpha.cuda()    

         if not self.onehot:
            class_mask = inputs.data.new(N, C).fill_(0)
            class_mask = Variable(class_mask)
            ids = targets.view(-1, 1)
            class_mask.scatter_(1, ids.data, 1.)
            targets = class_mask

        pos_sample_loss_matrix = -targets * (torch.pow((1 - inputs), self.gamma)) * inputs.log()  ## 正样本的loss
        # mean_pos_sample_loss = pos_sample_loss_matrix.sum() / targets.sum()

        neg_sample_loss_matrix = -(targets == 0).float() * (torch.pow((inputs), self.gamma)) * (1 - inputs).log()  ## 负样本的loss
        # mean_neg_sample_loss = pos_sample_loss_matrix.sum() / targets.sum()
        if self.alpha:
            return (self.alpha * pos_sample_loss_matrix + (1 - self.alpha) * neg_sample_loss_matrix).sum() / (N * C)
        else:
            return (pos_sample_loss_matrix + neg_sample_loss_matrix).sum() / (N * C)


多分类focal loss

pytorch--自定义loss(-log BinaryCrossEntropy FocalLoss)

class FocalLoss(nn.Module):
    """ -[y*(1-p)^gamma*log(p) loss
        softmax**输入的foacl loss。
    """

    def __init__(self, gamma, onehot=False):
        super(FocalLoss, self).__init__()

        self.gamma = gamma
        self.onehot = onehot


    def forward(self, inputs, targets):
        """

        :param input: onehot
        :param target: 默认是onehot以后
        :return:
        """

        inputs = torch.clamp(inputs, min=0.001, max=1.0)  ##将一个张量中的数值限制在一个范围内,如限制在[0.1,1.0]范围内,可以避免一些运算错误,如预测结果q中元素可能为0

         if not self.onehot:
            N = inputs.size(0)
            C = inputs.size(1)
            class_mask = inputs.data.new(N, C).fill_(0)
            class_mask = Variable(class_mask)
            ids = targets.view(-1, 1)
            class_mask.scatter_(1, ids.data, 1.)
            targets = class_mask

        pos_sample_loss_matrix = -targets * (torch.pow((1 - inputs), self.gamma)) * inputs.log()  ## 正样本的loss
        # mean_pos_sample_loss = pos_sample_loss_matrix.sum() / targets.sum()

        ## 默认输出均值
        ## 这里不能直接求mean,
        # 因为整个矩阵还是原来的输入大小的,
        # 求loss应该是除以label中有目标的总数。
        
        return pos_sample_loss_matrix / targets.sum()
        


代码

  • NegtiveLogLoss
  • BinaryCrossEntropy
import torch
import torch.nn as nn
from torch.autograd import Variable

class NegtiveLogLoss(nn.Module):
   """ -log(p) loss"""

   def __init__(self, onehot=False):
       super(NegtiveLogLoss, self).__init__()
       self.onehot = onehot

   def forward(self, inputs, targets):
       """

       :param input: onehot
       :param target: 默认是onehot以后
       :return:
       """

       inputs = torch.clamp(inputs, min=0.001, max=1.0)  ## 将一个张量中的数值限制在一个范围内,如限制在[0.1,1.0]范围内,可以避免一些运算错误,如预测结果q中元素可能为0

       if not self.onehot:
           N = inputs.size(0)
           C = inputs.size(1)
           class_mask = inputs.data.new(N, C).fill_(0)
           class_mask = Variable(class_mask)
           ids = targets.view(-1, 1)
           class_mask.scatter_(1, ids.data, 1.)
           targets = class_mask

       loss_matrix = -targets * inputs.log()  ## 对预测的矩阵里面的每个元素做log,
       ## 然后乘以one hot的label,也就是说获得1位置的值了。
       ## 这时候还是个矩阵,还没有计算均值
       ## 默认输出均值
       return loss_matrix.sum() / targets.sum()  ## 这里不能直接求mean,
       # 因为整个矩阵还是原来的输入大小的,
       # 求loss应该是除以label中有目标的总数。



class BinaryCrossEntropy(nn.Module):
   """ -(ylog(p)+(1-y)log(1-p) loss"""

   def __init__(self, alpha=None, onehot=False):
       super(BinaryCrossEntropy, self).__init__()
       self.alpha = alpha
       self.onehot = onehot

   def forward(self, inputs, targets):
       """

       :param input: onehot
       :param target: 默认是onehot以后
       :return:
       """
       N = inputs.size(0)
       C = inputs.size(1)
       inputs = torch.clamp(inputs, min=0.001, max=1.0)  ##将一个张量中的数值限制在一个范围内,如限制在[0.1,1.0]范围内,可以避免一些运算错误,如预测结果q中元素可能为0
       
       if not self.onehot:

           class_mask = inputs.data.new(N, C).fill_(0)
           class_mask = Variable(class_mask)
           ids = targets.view(-1, 1)
           class_mask.scatter_(1, ids.data, 1.)
           targets = class_mask

       pos_sample_loss_matrix = -targets * inputs.log()  ## 正样本的loss
       # mean_pos_sample_loss = pos_sample_loss_matrix.sum() / targets.sum()
      
       neg_sample_loss_matrix = -(targets == 0).float() * (1 - inputs).log()  ## 负样本的loss
       # mean_neg_sample_loss = pos_sample_loss_matrix.sum() / targets.sum()

       if self.alpha:
           return (self.alpha*pos_sample_loss_matrix + (1-self.alpha)*neg_sample_loss_matrix).sum() / (N * C)
       else:
           return (pos_sample_loss_matrix + neg_sample_loss_matrix).sum() / (N * C)  



引用

  • http://kodgv.xyz/2019/04/22/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/FocalLoss%E9%92%88%E5%AF%B9%E4%B8%8D%E5%B9%B3%E8%A1%A1%E6%95%B0%E6%8D%AE/
相关标签: pytorch loss