ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

代码笔记13 语义分割交叉熵的实现(去除背景类)

2022-06-11 23:34:42  阅读:225  来源: 互联网

标签:13 ej self torch 语义 per label score 去除


记录

  算是自己一点点小小的记录,以前很少看开源的代码,都自己闷头写,最后才发现自己写的就是shi。不看不学不练啊,读开源代码不代表不自己造轮子,而是要学会别人编程的思想并学习,自己检讨我自己。
  最近确实压力很大,想把这篇文章水出来,可是一来没有人带,导师是拉项目大师,只会分配杂活,教你是不可能的,因为他自己也不会。师兄们也在这样的环境下很佛系,反正也没毕业要求,没人想着写文章或者做这方面的研究。找了这个方向别的老师,也就是私下里请教几个问题,毕竟不是亲导师,能回复回复你帮帮你都算不错了。这几个月学了很多也走了很多坑很多弯路,没有人理解这种感觉吧。还是感谢我的妈妈和女朋友,总能在精神上支持我,不过我这还没搞定呢哈哈哈哈。等到弄得差不多就把学到的东西总结一下慢慢发上来。

2d交叉熵

  这个我就不多说了,可以上网搜,这主要是一种信息熵来衡量信息差别的。主要问题在于,对于室内语义分割中,很大的情况我们是不需要背景类的,例如SUN-RGBD和NYU中都含有0(ignored)这一类,这一类本身不能作为一类算进损失函数中。
  pytorch中封装的交叉熵函数中1

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

其中有ignored_index这一项,但其实不是我们所需要的,但我们可以通过这种方式一样实现这种功能,后续我会展示

实现方法

我一共展现了三种方法,我将完整的代码以及测试结果写在下面。
第一种是我写的,很垃圾,我的想法是将二维的特征图打成一维的,然后筛除0类别再进行交叉熵。
其实二三中都是,先做二位交叉熵,算出来每个像素的交叉熵值后,再根据label进行筛检。
第二种方法来源于github2
亏我当初写了快一天,比起来垃圾多了。。。

import torch
import torch.nn as nn
import torch.nn.functional as F

class CrossEntropyLoss1(nn.Module):
    def __init__(self, classesnum, device):
        super().__init__()
        # utilize weight for different classes in Loss function, the Loss made from the proportion of the pixel classes

        # self.weight = torch.FloatTensor([0.9627, 6.31385, 2.3358, 1.0000, 0.34482, 0.23155, 0.26256, 1.69797, 1.43697,  1.12408, 6.11624, 0.14348, 0.71114])
        self.weight = torch.FloatTensor([0.9627, 6.31385, 2.3358])
        self.weight = self.weight.to(device=device)
        self.crossentropyloss = nn.CrossEntropyLoss(weight=self.weight,size_average=False, reduce=False)
        # self.crossentropyloss = nn.CrossEntropyLoss()
        self.classesnum = classesnum


    def forward(self, score, label):
        B, C, W, H = score.size()
        label = label - 1
        # ignore the class 0,which is the background in sunrgbd,and it does not supposed to be one class
        label_mask = (label != -1)  #find background pixel,True for not, False for is
        score_mask = label_mask.expand(C, B, W, H).permute(1, 0, 2, 3) #expand it to the size of score maps, for exacting not background pixels

        for i in range(int(B)):
            per_label = label[i, :, :]
            per_score = score[i, :, :, :]
            per_labelmask = label_mask[i, :, :]
            per_scoremask = score_mask[i, :, :, :]
            per_label_ej = per_label[per_labelmask]
            per_score_ej = per_score[per_scoremask].reshape(self.classesnum, -1)
            if i == 0:
                lab_ej = per_label_ej
                score_ej = per_score_ej
            elif i > 0:
                lab_ej = torch.cat([lab_ej, per_label_ej], dim=0)
                score_ej = torch.cat([score_ej, per_score_ej], dim=1)

        lab_ej = lab_ej.unsqueeze(dim=0)
        score_ej = score_ej.unsqueeze(dim=0)
        t, pixelsum = lab_ej.size()

        loss = self.crossentropyloss(score_ej, lab_ej)

        input = F.softmax(score_ej, dim=1)
        arg_max = torch.argmax(input, dim=1)
        accurate = torch.sum(arg_max == lab_ej)
        accurate = accurate.item()

        return loss, pixelsum, accurate

class CrossEntropyLoss2(nn.Module):
    def __init__(self):
        super(CrossEntropyLoss2, self).__init__()
        self.weight = torch.FloatTensor([0.9627, 6.31385, 2.3358])

        self.ce_loss = nn.CrossEntropyLoss(weight = self.weight,
                                           size_average=False, reduce=False)

    def forward(self, inputs, targets):
        mask = targets > 0
        targets_m = targets.clone()
        targets_m[mask] -= 1
        loss_all = self.ce_loss(inputs, targets_m.long())
        loss_all = torch.masked_select(loss_all, mask)
        return loss_all

if __name__ == '__main__':
    loss1 = CrossEntropyLoss1(classesnum=3,device='cpu')
    loss2 = CrossEntropyLoss2()
    loss3 = nn.CrossEntropyLoss(weight=torch.FloatTensor([0.9627, 6.31385, 2.3358]),ignore_index=-1, size_average=False, reduce=False)
    label = torch.tensor([[[1,0,2,3],
                          [0,3,3,2],
                          [1,1,0,2],
                          [3,2,0,2]]])
    score = torch.randn([1,3,4,4])

    crent1 = loss1(score,label)
    crent2 = loss2(score,label)
    crent3 = loss3(score,label-1)

    print(crent1,'\n',crent2,'\n',crent3)


结果可见

(tensor([[ 2.0845,  6.6480,  1.6856,  4.9340,  2.6181,  7.4988,  1.6213,  3.3337,
          3.8872,  4.4253, 16.8919, 10.6067]]), 12, 2) 
 tensor([ 2.0845,  6.6480,  1.6856,  4.9340,  2.6181,  7.4988,  1.6213,  3.3337,
         3.8872,  4.4253, 16.8919, 10.6067]) 
 tensor([[[ 2.0845,  0.0000,  6.6480,  1.6856],
         [ 0.0000,  4.9340,  2.6181,  7.4988],
         [ 1.6213,  3.3337,  0.0000,  3.8872],
         [ 4.4253, 16.8919,  0.0000, 10.6067]]])

可见结果是一样的,不过ignored_index的方式是需要为负数的,这个通过lable-1就可以做到,而且出来的值其实是将ignored值输出为0了,后一步还需要做非零点数的计算取平均值

Refrences

[1] https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html
[2] https://github.com/JindongJiang/RedNet

标签:13,ej,self,torch,语义,per,label,score,去除
来源: https://www.cnblogs.com/HumbleHater/p/16367135.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有