Compreendendo os histogramas do TensorBoard (peso)

120

É muito simples ver e entender os valores escalares no TensorBoard. No entanto, não está claro como entender os gráficos de histograma.

Por exemplo, eles são os histogramas dos pesos da minha rede.

insira a descrição da imagem aqui

(Depois de consertar um bug graças ao sunside) insira a descrição da imagem aqui Qual é a melhor maneira de interpretar isso? Os pesos da camada 1 parecem quase planos, o que isso significa?

Eu adicionei o código de construção de rede aqui.

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
fonte
4
Acabei de notar que você não está usando as ativações na última camada. Você provavelmente quis dizer tf.nn.softmax(tf.matmul(layer3_act, W4)).
sol
@sunside Obrigado. Acontece que o histograma também é muito útil para depuração. Eu atualizei as fotos.
Cantada Kim em
1
@SungKim Estou usando sua implementação como referência, mas como você adiciona o viés? Como isso? B1 = tf.get_variable("B1", shape=[hidden_layer_neurons],initializer=tf.random_normal_initializer())e layer1_bias = tf.add(layer1, B1)etf.summary.histogram("bias", layer1_bias)
Gert Kommer
1
@SungKim se você ainda tiver o diretório de log, poderia enviá-lo para o Aughie Boards ? Seria ótimo ver os histogramas em um painel interativo
Agost Biro
@SungKim, você consertaria seu código definindo input_sizepara que possamos executá-lo e ver o resultado emtensorboard
Mario

Respostas:

131

Parece que a rede não aprendeu nada nas camadas um a três. A última camada muda, o que significa que pode haver algo errado com os gradientes (se você os alterar manualmente), você está restringindo o aprendizado à última camada otimizando apenas seus pesos ou a última camada realmente ' devora todo o erro. Também pode ser que apenas preconceitos sejam aprendidos. A rede parece aprender alguma coisa, mas pode não estar usando todo o seu potencial. Mais contexto seria necessário aqui, mas brincar com a taxa de aprendizagem (por exemplo, usando uma menor) pode valer a pena tentar.

Em geral, os histogramas exibem o número de ocorrências de um valor em relação a outros valores. Simplesmente falando, se os valores possíveis estão em uma faixa de 0..9e você vê um pico de quantidade 10no valor 0, isso significa que 10 entradas assumem o valor 0; em contraste, se o histograma mostrar um platô de 1para todos os valores de 0..9, significa que para 10 entradas, cada valor possível 0..9ocorre exatamente uma vez. Você também pode usar histogramas para visualizar as distribuições de probabilidade ao normalizar todos os valores do histograma por sua soma total; se você fizer isso, obterá intuitivamente a probabilidade com que um certo valor (no eixo x) aparecerá (em comparação com outras entradas).

Agora layer1/weights, o platô significa que:

  • a maioria dos pesos está na faixa de -0,15 a 0,15
  • é (principalmente) igualmente provável que um peso tenha qualquer um desses valores, ou seja, eles são (quase) uniformemente distribuídos

Dito de forma diferente, quase o mesmo número de pesos têm os valores -0.15, 0.0, 0.15e tudo entre elas. Existem alguns pesos com valores ligeiramente menores ou maiores. Resumindo, isso simplesmente parece que os pesos foram inicializados usando uma distribuição uniforme com média zero e intervalo de valores -0.15..0.15... mais ou menos. Se você realmente usa inicialização uniforme, isso é normal quando a rede ainda não foi treinada.

Em comparação, layer1/activationsforma uma curva em forma de sino (gaussiana): os valores são centralizados em torno de um valor específico, neste caso 0, mas também podem ser maiores ou menores do que isso (igualmente provável, pois é simétrico). A maioria dos valores aparecem próximos da média de 0, mas os valores variam de -0.8a 0.8. Presumo que layer1/activationsseja considerado a distribuição de todas as saídas da camada em um lote. Você pode ver que os valores mudam com o tempo.

O histograma da camada 4 não me diz nada específico. A partir da forma, é apenas mostrando que algum peso em torno de valores -0.1, 0.05e 0.25tendem a ser ocorrer com maior probabilidade; uma razão pode ser que diferentes partes de cada neurônio coletam as mesmas informações e são basicamente redundantes. Isso pode significar que você pode realmente usar uma rede menor ou que sua rede tem potencial para aprender mais recursos distintos para evitar overfitting. No entanto, essas são apenas suposições.

Além disso, como já declarado nos comentários abaixo, adicione unidades de polarização. Ao deixá-los de fora, você está forçando a restrição de sua rede a uma solução possivelmente inválida.

lado do sol
fonte
5
Não ter preconceito pode ser uma ideia muito ruim - é realmente como tentar desenhar uma linha através de uma nuvem de pontos (muito dimensionalmente elevada), mas ser forçado a passar pelo valor 0; pode funcionar e dar-lhe alguma solução, mas é provável que seja uma solução má ou simplesmente errada.
sol
1
Não posso dizer muito a partir do histograma, infelizmente. (Porém,
atualizei
1
Provavelmente deve treinar um pouco mais agora. Especialmente com seus primeiros resultados, layer4/Qpredparece que pode ficar muito melhor. Quanto aos pesos permanecerem os mesmos ... Acho isso suspeito, mas não consigo entender agora. Pode ser que seja realmente a distribuição correta, mas como não houve nenhuma mudança, acho isso difícil de acreditar.
sol de
1
@sunside existe algum método para priorizar a atualização dos pesos da rede sobre os vieses? Como os preconceitos, assim como a última camada, parecem sugar todo o erro. Estou tendo um problema semelhante, em que apenas as tendências são atualizadas e o histograma de peso permanece relativamente inalterado.
mamafoku
2
Não ter um viés está ok se usar a norma de lote antes da ativação
Tosha