Zrozumienie histogramów TensorBoard (wagi)

120

Naprawdę łatwo jest zobaczyć i zrozumieć wartości skalarne w TensorBoard. Jednak nie jest jasne, jak rozumieć wykresy histogramów.

Na przykład są to histogramy moich wag sieci.

wprowadź opis obrazu tutaj

(Po naprawieniu błędu dzięki Sunside) wprowadź opis obrazu tutaj Jak najlepiej je zinterpretować? Obciążniki warstwy 1 wyglądają w większości na płaskie, co to oznacza?

Dodałem tutaj kod budowy sieci.

X = tf.placeholder(tf.float32, [None, input_size], name="input_x")
x_image = tf.reshape(X, [-1, 6, 10, 1])
tf.summary.image('input', x_image, 4)

# First layer of weights
with tf.name_scope("layer1"):
    W1 = tf.get_variable("W1", shape=[input_size, hidden_layer_neurons],
                         initializer=tf.contrib.layers.xavier_initializer())
    layer1 = tf.matmul(X, W1)
    layer1_act = tf.nn.tanh(layer1)
    tf.summary.histogram("weights", W1)
    tf.summary.histogram("layer", layer1)
    tf.summary.histogram("activations", layer1_act)

# Second layer of weights
with tf.name_scope("layer2"):
    W2 = tf.get_variable("W2", shape=[hidden_layer_neurons, hidden_layer_neurons],
                         initializer=tf.contrib.layers.xavier_initializer())
    layer2 = tf.matmul(layer1_act, W2)
    layer2_act = tf.nn.tanh(layer2)
    tf.summary.histogram("weights", W2)
    tf.summary.histogram("layer", layer2)
    tf.summary.histogram("activations", layer2_act)

# Third layer of weights
with tf.name_scope("layer3"):
    W3 = tf.get_variable("W3", shape=[hidden_layer_neurons, hidden_layer_neurons],
                         initializer=tf.contrib.layers.xavier_initializer())
    layer3 = tf.matmul(layer2_act, W3)
    layer3_act = tf.nn.tanh(layer3)

    tf.summary.histogram("weights", W3)
    tf.summary.histogram("layer", layer3)
    tf.summary.histogram("activations", layer3_act)

# Fourth layer of weights
with tf.name_scope("layer4"):
    W4 = tf.get_variable("W4", shape=[hidden_layer_neurons, output_size],
                         initializer=tf.contrib.layers.xavier_initializer())
    Qpred = tf.nn.softmax(tf.matmul(layer3_act, W4)) # Bug fixed: Qpred = tf.nn.softmax(tf.matmul(layer3, W4))
    tf.summary.histogram("weights", W4)
    tf.summary.histogram("Qpred", Qpred)

# We need to define the parts of the network needed for learning a policy
Y = tf.placeholder(tf.float32, [None, output_size], name="input_y")
advantages = tf.placeholder(tf.float32, name="reward_signal")

# Loss function
# Sum (Ai*logp(yi|xi))
log_lik = -Y * tf.log(Qpred)
loss = tf.reduce_mean(tf.reduce_sum(log_lik * advantages, axis=1))
tf.summary.scalar("Q", tf.reduce_mean(Qpred))
tf.summary.scalar("Y", tf.reduce_mean(Y))
tf.summary.scalar("log_likelihood", tf.reduce_mean(log_lik))
tf.summary.scalar("loss", loss)

# Learning
train = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(loss)
Sung Kim
źródło
4
Właśnie zauważyłem, że w ogóle nie używasz aktywacji na ostatniej warstwie. Prawdopodobnie miałeś na myśli tf.nn.softmax(tf.matmul(layer3_act, W4)).
Sunside
@sunside Thanks. Okazuje się, że histogram jest również bardzo przydatny do debugowania. Zaktualizowałem fotki.
Sung Kim
1
@SungKim Używam twojej implementacji jako odniesienia, ale jak dodać odchylenie? Lubię to? B1 = tf.get_variable("B1", shape=[hidden_layer_neurons],initializer=tf.random_normal_initializer())i layer1_bias = tf.add(layer1, B1)itf.summary.histogram("bias", layer1_bias)
Gert Kommer
1
@SungKim, jeśli nadal masz katalog dziennika, czy możesz przesłać go do Aughie Boards ? Byłoby wspaniale zobaczyć histogramy na interaktywnym pulpicie nawigacyjnym
Agost Biro
@SungKim, czy naprawiłbyś swój kod, definiując go input_sizetak, abyśmy mogli go uruchomić i zobaczyć wyniktensorboard
Mario,

Odpowiedzi:

131

Wygląda na to, że sieć nie nauczyła się niczego w warstwach od pierwszej do trzeciej. Ostatnia warstwa się zmienia, więc oznacza to, że albo coś może być nie tak z gradientami (jeśli manipulujesz nimi ręcznie), ograniczasz naukę do ostatniej warstwy, optymalizując tylko jej wagi lub naprawdę ostatnią warstwę. zjada wszystkie błędy. Może się również zdarzyć, że uczy się tylko uprzedzeń. Wydaje się, że sieć czegoś się uczy, ale może nie wykorzystywać swojego pełnego potencjału. Potrzebny byłby tutaj szerszy kontekst, ale warto spróbować wykorzystać współczynnik uczenia się (np. Używając mniejszego).

Ogólnie histogramy pokazują liczbę wystąpień wartości względem siebie nawzajem. Mówiąc najprościej, jeśli możliwe wartości mieszczą się w zakresie 0..9i widzisz skokowy wzrost 10wartości 0, oznacza to, że 10 danych wejściowych przyjmuje wartość 0; Natomiast jeśli histogram pokazuje plateau 1dla wszystkich wartości 0..9, oznacza to, że dla 10 wejść każda możliwa wartość 0..9występuje dokładnie raz. Możesz także użyć histogramów do wizualizacji rozkładów prawdopodobieństwa, gdy normalizujesz wszystkie wartości histogramów według ich całkowitej sumy; jeśli to zrobisz, intuicyjnie uzyskasz prawdopodobieństwo, z jakim pojawi się określona wartość (na osi x) (w porównaniu z innymi danymi wejściowymi).

Teraz layer1/weightspłaskowyż oznacza, że:

  • większość wag mieści się w zakresie od -0,15 do 0,15
  • jest (przeważnie) równie prawdopodobne, że waga będzie miała którąkolwiek z tych wartości, tj. są one (prawie) równomiernie rozłożone

Powiedział inaczej, prawie taką samą liczbę ciężarków mają znaczenia -0.15, 0.0, 0.15i wszystko pomiędzy. Niektóre wagi mają nieco mniejsze lub wyższe wartości. Krótko mówiąc, wygląda to tak, jakby wagi zostały zainicjowane przy użyciu jednolitego rozkładu z zerową średnią i zakresem wartości -0.15..0.15... dawaj lub bierz. Jeśli rzeczywiście używasz jednolitej inicjalizacji, jest to typowe, gdy sieć nie została jeszcze przeszkolona.

Dla porównania, layer1/activationstworzy krzywą dzwonową (gaussa): w tym przypadku wartości są wyśrodkowane wokół określonej wartości 0, ale mogą być również większe lub mniejsze (równie prawdopodobne, ponieważ są symetryczne). Większość wartości jest zbliżona do średniej wartości 0, ale wartości mieszczą się w zakresie od -0.8do 0.8. Zakładam, że layer1/activationsjest to rozkład na wszystkie wyjścia warstwy w partii. Widać, że wartości zmieniają się w czasie.

Histogram warstwy 4 nie mówi mi nic konkretnego. Od kształtu, to tylko pokazuje, że niektóre wartości wagi wokół -0.1, 0.05i 0.25wydają się być występować z większym prawdopodobieństwem; powodem może być to, że różne części każdego neuronu w rzeczywistości pobierają te same informacje i są w zasadzie zbędne. Może to oznaczać, że możesz faktycznie korzystać z mniejszej sieci lub że Twoja sieć ma potencjał uczenia się większej liczby wyróżniających cech, aby zapobiec nadmiernemu dopasowaniu. To jednak tylko przypuszczenia.

Ponadto, jak już stwierdzono w komentarzach poniżej, należy dodać jednostki odchylenia. Pomijając je, na siłę ograniczasz swoją sieć do potencjalnie nieprawidłowego rozwiązania.

Sunside
źródło
5
Brak odchylenia w ogóle może być bardzo złym pomysłem - to tak naprawdę jak próba narysowania linii przez (bardzo wielowymiarową) chmurę punktów, ale zmuszenie do przejścia przez wartość 0; może zadziałać i da ci jakieś rozwiązanie, ale są szanse, że jest to złe lub po prostu niewłaściwe.
Sunside
1
Niestety nie mogę powiedzieć wiele z histogramu. (Zaktualizowałem jednak moją odpowiedź.)
Sunside
1
Powinien teraz prawdopodobnie trenować trochę dłużej. Zwłaszcza biorąc pod uwagę twoje pierwsze wyniki, layer4/Qpredwygląda na to, że może być znacznie lepiej. Jeśli chodzi o obciążenia, które pozostają takie same ... Uważam, że to podejrzane, ale nie mogę teraz tego zrozumieć. Możliwe, że to naprawdę jest poprawna dystrybucja, ale biorąc pod uwagę, że nie ma żadnej zmiany, trudno mi w to uwierzyć.
Sunside
1
@sunside czy jest jakaś metoda nadawania priorytetu aktualizacji wagi sieci nad uprzedzeniami? Ponieważ uprzedzenia, a także ostatnia warstwa wydają się wysysać cały błąd. Mam podobny problem, w którym aktualizowane są tylko odchylenia, a histogram wagi pozostaje stosunkowo niezmieniony.
mamafoku
2
Brak odchylenia jest w porządku, jeśli używasz normy wsadowej przed aktywacją
Tosha