tf.layers.conv2d と tf.layers.dense のデフォルトのカーネルイニシャライザーは何ですか?

Tensorflow API の公式ドキュメントでは、tf.lays.conv2dtf.layers.dense のパラメータ kernel_initializer のデフォルトは None であるとされています。

しかし、layers tutorial (https://www.tensorflow.org/tutorials/layers) を読むと、このパラメータがコードに設定されていないことに気づきました。例えば

# Convolutional Layer #1
conv1 = tf.layers.conv2d(
    inputs=input_layer,
    filters=32,
    kernel_size=[5, 5],
    padding="same",
    activation=tf.nn.relu)

チュートリアルのサンプルコードは何のエラーもなく実行されるので、デフォルトの kernel_initializerNone ではないのだと思います。では、どのイニシャライザが使われているのでしょうか?

別のコードでは、conv2dとdenseレイヤーの kernel_initializer を設定しませんでしたが、すべてうまくいきました。しかし、kernel_initializertf.truncated_normal_initializer(stddev=0.1, dtype=tf.float32) をセットしようとすると、NaNエラーが発生しました。どうなっているのでしょうか?どなたか教えてください。

いい質問ですねー。調べるのはなかなかコツがいりますね!

  • ご覧の通り、tf.lays.conv2dにはドキュメントがありません。
  • 関数](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/layers/convolutional.py)の定義を見てみると、この関数は variable_scope.get_variable を呼び出していることがわかります。

コードでは

self.kernel = vs.get_variable('kernel',
                                  shape=kernel_shape,
                                  initializer=self.kernel_initializer,
                                  regularizer=self.kernel_regularizer,
                                  trainable=True,
                                  dtype=self.dtype)

次のステップ: イニシャライザが None のとき、変数スコープはどうなっているか

ここにはこう書いてあります。

initializer が None(デフォルト) の場合、コンストラクタで渡されたデフォルトのイニシャライザが使われます。 が使用されます。もし、これもNoneならば、新しい glorot_uniform_initializer を使用します。

つまり答えは、glorot_uniform_initializer を使うということです。

完全を期すために、このイニシャライザーの定義を示します。

Glorot uniform initializer, Xavier uniform initializerとも呼ばれます。 これは、一様分布から [-limit, limit] の範囲内でサンプルを取得します。 ここで, limitsqrt(6 / (fan_in + fan_out)) です. ここで、 fan_in はウェイトテンソルの入力ユニット数 であり、fan_out はウェイトテンソルの出力ユニット数である。 参考:http://jmlr.org/proceedings/papers/v9/glorot10a/glorot10a.pdf

編集:これは私がコードとドキュメントで見つけたものです。おそらく、重みに対してevalを実行することで、初期化がこのように見えることを確認することができるだろう

解説 (1)

Andrew Ng氏の[本講座](https://www.youtube.com/watch?v=s2coXdufOzE)やXavierドキュメントによると、活性化関数としてReLUを使っている場合、デフォルトの重みの初期化子(*Xavier uniform)をXavier normal**に変更した方が良いそうです。

y = tf.layers.conv2d(x, kernel_initializer=tf.contrib.layers.xavier_initializer(uniform=False), )
解説 (0)