1. ホーム
  2. tensorflow

[解決済み] TensorBoardの(重み)ヒストグラムを理解する

2022-04-28 12:12:53

質問

TensorBoardでスカラー値を見て理解するのは本当に簡単です。しかし、ヒストグラムのグラフをどのように理解すればよいのかがよくわからない。

例えば、私のネットワークの重みのヒストグラムです。

(sunsideのおかげでバグを修正した後) これらをどのように解釈すればよいのでしょうか。レイヤー1のウェイトはほとんど平坦に見えますが、これはどういう意味でしょうか?

ここにネットワーク構築コードを追加しました。

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)

解決方法は?

1層目から3層目までは、ネットワークが何も学習していないようです。最後の層は変化しているので、勾配に何か問題があるか(手動でいじっている場合)、重みだけを最適化して学習を最後の層に制約しているか、最後の層が本当にすべての誤差を「食い尽くして」いるかのいずれかであることがわかります。また、バイアスのみを学習している可能性もある。ネットワークは何かを学習しているように見えるが、その潜在能力をフルに発揮していない可能性がある。より多くの文脈が必要ですが、学習率を弄って(例えば、より小さいものを使って)試してみる価値があるかもしれません。

一般に、ヒストグラムは、ある値の出現回数を他の値との相対的な関係で表示します。簡単に言えば、取り得る値が以下の範囲にある場合、ヒストグラムはその値を表示します。 0..9 という量のスパイクが表示されます。 10 の値で 0 ということは、10個の入力が値 0 これに対して、ヒストグラムのプラトーが 1 のすべての値に対して 0..9 ということは、10個の入力に対して、それぞれの可能な値 0..9 が発生します。 まさに 回です。 また、ヒストグラムの値をすべて総和で正規化すると、確率分布を視覚化することができます。そうすると、ある値(x軸)が(他の入力と比較して)現れる可能性が直感的に得られます。

では、次に layer1/weights , プラトーはそれを意味します。

  • ほとんどのウェイトが-0.15から0.15の範囲にある。
  • ある重みがこれらの値のいずれかを持つ可能性は(ほぼ)等しく、つまり(ほぼ)一様に分布している。

逆に言えば、ほぼ同数のウェイトが次のような値を持つことになります。 -0.15 , 0.0 , 0.15 とその間にあるもの全てです。ウェイトの値が若干小さかったり大きかったりするものもあります。 つまり、これは単純に平均がゼロで値の範囲が広い一様分布を使って重みを初期化したように見えるのです -0.15..0.15 ...程度のものです。もし本当に一様な初期化を使っているのなら、これはネットワークがまだ訓練されていないときの典型的な例です。

それに比べて layer1/activations はベルカーブ(ガウシアン)のような形状になります。値は特定の値を中心としており、この場合は 0 しかし、それよりも大きいことも小さいこともある(対称的であるため、同じように大きい可能性がある)。ほとんどの値は 0 しかし、値は -0.8 から 0.8 . 私は layer1/activations は、バッチ内のすべてのレイヤー出力に対する分布としてとらえる。時間の経過とともに値が変化しているのがわかると思います。

レイヤー4のヒストグラムは、特に何もわかりません。形状から、いくつかの重み値が -0.1 , 0.050.25 は高い確率で発生する傾向があります。 かもしれない というのも、各ニューロンの異なる部分が実際には同じ情報を拾っており、基本的に冗長だからです。これは、より小さなネットワークを使うことができる、あるいは、オーバーフィッティングを防ぐために、ネットワークがより特徴的な機能を学習する可能性があることを意味します。ただし、これらはあくまで仮定にすぎません。

また、下のコメントにもあるように、バイアスユニットを追加してください。バイアスユニットを入れないと、ネットワークに強制的に制約を加えてしまい、無効な解になる可能性があります。