Krótka wersja:
Załóżmy, że masz dwa tensory, w których y_hat
znajdują się obliczone wyniki dla każdej klasy (na przykład od y = W * x + b) i y_true
zawiera 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_hat
jako 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_hat
tablicę 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_true
tablicy, w której ponownie wiersze są instancjami szkoleniowymi, a kolumny klasami. Poniżej utworzyłem przykładową y_true
tablicę 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_softmax
zbliżony do rozkładu prawdopodobieństwa y_true
? Możemy zmierzyć błąd za pomocą utraty 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_softmax
pokazał, ż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_1
i total_loss_2
generuj 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()
.
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.