Эквивалентность PyTorch для softmax_cross_entropy_with_logits

Мне было интересно, есть ли эквивалентная функция потерь PyTorch для softmax_cross_entropy_with_logits TensorFlow?


person Dark_Voyager    schedule 14.09.2017    source источник
comment
может быть, torch.nn.CrossEntropyLoss?   -  person Yaroslav Bulatov    schedule 14.09.2017
comment
@ЯрославБулатов спасибо за ответ! tf.nn.softmax_cross_entropy_with_logits требует, чтобы логиты и метки имели одинаковую форму, тогда как torch.nn.CrossEntropyLoss имеет входные данные: (N,C), где C = количество классов; Цель: (N), где каждое значение равно 0 ‹= target[i] ‹= C-1. Кроме того, последний не использует Softmax в расчетах. Я ищу точную копию функции TensorFlow.   -  person Dark_Voyager    schedule 14.09.2017
comment
Это обсуждалось в форум pytorch. Надеюсь, поможет   -  person McLawrence    schedule 15.09.2017
comment
@McLawrence: спасибо за ваше предложение! Эта страница не решила мою проблему, но привела к stackoverflow.com/a/39499486/4665251, что и помогло. Большое спасибо stackoverflowuser2010.   -  person Dark_Voyager    schedule 18.09.2017
comment
@Dark_Voyager Итак, как вы решили проблему? Не хотите поделиться?   -  person Blade    schedule 04.12.2019


Ответы (4)


существует ли эквивалентная функция потерь PyTorch для softmax_cross_entropy_with_logits TensorFlow?

torch.nn.functional.cross_entropy

В качестве входных данных используются логиты (выполнение log_softmax внутри). Здесь логиты — это просто некоторые значения, которые не являются вероятностями (т.е. не обязательно в интервале [0,1]).

Но логиты также являются значениями, которые будут преобразованы в вероятности. Если вы рассмотрите название функции тензорного потока, вы поймете, что это плеоназм (поскольку часть 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()), а не логиты.

person prosti    schedule 22.09.2020

Следуя указателям в нескольких потоках, я получил следующее преобразование. Я опубликую здесь свое решение на случай, если кто-то еще попадет в эту тему. Он изменен с здесь и ведет себя так, как ожидалось в пределах в этом контексте.

# 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()
person ilke444    schedule 12.04.2019
comment
Для чего нужна булевская маска? - person Blade; 04.12.2019

@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 года), потому что я пытался перевести GCN Томаса Кипфа (см. https://arxiv.org/abs/1609.02907) код из TensorFlow в PyTorch. Однако теперь я заметил, что Кипф сделал это сам (см. https://github.com/tkipf/pygcn), и в своем коде он просто использует встроенную функцию потерь PyTorch, отрицательную логарифмическую потерю вероятности, т.е.

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

Надеюсь это поможет.

~DV

person Dark_Voyager    schedule 05.12.2019

Решение

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))

горячая функция:

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)
person Sailist    schedule 30.08.2020