pytorch實現focal loss的兩種方式


pytorch實現focal loss的兩種方式

import torch
import torch.nn.functional as F
import numpy as np
from torch.autograd import Variable
'''
pytorch實現focal loss的兩種方式(現在討論的是基於分割任務)
在計算損失函數的過程中考慮到類別不平衡的問題,假設加上背景類別共有6個類別
'''
def compute_class_weights(histogram):
    classWeights = np.ones(6, dtype=np.float32)
    normHist = histogram / np.sum(histogram)
    for i in range(6):
        classWeights[i] = 1 / (np.log(1.10 + normHist[i]))
    return classWeights
def focal_loss_my(input,target):
    '''
    :param input: shape [batch_size,num_classes,H,W] 僅僅經過卷積操作后的輸出,並沒有經過任何激活函數的作用
    :param target: shape [batch_size,H,W]
    :return:
    '''
    n, c, h, w = input.size()

    target = target.long()
    input = input.transpose(1, 2).transpose(2, 3).contiguous().view(-1, c)
    target = target.contiguous().view(-1)

    number_0 = torch.sum(target == 0).item()
    number_1 = torch.sum(target == 1).item()
    number_2 = torch.sum(target == 2).item()
    number_3 = torch.sum(target == 3).item()
    number_4 = torch.sum(target == 4).item()
    number_5 = torch.sum(target == 5).item()

    frequency = torch.tensor((number_0, number_1, number_2, number_3, number_4, number_5), dtype=torch.float32)
    frequency = frequency.numpy()
    classWeights = compute_class_weights(frequency)
    '''
    根據當前給出的ground truth label計算出每個類別所占據的權重
    '''

    # weights=torch.from_numpy(classWeights).float().cuda()
    weights = torch.from_numpy(classWeights).float()
    focal_frequency = F.nll_loss(F.softmax(input, dim=1), target, reduction='none')
    '''
    上面一篇博文講過
    F.nll_loss(torch.log(F.softmax(inputs, dim=1),target)的函數功能與F.cross_entropy相同
    可見F.nll_loss中實現了對於target的one-hot encoding編碼功能,將其編碼成與input shape相同的tensor
    然后與前面那一項(即F.nll_loss輸入的第一項)進行 element-wise production
    相當於取出了 log(p_gt)即當前樣本點被分類為正確類別的概率
    現在去掉取log的操作,相當於  focal_frequency  shape  [num_samples]
    即取出ground truth類別的概率數值,並取了負號
    '''

    focal_frequency += 1.0#shape  [num_samples]  1-P(gt_classes)

    focal_frequency = torch.pow(focal_frequency, 2)  # torch.Size([75])
    focal_frequency = focal_frequency.repeat(c, 1)
    '''
    進行repeat操作后,focal_frequency shape [num_classes,num_samples]
    '''
    focal_frequency = focal_frequency.transpose(1, 0)
    loss = F.nll_loss(focal_frequency * (torch.log(F.softmax(input, dim=1))), target, weight=None,
                      reduction='elementwise_mean')
    return loss


def focal_loss_zhihu(input, target):
    '''
    :param input: 使用知乎上面大神給出的方案  https://zhuanlan.zhihu.com/p/28527749
    :param target:
    :return:
    '''
    n, c, h, w = input.size()

    target = target.long()
    inputs = input.transpose(1, 2).transpose(2, 3).contiguous().view(-1, c)
    target = target.contiguous().view(-1)

    N = inputs.size(0)
    C = inputs.size(1)

    number_0 = torch.sum(target == 0).item()
    number_1 = torch.sum(target == 1).item()
    number_2 = torch.sum(target == 2).item()
    number_3 = torch.sum(target == 3).item()
    number_4 = torch.sum(target == 4).item()
    number_5 = torch.sum(target == 5).item()

    frequency = torch.tensor((number_0, number_1, number_2, number_3, number_4, number_5), dtype=torch.float32)
    frequency = frequency.numpy()
    classWeights = compute_class_weights(frequency)

    weights = torch.from_numpy(classWeights).float()
    weights=weights[target.view(-1)]#這行代碼非常重要

    gamma = 2

    P = F.softmax(inputs, dim=1)#shape [num_samples,num_classes]

    class_mask = inputs.data.new(N, C).fill_(0)
    class_mask = Variable(class_mask)
    ids = target.view(-1, 1)
    class_mask.scatter_(1, ids.data, 1.)#shape [num_samples,num_classes]  one-hot encoding

    probs = (P * class_mask).sum(1).view(-1, 1)#shape [num_samples,]
    log_p = probs.log()

    print('in calculating batch_loss',weights.shape,probs.shape,log_p.shape)

    # batch_loss = -weights * (torch.pow((1 - probs), gamma)) * log_p
    batch_loss = -(torch.pow((1 - probs), gamma)) * log_p

    print(batch_loss.shape)

    loss = batch_loss.mean()
    return loss

if __name__=='__main__':
    pred=torch.rand((2,6,5,5))
    y=torch.from_numpy(np.random.randint(0,6,(2,5,5)))
    loss1=focal_loss_my(pred,y)
    loss2=focal_loss_zhihu(pred,y)

    print('loss1',loss1)
    print('loss2', loss2)
'''
in calculating batch_loss torch.Size([50]) torch.Size([50, 1]) torch.Size([50, 1])
torch.Size([50, 1])
loss1 tensor(1.3166)
loss2 tensor(1.3166)
'''


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM