Co to są logity, softmax i softmax_cross_entropy_with_logits?

350

Przeglądałem tutaj dokumenty API interfejsu tensorflow . W dokumentacji tensorflow używali słowa kluczowego o nazwie logits. Co to jest? W wielu metodach w dokumentach API jest tak napisane

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

Jeśli to, co jest napisane, to logitstylko Tensors, po co zachować inną nazwę logits?

Kolejną rzeczą jest to, że istnieją dwie metody, których nie potrafiłem odróżnić. Byli

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

Jakie są między nimi różnice? Dokumenty nie są dla mnie jasne. Wiem co tf.nn.softmaxrobi. Ale nie ten drugi. Przykład będzie naprawdę pomocny.

Shubhashis
źródło

Odpowiedzi:

426

Logity po prostu oznaczają, że funkcja działa na nieskalowanym wyjściu wcześniejszych warstw i że względna skala dla zrozumienia jednostek jest liniowa. Oznacza to w szczególności, że suma danych wejściowych może nie być równa 1, że wartości nie są prawdopodobieństwami (możesz mieć wartość wejściową 5).

tf.nn.softmaxdaje tylko wynik zastosowania funkcji softmax do tensora wejściowego. Softmax „wyciska” dane wejściowe, tak że sum(input) = 1: jest to sposób na normalizację. Kształt wyjścia softmax jest taki sam jak wejście: po prostu normalizuje wartości. Wyniki softmax można interpretować jako prawdopodobieństwa.

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

Natomiast tf.nn.softmax_cross_entropy_with_logitsoblicza entropię krzyżową wyniku po zastosowaniu funkcji softmax (ale robi to wszystko razem w bardziej matematycznie ostrożny sposób). Jest podobny do wyniku:

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

Entropia krzyżowa jest metryką podsumowującą: sumuje się między elementami. Wyjście tensora tf.nn.softmax_cross_entropy_with_logitskształtu [2,5]ma kształt [2,1](pierwszy wymiar jest traktowany jako partia).

Jeśli chcesz przeprowadzić optymalizację w celu zminimalizowania entropii krzyżowej ORAZ chcesz zmiękczyć po ostatniej warstwie, powinieneś użyć tf.nn.softmax_cross_entropy_with_logitszamiast robić to sam, ponieważ obejmuje matematycznie niestabilne liczbowo przypadki narożników. W przeciwnym razie hakujesz go, dodając tu i ówdzie małe epsilony.

Edytowano 2016-02-07: Jeśli masz etykiety jednoklasowe, w których obiekt może należeć tylko do jednej klasy, możesz teraz rozważyć użycie tf.nn.sparse_softmax_cross_entropy_with_logits, aby nie trzeba było konwertować etykiet na gęstą tablicę jednogrzbietową. Ta funkcja została dodana po wersji 0.6.0.

dga
źródło
1
O softmax_cross_entropy_with_logits nie wiem, czy używam go poprawnie. Wynik nie jest tak stabilny w moim kodzie. Ten sam kod działa dwa razy, całkowita dokładność zmienia się z 0,6 na 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). Ale kiedy używam innego sposobu, 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))wynik jest stabilny i lepszy.
Rida,
15
Jesteś podwójnie miękki w pierwszej linii. softmax_cross_entropy_with_logits oczekuje nieskalowanych logów, a nie wyników tf.nn.softmax. Po prostu chcesz tf.nn.softmax_cross_entropy_with_logits(tf.add(tf.matmul(x, W, b))w swoim przypadku.
dga
7
@dga Myślę, że masz literówkę w kodzie, bmusi znajdować się poza tf.nn.softmax_cross_entropy_with_logits(tf.add(tf.matmul(x, W), b)
nawiasami
1
co oznacza, że ​​„skala względna dla zrozumienia jednostek jest liniowa”. część twojego pierwszego zdania oznacza?
Charlie Parker
5
Pozytywne - ale twoja odpowiedź jest nieco niepoprawna, gdy mówisz, że „kształt wyniku softmax jest taki sam jak danych wejściowych - po prostu normalizuje wartości”. Softmax nie tylko „wyciska” wartości, aby ich suma była równa 1. To także redystrybuuje je, i jest to prawdopodobnie główny powód, dla którego jest używany. Zobacz stackoverflow.com/questions/17187507/… , szczególnie odpowiedź Piotra Czapli.
Paolo Perrotta
282

Krótka wersja:

Załóżmy, że masz dwa tensory, w których y_hatznajdują się obliczone wyniki dla każdej klasy (na przykład od y = W * x + b) i y_truezawiera zakodowane na gorąco prawdziwe etykiety.

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

Jeśli interpretujesz wyniki y_hatjako nietypowe prawdopodobieństwa dziennika, wówczas są to logity .

Dodatkowo łączna strata entropijna obliczona w ten sposób:

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

jest zasadniczo równoważny całkowitej stracie entropijnej obliczonej z funkcją softmax_cross_entropy_with_logits():

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

Długa wersja:

W warstwie wyjściowej sieci neuronowej prawdopodobnie obliczysz tablicę, która zawiera wyniki klas dla każdego z twoich wystąpień treningowych, na przykład z obliczeń y_hat = W*x + b. Aby służyć jako przykład, poniżej stworzyłem y_hattablicę 2 x 3, w której wiersze odpowiadają instancjom szkoleniowym, a kolumny odpowiadają klasom. Tak więc tutaj są 2 instancje treningowe i 3 klasy.

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

Zauważ, że wartości nie są znormalizowane (tzn. Wiersze nie sumują się do 1). Aby je znormalizować, możemy zastosować funkcję softmax, która interpretuje dane wejściowe jako nietypowe prawdopodobieństwa dziennika (aka logity ) i generuje znormalizowane prawdopodobieństwo liniowe.

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

Ważne jest, aby w pełni zrozumieć, co mówi wyjście softmax. Poniżej pokazałem tabelę, która wyraźniej przedstawia powyższy wynik. Można zauważyć, że na przykład prawdopodobieństwo, że instancja treningowa 1 będzie „klasą 2”, wynosi 0,619. Prawdopodobieństwa klasowe dla każdej instancji treningowej są znormalizowane, więc suma każdego wiersza wynosi 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

Mamy teraz prawdopodobieństwa klasowe dla każdej instancji treningowej, gdzie możemy pobrać argmax () każdego wiersza, aby wygenerować ostateczną klasyfikację. Z góry możemy wygenerować, że instancja treningowa 1 należy do „klasy 2”, a instancja treningowa 2 należy do „klasy 1”.

Czy te klasyfikacje są prawidłowe? Musimy zmierzyć się z prawdziwymi etykietami z zestawu treningowego. Będziesz potrzebował zakodowanej na gorąco y_truetablicy, w której ponownie wiersze są instancjami szkoleniowymi, a kolumny klasami. Poniżej utworzyłem przykładową y_truetablicę z jednym rozgrzaniem, w której prawdziwa etykieta dla instancji szkoleniowej 1 to „Klasa 2”, a prawdziwa etykieta dla instancji szkoleniowej 2 to „Klasa 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.]])

Czy rozkład prawdopodobieństwa jest y_hat_softmaxzbliżony do rozkładu prawdopodobieństwa y_true? Możemy zmierzyć błąd za pomocą utraty entropii krzyżowej .

Wzór na utratę entropii krzyżowej

Możemy obliczyć stratę między entropią na podstawie rzędów i zobaczyć wyniki. Poniżej widzimy, że instancja treningowa 1 straciła 0,479, a instancja treningowa 2 straciła 1,200. Ten wynik ma sens, ponieważ w naszym powyższym przykładzie y_hat_softmaxpokazał, że największe prawdopodobieństwo wystąpienia szkolenia 1 dotyczyło „klasy 2”, co odpowiada wystąpieniu szkolenia 1 y_true; jednak przewidywanie dla przypadku treningowego 2 wykazało najwyższe prawdopodobieństwo dla „klasy 1”, która nie pasuje do prawdziwej klasy „klasy 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])

To, czego naprawdę chcemy, to całkowita strata we wszystkich instancjach treningowych. Możemy więc obliczyć:

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

Korzystanie z softmax_cross_entropy_with_logits ()

Zamiast tego możemy obliczyć całkowitą utratę entropii krzyżowej za pomocą tf.nn.softmax_cross_entropy_with_logits()funkcji, jak pokazano poniżej.

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

Zauważ, że total_loss_1i total_loss_2generuj zasadniczo równoważne wyniki z pewnymi niewielkimi różnicami w końcowych cyfrach. Jednak równie dobrze możesz zastosować drugie podejście: wymaga ono o jeden mniej wiersza kodu i kumuluje mniej błędu numerycznego, ponieważ softmax jest wykonywany dla Ciebie wewnątrz softmax_cross_entropy_with_logits().

stackoverflowuser2010
źródło
Potwierdzam wszystkie powyższe. W prosty kod: 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)powraca blisko do zera wszędzie
Sami A. Haija
51

tf.nn.softmaxoblicza propagację do przodu przez warstwę softmax. Używasz go podczas oceny modelu, gdy obliczasz prawdopodobieństwa, które daje model.

tf.nn.softmax_cross_entropy_with_logitsoblicza koszt warstwy softmax. Jest używany tylko podczas treningu .

Logity są niezormalizowanymi prawdopodobieństwami logarytmicznymi wyjściowymi dla modelu (wartości wyjściowe przed zastosowaniem do nich normalizacji softmax).

Ian Goodfellow
źródło
2
Rozumiem. Dlaczego nie wywołać funkcji tf.nn.softmax_cross_entropy_sans_normalization?
auro
8
@auro, ponieważ normalizuje wartości (wewnętrznie) podczas obliczania między entropiami. Chodzi o tf.nn.softmax_cross_entropy_with_logitsocenę, jak bardzo model odbiega od złotych etykiet, a nie o znormalizowaną wydajność.
erickrf
1
W przypadku użycia tf.nn.sparse_softmax_cross_entropy_with_logits () oblicza koszt rzadkiej warstwy softmax, a zatem powinien być używany tylko podczas szkolenia, jaka byłaby alternatywa podczas uruchamiania modelu z nowymi danymi, czy można uzyskać z tego prawdopodobieństwa jeden.
SerialDev
2
@SerialDev, nie można uzyskać prawdopodobieństwa tf.nn.sparse_softmax_cross_entropy_with_logits. Aby uzyskać prawdopodobieństwa, użyj tf.nn.softmax.
Nandeesh
4

Powyższe odpowiedzi mają wystarczający opis dla zadanego pytania.

Ponadto Tensorflow zoptymalizował operację zastosowania funkcji aktywacji, a następnie obliczenie kosztów za pomocą własnej aktywacji, a następnie funkcji kosztów. Dlatego dobrą praktyką jest stosowanie: tf.nn.softmax_cross_entropy()ponadtf.nn.softmax(); tf.nn.cross_entropy()

Widać wyraźną różnicę między nimi w modelu wymagającym dużych zasobów.

Abisz
źródło
1
powyższa odpowiedź wyraźnie nie przeczytała pytania. Wszyscy mówią te same rzeczy, które są znane, ale nie odpowiadają na samo pytanie
Euler_Salter
@abhish Czy chodziło Ci o, tf.nn.softmaxa następnie tf.losses.softmax_cross_entropy?
ankurrc,
4

softmaxLogit zawsze powtarza to, co J. Hinton cały czas powtarza w filmach z Coursera.

prosti
źródło
1

Odpowiedź zgodna z Tensorflow 2.0 : Objaśnienia dgaistackoverflowuser2010 szczegółowe informacje na temat Logitów i powiązanych funkcji.

Wszystkie te funkcje, jeśli są używane w, Tensorflow 1.xbędą działały poprawnie, ale jeśli migrujesz swój kod z 1.x (1.14, 1.15, etc)do2.x (2.0, 2.1, etc..) za pomocą tych funkcji powodują błędu.

Dlatego też określając wywołania zgodne z wersją 2.0 dla wszystkich funkcji, które omówiliśmy powyżej, jeśli przeprowadzamy migrację 1.x to 2.x, z korzyścią dla społeczności.

Funkcje w 1.x :

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

Odpowiednie funkcje po migracji z wersji 1.x do wersji 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

Aby uzyskać więcej informacji na temat migracji z wersji 1.x do wersji 2.x, zapoznaj się z niniejszym przewodnikiem migracji .

Obsługa Tensorflow
źródło
0

Jeszcze jedna rzecz, którą zdecydowanie chciałbym podkreślić, ponieważ logit jest tylko surowym wyjściem, ogólnie wyjściem ostatniej warstwy. Może to być również wartość ujemna. Jeśli użyjemy go tak, jak to jest do oceny „entropii krzyżowej”, jak wspomniano poniżej:

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

to nie zadziała. Ponieważ log -ve nie jest zdefiniowany. Tak więc użycie aktywacji softmax rozwiąże ten problem.

Tak rozumiem, popraw mnie, jeśli się mylę.

vipin bansal
źródło