きっかけ
最近CNNを色々勉強して試していて,batch normalizationに手を出し始めたのですが,どうやらtf.nn.batch_normalizationで必要な平均と分散の計算にあたってtf.nn.momentsなる関数が使われることが多いようです.
結論を言うとtf.nn.momentsとは平均と分散を返すだったのですが,(おそらく当たり前すぎて) 説明が全然見当たらなかったのでメモ.
モーメント (積率) とは?
(素人なので間違っているかも.その場合はご指摘いただければと思います)
文脈や分野によって意味が違うようですが,確率論においては平均や分散が,つまり,
$Var(X) = E((X -\mu)^2)$
$E(X) = E((X - 0)^1)$
みたいに,「『Xから定数を引いたもの』のn乗の期待値」のかたちで表されるものがモーメントと定義されるそうです.nが1だったら1次のモーメント.2だったら2次のモーメント.
また,「(平均のように) 定数部分が0であるn次のモーメント」,つまり,「n乗した値の期待値$E(X^n)$」を,$m_n$と表したり$\mu'_n$と表したりします.これらは,「原点のまわりのn次のモーメント」と呼ばれるそうです.
さらに,「(分散のように) 定数部分が平均値であるn次のモーメント」,つまり,「平均との差のn乗の期待値$E((X - \mu)^n)$を$\mu_n$と表します.これらは,「平均のまわりのn次のモーメント」と呼ばれるそうです (参考: 分布をまとめる − 平均と分散).
tf.nn.momentsにおけるモーメント
…モーメントをわざわざ説明しといて何なんですが,公式曰く,
Calculate the mean and variance of x.
とのこと.定数や次数をわざわざ自前で設定するようにはできてないようです (平均とか分散とか以外の用途でmomentsを使う必要がそもそも無いのかな?).
なので,返す値は (1次のモーメント, 2次のモーメント) = (平均, 分散) になります.例えば,
import tensorflow as tf
import numpy as np
arr = np.array([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
], dtype=np.float32)
x = tf.constant(arr)
で2次元配列xを作っておいて,momentsを計算すると,
moments = tf.nn.moments(x, [0]) # 1次 (行方向) に圧縮
with tf.Session() as sess:
m, e = sess.run(moments)
print(m, e)
>>> [ 4. 5. 6.] [ 6. 6. 6.]
また,tf.nn.momentsの第二引数に[0, 1]を渡すと,
moments = tf.nn.moments(x, [0, 1]) # 全体の平均と分散を求める
with tf.Session() as sess:
m, e = sess.run(moments)
print(m, e)
>>> 5.0 6.66667
となります.
tensorflowでCNNをやる場合,入力は [batch_size, height, width, channel] の4次テンソルであるはずなので,
batch_mean, batch_var = tf.nn.moments(net, [0, 1, 2])
として,チャンネルごとの平均と分散を求めることになります.