2015-11-10 38 views
15

że patrzy na Tensorflow MNIST example for beginners i stwierdzono, że w tej części:Dlaczego przykład TensorFlow kończy się niepowodzeniem podczas zwiększania wielkości partii?

for i in range(1000): 
    batch_xs, batch_ys = mnist.train.next_batch(100) 
    sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys}) 

zmieniając wielkość wsadu od 100 powinna być wyższa niż 204 powoduje, że model nie są zbieżne. Działa do 204, ale przy 205 i dowolnej większej liczbie próbowałem, dokładność wyniesie < 10%. Czy to błąd, coś o algorytmie, coś innego?

To jest ich instalacja binarna dla OS X, wydaje się być wersja 0.5.0.

+0

W przypadku jesteś cierpi z tego samego błędu jak ja zrobiłeś, możesz chcieć tot sprawdzić tutaj: http://stackoverflow.com/questions/33712178/tensorflow-nan-bug – user1111929

Odpowiedz

28

Używasz bardzo podstawowego modelu liniowego w przykładzie dla początkujących?

Oto sztuczka do debugowania - oglądać przekrój entropii jak zwiększyć wielkość wsadu (pierwsza linia jest na przykładzie, drugi właśnie dodane):

cross_entropy = -tf.reduce_sum(y_*tf.log(y)) 
cross_entropy = tf.Print(cross_entropy, [cross_entropy], "CrossE") 

przy wielkości partii 204, zobaczysz:

I tensorflow/core/kernels/logging_ops.cc:64] CrossE[92.37558] 
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[90.107414] 

Ale na 205 zobaczysz sekwencję jak to od początku:

I tensorflow/core/kernels/logging_ops.cc:64] CrossE[472.02966] 
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[475.11697] 
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[1418.6655] 
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[1546.3833] 
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[1684.2932] 
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[1420.02] 
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[1796.0872] 
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[nan] 

Ack - pojawia się NaN. Zasadniczo, duży rozmiar partii tworzy tak duży gradient, że twój model wymyka się spod kontroli - aktualizacje, które stosują, są zbyt duże i przekraczają kierunek, w którym powinny iść ogromnym marginesem.

W praktyce istnieje kilka sposobów, aby to naprawić. Można zmniejszyć szybkość uczenia się z .01 do, powiedzmy, 0.005, co daje ostateczną dokładność 0,92.

train_step = tf.train.GradientDescentOptimizer(0.005).minimize(cross_entropy) 

Albo można użyć bardziej skomplikowany algorytm (Adam, Momentum, itp), optymalizacji, który stara się zrobić więcej, aby zorientować się w kierunku gradientu. Lub możesz użyć bardziej złożonego modelu, który ma więcej darmowych parametrów, dzięki którym można rozproszyć ten duży gradient.

15

@dga dała świetną odpowiedź, ale chciałem trochę rozszerzyć.

Kiedy pisał poradnik początkujących zaimplementowałem funkcja kosztu tak:

cross_entropy = -tf.reduce_sum (Y_ tf.log * (Y))

to pisałem w ten sposób, ponieważ wygląda to podobnie do matematycznej definicji cross-entropii. Ale może rzeczywiście lepiej byłoby zrobić coś takiego:

cross_entropy = -tf.reduce_mean (Y_ * tf.log (y))

Dlaczego to może być ładniejszy użyć zamiast średniej sumy? Cóż, jeśli sumujemy, to podwojenie wielkości partii podwaja koszt, a także podwaja wartość gradientu. Dopóki nie dostosujemy naszego wskaźnika uczenia się (lub nie zastosujemy algorytmu, który dostosuje go do nas, tak jak zasugerował @dga), nasze treningi wybuchną! Ale jeśli używamy średniej, to nasza szybkość uczenia się staje się jakby niezależna od wielkości partii, co jest miłe.

Zachęcam do zapoznania się z Adamem (tf.train.AdamOptimizer()). Często jest bardziej tolerancyjny na błądzenie rzeczami niż SGD.

+0

Ale to nie zmienia całej rzeczy, którą próbujemy zoptymalizować. Przy wartościach "[1, 72, 5]" różnica jest dość znacząca. –

+1

'sum' podaje liczbę bitów/goli/cyfr potrzebnych do zakodowania wszystkich danych. Podając średnią dla wszystkich przykładów, podaje średnią liczbę bitów wymaganych na przykład. Ale powyższa wersja przejmuje średnią z obu wymiarów. Nieprzeszkolony (nieopierzony) model MNIST powinien, nie nieoczekiwanie, wymagać 1 cyfry na cyfrę lub 'log (10) ~ = 2,3' gów na cyfrę. Zmień go na log10, jeśli chcesz go wpisać cyframi. Jeśli chcesz zachować fizyczne znaczenie, użyj 'cost = -tf.reduce_mean (tf.reduce_sum (self.y_ * tf.log (self.y), 1))'. czyli: 'suma' na różnych klasach, 'średnia' powyżej pozycji. – mdaoust

2

@dga dobrze wytłumaczył ci powód takiego zachowania (cross_entropy staje się zbyt duży), a zatem algorytm nie będzie w stanie się zjednoczyć. Istnieje kilka sposobów, aby to naprawić. Zasugerował już, aby zmniejszyć tempo uczenia się.

Pochodzenie gradientowe jest najbardziej podstawowym algorytmem. Prawie wszystkie inne optimizers będzie pracować prawidłowo:

train_step = tf.train.AdagradOptimizer(0.01).minimize(cross_entropy) 
train_step = tf.train.AdamOptimizer().minimize(cross_entropy) 
train_step = tf.train.FtrlOptimizer(0.01).minimize(cross_entropy) 
train_step = tf.train.RMSPropOptimizer(0.01, 0.1).minimize(cross_entropy) 

Innym podejściem jest użycie tf.nn.softmax_cross_entropy_with_logits który obsługuje niestabilności numerycznych.

15

Nan występuje, gdy 0 * log (0) występuje:

wymienić:

cross_entropy = -tf.reduce_sum(y_*tf.log(y)) 

z:

cross_entropy = -tf.reduce_sum(y_*tf.log(y + 1e-10)) 
+0

Wszelkie informacje na temat tego, co się wydarzyło, będą pomocne. – turtle

+0

@turtle '1e-10' jest tylko małym określeniem, aby uniknąć niestabilności liczbowej logu gdy y = 0 – Conchylicultor

Powiązane problemy