ChainerでHeNormalによる初期化を行う場合はWeight Initializerを使うのがよい


HeNormalとは

重み係数の初期化手法の1つで、別名"MSRA"とも呼ばれます。Kaiming Heらの論文で使われており、論文著者とMicrosoft Researchが名前の由来になっていると思われます。

HeNormalでは重み係数$W$を標準偏差$\sqrt{2/N}$の正規分布に従う乱数で初期化します。ここで$N$は入力の大きさで、links.Linearの場合は入力ベクトルのサイズ、links.Convolution2Dの場合はチャンネル数×カーネル高さ×カーネル幅になります。

wscale指定ではだめなのか?

HeNormalで初期化する方法として、linkのインスタンス生成時にwscalemath.sqrt(2)が指定されることがあります。
例えばchainer.links.Linear(100, 100, wscale=math.sqrt(2))のような指定を行います。
ChainerのImageNetサンプルにあるNetwork-in-Networkモデルでもこの方法が使われています。
しかしながらwscaleの動作がv1.9.0から意図せず変わっていることがわかりました。
すでにissue登録もしています。
wscale doesn't have backward compatibility
明示的にHeNormalを使いたい場合にはこの問題が解決されるまでwscaleによる指定は避けたほうがよいでしょう。

例えばChainer実装を使った結果を公開する際に「HeNormalで初期化した」と述べたり、他のチームの研究でHeNormalを使っていてその再現をするために初期化方法を揃えたいといった場合には、以下に述べるようにWeight Initializerを使うのがよいと思います。

Weight Initializerの使い方

ChainerではWeight Initializerを使うことで重み係数の初期化方法を指定できます。
Initializerを使って初期化するにはlinkのinitialWにinitializerのインスタンスを指定すればよいです。
例:

class MLP(chainer.Chain):

    def __init__(self, n_in, n_units, n_out):
        initializer = chainer.initializers.HeNormal()
        super(MLP, self).__init__(
            l1=L.Linear(None, n_units, initialW=initializer),  # n_in -> n_units
            l2=L.Linear(None, n_units, initialW=initializer),  # n_units -> n_units
            l3=L.Linear(None, n_out, initialW=initializer),  # n_units -> n_out
        )

    ...

参考文献

  1. Kaiming He el al. Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification, (2015)