代码之家  ›  专栏  ›  技术社区  ›  Farshid Rayhan

pytorch图像分割的通道交叉熵

  •  2
  • Farshid Rayhan  · 技术社区  · 7 年前

    我正在做一个图像分割任务。总共有7个类,所以最终输出是一个类似于张量的[batch,7,height,width],它是一个softmax输出。现在直观地说,我想使用交叉熵损失,但是pytorch实现不适用于通道级的一个热编码向量

    所以我打算自己做一个功能。在StackOverflow的帮助下,到目前为止,我的代码如下所示

    from torch.autograd import Variable
    import torch
    import torch.nn.functional as F
    
    
    def cross_entropy2d(input, target, weight=None, size_average=True):
        # input: (n, c, w, z), target: (n, w, z)
        n, c, w, z = input.size()
        # log_p: (n, c, w, z)
        log_p = F.log_softmax(input, dim=1)
        # log_p: (n*w*z, c)
        log_p = log_p.permute(0, 3, 2, 1).contiguous().view(-1, c)  # make class dimension last dimension
        log_p = log_p[
           target.view(n, w, z, 1).repeat(0, 0, 0, c) >= 0]  # this looks wrong -> Should rather be a one-hot vector
        log_p = log_p.view(-1, c)
        # target: (n*w*z,)
        mask = target >= 0
        target = target[mask]
        loss = F.nll_loss(log_p, target.view(-1), weight=weight, size_average=False)
        if size_average:
            loss /= mask.data.sum()
        return loss
    
    
    images = Variable(torch.randn(5, 3, 4, 4))
    labels = Variable(torch.LongTensor(5, 3, 4, 4).random_(3))
    cross_entropy2d(images, labels)
    

    我有两个错误。其中一个是在代码本身中提到的,它期望一个热向量。第二个说

    RuntimeError: invalid argument 2: size '[5 x 4 x 4 x 1]' is invalid for input with 3840 elements at ..\src\TH\THStorage.c:41
    

    举个例子,我试着让它在一个三级问题上起作用。所以目标和标签是(不包括用于简化的批处理参数!)

    目标:

     Channel 1     Channel 2  Channel 3
    

    [[0 1 1 0 ] [0 0 0 1 ] [1 0 0 0 ] [0 0 1 1 ] [0 0 0 0 ] [1 1 0 0 ] [0 0 0 1 ] [0 0 0 0 ] [1 1 1 0 ] [0 0 0 0 ] [0 0 0 1 ] [1 1 1 0 ]

    标签:

    通道1通道2通道3
    

    [[0 1 1 0 ] [0 0 0 1 ] [1 0 0 0 ] [0 0 1 1 ] [.2 0 0 0] [.8 1 0 0 ] [0 0 0 1 ] [0 0 0 0 ] [1 1 1 0 ] [0 0 0 0 ] [0 0 0 1 ] [1 1 1 0 ]

    那么我该如何修正我的代码来计算信道交叉熵损失呢?

    3 回复  |  直到 7 年前
        1
  •  3
  •   Linda    6 年前

    正如shai的回答已经指出的,关于 torch.nn.CrossEntropy() 可以找到函数 here 代码可以找到 here . 内置函数确实已经支持kd交叉熵损失。

    在3D的情况下, torch.nn.交叉熵() 函数需要两个参数:4D输入矩阵和3D目标矩阵。输入矩阵的形状为:(minibatch,classes,h,w)。目标矩阵的形状(minibatch,h,w)为0到(classes-1)之间的数字。如果你从一个热编码矩阵开始,你必须用 np.argmax() .

    三个类的示例,小批量大小为1:

    import pytorch
    import numpy as np
    
    input_torch = torch.randn(1, 3, 2, 5, requires_grad=True)
    
    one_hot = np.array([[[1, 1, 1, 0, 0], [0, 0, 0, 0, 0]],    
                        [[0, 0, 0, 0, 0], [1, 1, 1, 0, 0]],
                        [[0, 0, 0, 1, 1], [0, 0, 0, 1, 1]]])
    
    target = np.array([np.argmax(a, axis = 0) for a in target])
    target_torch = torch.tensor(target_argmax)
    
    loss = torch.nn.CrossEntropyLoss()
    output = loss(input_torch, target_torch)
    output.backward()
    
        2
  •  0
  •   Shai    7 年前

    二维(或kd)交叉熵是神经网络中一个非常基本的构造块。pytorch不太可能没有“开箱即用”的实现。
    看着 torch.nn.CrossEntropyLoss 以及潜在的 torch.nn.functional.cross_entropy 您将看到,损失可以处理二维输入(即4d输入预测张量)。
    此外,您还可以签出实际实现此功能的代码 here 看看它是如何根据 dim 属于 input 张量。

    所以,不用麻烦了,已经为你做了!

        3
  •  0
  •   Farshid Rayhan    6 年前

    这是我的密码

    `for batch, data in enumerate(trainloader, 0):
    
            inputs, labels = data
            labels = labels.long()
            inputs, labels = inputs.to(device), labels.to(device)
    
            labels = labels.view([-1, ])
    
    
    
            optimizer = optim.Adam(net.parameters(), lr=lr)
    
    
            optimizer.zero_grad()
            outputs = net(inputs)
    
    
            outputs = outputs.view(-1, num_of_class)
    
    
            loss = criterion(outputs, labels)
            loss.backward()
            optimizer.step()
            running_loss += loss.item()
    
    
    
            # # sanity check
            # print()
            # print('epoch ', epoch, 'batch ', batch, " inputs", inputs.shape, "labels", labels.shape,
            #       "outputs", outputs.shape)
            # # sanity check end
    
    
    
            outputs = outputs.to('cpu')
            outputs = outputs.data.numpy()
            outputs = outputs.reshape([-1, num_of_class])
    
            mask = np.zeros([outputs.shape[0]])
            #
            for i in range(len(outputs)):
                mask[i] = np.argmax(outputs[i])
    
            mask = mask.reshape([-1, 1])
    
            IoU = jaccard_similarity_score(labels.to('cpu').data, mask)
    

    `