【问题标题】:PyTorch equivalence for softmax_cross_entropy_with_logitssoftmax_cross_entropy_with_logits 的 PyTorch 等价性
【发布时间】:2018-02-23 09:44:54
【问题描述】:

我想知道 TensorFlow 的 softmax_cross_entropy_with_logits 是否有等效的 PyTorch 损失函数?

【问题讨论】:

  • 也许是 torch.nn.CrossEntropyLoss ?
  • @YaroslavBulatov 感谢您的回复! tf.nn.softmax_cross_entropy_with_logits 要求 logits 和标签必须具有相同的形状,而 torch.nn.CrossEntropyLoss 具有 Input: (N,C) 其中 C = 类数;目标:(N),其中每个值为 0
  • 这已经在pytorch forum 中讨论过了。希望对你有帮助
  • @McLawrence:谢谢你的建议!该页面没有解决我的问题,但它导致stackoverflow.com/a/39499486/4665251 解决了。非常感谢 stackoverflowuser2010。
  • @Dark_Voyager 那么你是如何解决这个问题的呢?介意分享吗?

标签: tensorflow pytorch cross-entropy


【解决方案1】:

TensorFlow 的 softmax_cross_entropy_with_logits 是否有等效的 PyTorch 损失函数?

torch.nn.functional.cross_entropy

这将 logits 作为输入(在内部执行 log_softmax)。这里的“logits”只是一些不是概率的值(即不一定在区间[0,1])。

但是,logits 也是将转换为概率的值。 如果您考虑 tensorflow 函数的名称,您将理解它是 pleonasm(因为 with_logits 部分假定 softmax 将被调用)。

在 PyTorch 中的实现是这样的:

loss = F.cross_entropy(x, target)

相当于:

lp = F.log_softmax(x, dim=-1)
loss = F.nll_loss(lp, target)

不是F.binary_cross_entropy_with_logits,因为这个函数假设多标签分类:

F.sigmoid + F.binary_cross_entropy = F.binary_cross_entropy_with_logits

也不是torch.nn.functional.nll_loss,因为此函数采用对数概率(在log_softmax() 之后)而不是对数。

【讨论】:

    【解决方案2】:

    解决方案

    from thexp.calculate.tensor import onehot
    from torch.nn import functional as F
    import torch
    
    logits = torch.rand([3,10])
    ys = torch.tensor([1,2,3])
    targets = onehot(ys,10)
    assert F.cross_entropy(logits,ys) == -torch.mean(torch.sum(F.log_softmax(logits, dim=1) * targets, dim=1))
    

    onehot 函数:

    def onehot(labels: torch.Tensor, label_num):
        return torch.zeros(labels.shape[0], label_num, device=labels.device).scatter_(1, labels.view(-1, 1), 1)
    

    【讨论】:

      【解决方案3】:

      根据几个线程中的指针,我最终进行了以下转换。我会在此处发布我的解决方案,以防其他人陷入此线程。它是从here 修改而来的,在this context 中的行为与预期一样。

      # pred is the prediction with shape [C, H*W]
      # gt is the target with shape [H*W]
      # idx is the boolean array on H*W for masking
      
      # Tensorflow version
      loss = tf.nn.sparse_softmax_cross_entropy_with_logits( \
                logits=tf.boolean_mask(pred, idx), \
                labels=tf.boolean_mask(gt, idx)))
      
      # Pytorch version       
      logp = torch.nn.functional.log_softmax(pred[idx])
      logpy = torch.gather(logp, 1, Variable(gt[idx].view(-1,1)))
      loss = -(logpy).mean()
      

      【讨论】:

      • 布尔掩码是干什么用的?
      【解决方案4】:

      @Blade 这是我想出的解决方案!

      import torch
      import torch.nn as nn
      import torch.nn.functional as F
      
      
      class masked_softmax_cross_entropy_loss(nn.Module):
          r"""my version of masked tf.nn.softmax_cross_entropy_with_logits"""
          def __init__(self, weight=None):
              super(masked_softmax_cross_entropy_loss, self).__init__()
              self.register_buffer('weight', weight)
      
          def forward(self, input, target, mask):
              if not target.is_same_size(input):
                  raise ValueError("Target size ({}) must be the same as input size ({})".format(target.size(), input.size()))
      
              input = F.softmax(input)
              loss = -torch.sum(target * torch.log(input), 1)
              loss = torch.unsqueeze(loss, 1)
              mask /= torch.mean(mask)
              mask = torch.unsqueeze(mask, 1)
              loss = torch.mul(loss, mask)
              return torch.mean(loss)
      

      顺便说一句:当时(2017 年 9 月)我需要这个损失函数,因为我试图将 Thomas Kipf 的 GCN(参见 https://arxiv.org/abs/1609.02907)代码从 TensorFlow 转换为 PyTorch。但是,我现在注意到 Kipf 自己完成了这项工作(请参阅 https://github.com/tkipf/pygcn),并且在他的代码中,他只是使用了内置的 PyTorch 损失函数,即负对数似然损失,即

      loss_train = F.nll_loss(output[idx_train], labels[idx_train])
      

      希望这会有所帮助。

      ~DV

      【讨论】:

        猜你喜欢
        • 2022-11-28
        • 2019-11-03
        • 2020-03-26
        • 2022-01-19
        • 2020-01-06
        • 2020-12-28
        • 2018-04-02
        • 2019-09-25
        • 2019-08-29
        相关资源
        最近更新 更多