O que são logits, softmax e softmax_cross_entropy_with_logits?

351

Eu estava examinando os documentos da API do tensorflow aqui . Na documentação do tensorflow, eles usaram uma palavra-chave chamada logits. O que é isso? Em muitos métodos nos documentos da API, ele é escrito como

tf.nn.softmax(logits, name=None)

Se o que está escrito é logitsapenas um Tensors, por que manter um nome diferente logits?

Outra coisa é que existem dois métodos que não consegui diferenciar. Eles eram

tf.nn.softmax(logits, name=None)
tf.nn.softmax_cross_entropy_with_logits(logits, labels, name=None)

Quais são as diferenças entre eles? Os documentos não estão claros para mim. Eu sei o que tf.nn.softmaxfaz. Mas não o outro. Um exemplo será realmente útil.

Shubhashis
fonte

Respostas:

427

Logits significa simplesmente que a função opera na saída não escalonada das camadas anteriores e que a escala relativa para entender as unidades é linear. Isso significa, em particular, que a soma das entradas pode não ser igual a 1, que os valores não são probabilidades (você pode ter uma entrada de 5).

tf.nn.softmaxproduz apenas o resultado da aplicação da função softmax a um tensor de entrada. O softmax "esmaga" as entradas para que sum(input) = 1: seja uma maneira de normalizar. O formato da saída de um softmax é o mesmo da entrada: apenas normaliza os valores. As saídas do softmax podem ser interpretadas como probabilidades.

a = tf.constant(np.array([[.1, .3, .5, .9]]))
print s.run(tf.nn.softmax(a))
[[ 0.16838508  0.205666    0.25120102  0.37474789]]

Por outro lado, tf.nn.softmax_cross_entropy_with_logitscalcula a entropia cruzada do resultado após aplicar a função softmax (mas faz tudo isso de uma maneira matematicamente mais cuidadosa). É semelhante ao resultado de:

sm = tf.nn.softmax(x)
ce = cross_entropy(sm)

A entropia cruzada é uma métrica resumida: soma entre os elementos. A saída de tf.nn.softmax_cross_entropy_with_logitsum [2,5]tensor de forma é de forma [2,1](a primeira dimensão é tratada como lote).

Se você deseja fazer a otimização para minimizar a entropia cruzada E você está aplicando o softmax após sua última camada, use-o em tf.nn.softmax_cross_entropy_with_logitsvez de fazer você mesmo, porque ele cobre casos de canto numericamente instáveis ​​da maneira matematicamente correta. Caso contrário, você acabará invadindo-o adicionando pequenos epsilons aqui e ali.

Editado 07-02-2016: se você tiver rótulos de classe única, onde um objeto só pode pertencer a uma classe, considere usar agora tf.nn.sparse_softmax_cross_entropy_with_logitspara não precisar converter seus rótulos em um array denso e quente. Esta função foi adicionada após o lançamento 0.6.0.

dga
fonte
11
Sobre o softmax_cross_entropy_with_logits, não sei se o uso corretamente. O resultado não é tão estável no meu código. O mesmo código é executado duas vezes, a precisão total muda de 0,6 para 0,8. cross_entropy = tf.nn.softmax_cross_entropy_with_logits(tf.nn.softmax(tf.add(tf.matmul(x,W),b)),y) cost=tf.reduce_mean(cross_entropy). Mas quando uso outra maneira, pred=tf.nn.softmax(tf.add(tf.matmul(x,W),b)) cost =tf.reduce_mean(-tf.reduce_sum(y*tf.log(pred),reduction_indices=1))o resultado é estável e melhor.
Rida
15
Você está usando softmax duas vezes na sua primeira linha. O softmax_cross_entropy_with_logits espera logits sem escala, não a saída de tf.nn.softmax. Você só quer tf.nn.softmax_cross_entropy_with_logits(tf.add(tf.matmul(x, W, b))no seu caso.
Dga 14/07
7
@dga Acho que você tem um erro de digitação no seu código, as bnecessidades de estar fora do suporte,tf.nn.softmax_cross_entropy_with_logits(tf.add(tf.matmul(x, W), b)
jrieke
11
o que significa "que a escala relativa para entender as unidades é linear". parte da sua primeira frase significa?
Charlie Parker
5
Voto positivo - mas sua resposta está levemente incorreta quando você diz que "[a] forma de saída de um softmax é a mesma que a entrada - apenas normaliza os valores". O Softmax não apenas "esmaga" os valores para que sua soma seja igual a 1. Ele também os redistribui, e essa é possivelmente a principal razão pela qual ela é usada. Consulte stackoverflow.com/questions/17187507/… , especialmente a resposta da Piotr Czapla.
Paolo Perrotta
282

Versão curta:

Suponha que você tenha dois tensores, onde y_hatcontém pontuações computadas para cada classe (por exemplo, de y = W * x + b) e y_truecontém rótulos verdadeiros codificados com um hot hot.

y_hat  = ... # Predicted label, e.g. y = tf.matmul(X, W) + b
y_true = ... # True label, one-hot encoded

Se você interpretar as pontuações y_hatcomo probabilidades de log não normalizadas, elas serão logits .

Além disso, a perda total de entropia cruzada calculada desta maneira:

y_hat_softmax = tf.nn.softmax(y_hat)
total_loss = tf.reduce_mean(-tf.reduce_sum(y_true * tf.log(y_hat_softmax), [1]))

é essencialmente equivalente à perda total de entropia cruzada calculada com a função softmax_cross_entropy_with_logits():

total_loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(y_hat, y_true))

Versão longa:

Na camada de saída da sua rede neural, você provavelmente calculará uma matriz que contém as pontuações da classe para cada uma das suas instâncias de treinamento, como em uma computação y_hat = W*x + b. Para servir como exemplo, abaixo, criei uma y_hatmatriz como 2 x 3, em que as linhas correspondem às instâncias de treinamento e as colunas correspondem às classes. Então, aqui existem 2 instâncias de treinamento e 3 classes.

import tensorflow as tf
import numpy as np

sess = tf.Session()

# Create example y_hat.
y_hat = tf.convert_to_tensor(np.array([[0.5, 1.5, 0.1],[2.2, 1.3, 1.7]]))
sess.run(y_hat)
# array([[ 0.5,  1.5,  0.1],
#        [ 2.2,  1.3,  1.7]])

Observe que os valores não são normalizados (ou seja, as linhas não somam 1). Para normalizá-los, podemos aplicar a função softmax, que interpreta a entrada como probabilidades de log não normalizadas (aka logits ) e gera probabilidades lineares normalizadas.

y_hat_softmax = tf.nn.softmax(y_hat)
sess.run(y_hat_softmax)
# array([[ 0.227863  ,  0.61939586,  0.15274114],
#        [ 0.49674623,  0.20196195,  0.30129182]])

É importante entender completamente o que a saída softmax está dizendo. Abaixo, mostrei uma tabela que representa mais claramente a saída acima. Pode-se observar que, por exemplo, a probabilidade de a instância de treinamento 1 ser "Classe 2" é 0,619. As probabilidades da classe para cada instância de treinamento são normalizadas, portanto, a soma de cada linha é 1,0.

                      Pr(Class 1)  Pr(Class 2)  Pr(Class 3)
                    ,--------------------------------------
Training instance 1 | 0.227863   | 0.61939586 | 0.15274114
Training instance 2 | 0.49674623 | 0.20196195 | 0.30129182

Portanto, agora temos probabilidades de classe para cada instância de treinamento, onde podemos usar o argmax () de cada linha para gerar uma classificação final. Acima, podemos gerar que a instância de treinamento 1 pertença à "Classe 2" e a instância de treinamento 2 pertença à "Classe 1".

Essas classificações estão corretas? Precisamos avaliar os rótulos verdadeiros do conjunto de treinamento. Você precisará de uma y_truematriz codificada de um ponto quente , onde novamente as linhas estão instâncias de treinamento e as colunas são classes. Abaixo, criei um exemplo y_truede matriz quente, onde o rótulo verdadeiro para a instância de treinamento 1 é "Classe 2" e o rótulo verdadeiro para a instância de treinamento 2 é "Classe 3".

y_true = tf.convert_to_tensor(np.array([[0.0, 1.0, 0.0],[0.0, 0.0, 1.0]]))
sess.run(y_true)
# array([[ 0.,  1.,  0.],
#        [ 0.,  0.,  1.]])

A distribuição de probabilidade está y_hat_softmaxpróxima da distribuição de probabilidade em y_true? Podemos usar a perda de entropia cruzada para medir o erro.

Fórmula para perda de entropia cruzada

Podemos calcular a perda de entropia cruzada em uma linha e ver os resultados. Abaixo, podemos ver que a instância de treinamento 1 tem uma perda de 0,479, enquanto a instância de treinamento 2 tem uma perda maior de 1.200. Esse resultado faz sentido porque, no exemplo acima, y_hat_softmaxmostrou que a maior probabilidade da instância de treinamento 1 era para "Classe 2", que corresponde à instância de treinamento 1 em y_true; no entanto, a previsão para a instância de treinamento 2 mostrou uma probabilidade mais alta para "Classe 1", que não corresponde à verdadeira classe "Classe 3".

loss_per_instance_1 = -tf.reduce_sum(y_true * tf.log(y_hat_softmax), reduction_indices=[1])
sess.run(loss_per_instance_1)
# array([ 0.4790107 ,  1.19967598])

O que realmente queremos é a perda total em todas as instâncias de treinamento. Para que possamos calcular:

total_loss_1 = tf.reduce_mean(-tf.reduce_sum(y_true * tf.log(y_hat_softmax), reduction_indices=[1]))
sess.run(total_loss_1)
# 0.83934333897877944

Usando softmax_cross_entropy_with_logits ()

Em vez disso, podemos calcular a perda total de entropia cruzada usando a tf.nn.softmax_cross_entropy_with_logits()função, como mostrado abaixo.

loss_per_instance_2 = tf.nn.softmax_cross_entropy_with_logits(y_hat, y_true)
sess.run(loss_per_instance_2)
# array([ 0.4790107 ,  1.19967598])

total_loss_2 = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(y_hat, y_true))
sess.run(total_loss_2)
# 0.83934333897877922

Observe que total_loss_1e total_loss_2produz resultados essencialmente equivalentes com algumas pequenas diferenças nos dígitos finais. No entanto, você também pode usar a segunda abordagem: leva menos uma linha de código e acumula menos erro numérico porque o softmax é feito para você dentro de softmax_cross_entropy_with_logits().

stackoverflowuser2010
fonte
Eu confirmo todas as opções acima. O código simples: M = tf.random.uniform([100, 10], minval=-1.0, maxval=1.0); labels = tf.one_hot(tf.random.uniform([100], minval=0, maxval=10 , dtype='int32'), 10); tf.nn.softmax_cross_entropy_with_logits(labels=labels, logits=M) - tf.reduce_sum(-tf.nn.log_softmax(M)*tf.one_hot(labels, 10), -1)retorna quase zero em todos os lugares
Sami A. Haija
51

tf.nn.softmaxcalcula a propagação direta através de uma camada softmax. Você o utiliza durante a avaliação do modelo ao calcular as probabilidades que o modelo gera.

tf.nn.softmax_cross_entropy_with_logitscalcula o custo de uma camada softmax. É usado apenas durante o treinamento .

Os logits são as probabilidades de log não normalizadas geradas pelo modelo (os valores gerados antes da normalização softmax ser aplicada a eles).

Ian Goodfellow
fonte
2
Entendi. Por que não chamar a função tf.nn.softmax_cross_entropy_sans_normalization?
auro
8
@auro porque normaliza os valores (internamente) durante o cálculo da entropia cruzada. O objetivo tf.nn.softmax_cross_entropy_with_logitsé avaliar quanto o modelo se desvia dos rótulos dourados, não para fornecer uma saída normalizada.
erickrf
11
No caso de usar tf.nn.sparse_softmax_cross_entropy_with_logits () calcula o custo de uma camada softmax esparsa e, portanto, deve ser usado apenas durante o treinamento, qual seria a alternativa ao executar o modelo em relação a novos dados, é possível obter probabilidades disso? 1.
SerialDev
2
@SerialDev, não é possível obter probabilidades tf.nn.sparse_softmax_cross_entropy_with_logits. Para obter probabilidades, use tf.nn.softmax.
Nandeesh
4

As respostas acima têm descrição suficiente para a pergunta feita.

Além disso, o Tensorflow otimizou a operação de aplicação da função de ativação e calculou o custo usando sua própria ativação, seguida pelas funções de custo. Portanto, é uma boa prática usar: tf.nn.softmax_cross_entropy()overtf.nn.softmax(); tf.nn.cross_entropy()

Você pode encontrar diferenças importantes entre eles em um modelo intensivo de recursos.

Abish
fonte
11
a resposta acima claramente não leu a pergunta .. Todos dizem as mesmas coisas, que são conhecidas, mas não responder a pergunta em si
Euler_Salter
@abhish Você quis dizer, tf.nn.softmaxseguido por tf.losses.softmax_cross_entropy?
Ankurrc 19/08/19
4

O que acontece softmaxé o logit, é o que J. Hinton repete nos vídeos do Coursera o tempo todo.

prosti
fonte
1

Resposta compatível com Tensorflow 2.0 : As explicações dgae stackoverflowuser2010são muito detalhadas sobre Logits e as funções relacionadas.

Todas essas funções, quando usadas Tensorflow 1.x, funcionarão bem, mas se você migrar seu código de 1.x (1.14, 1.15, etc)para 2.x (2.0, 2.1, etc..), usar essas funções resultará em erro.

Portanto, especificando as chamadas compatíveis com 2.0 para todas as funções, discutimos acima, se migrarmos 1.x to 2.x, para o benefício da comunidade.

Funções no 1.x :

  1. tf.nn.softmax
  2. tf.nn.softmax_cross_entropy_with_logits
  3. tf.nn.sparse_softmax_cross_entropy_with_logits

Funções respectivas quando migradas de 1.x para 2.x :

  1. tf.compat.v2.nn.softmax
  2. tf.compat.v2.nn.softmax_cross_entropy_with_logits
  3. tf.compat.v2.nn.sparse_softmax_cross_entropy_with_logits

Para obter mais informações sobre a migração de 1.x para 2.x, consulte este Guia de migração .

Suporte ao Tensorflow
fonte
0

Mais uma coisa que eu definitivamente gostaria de destacar como logit é apenas uma saída bruta, geralmente a saída da última camada. Este pode ser um valor negativo também. Se o usarmos como para a avaliação "entropia cruzada", conforme mencionado abaixo:

-tf.reduce_sum(y_true * tf.log(logits))

então não vai funcionar. Como log--ve não está definido. Portanto, o uso da ativação do softmax superará esse problema.

Este é o meu entendimento, por favor, corrija-me se estiver errado.

vipin bansal
fonte