「バッチサイズは小さい方が良い」を勾配ブースティングで検証してみる

名刺の会社のアドベントカレンダー3日目です。

へい社ではR&Dメンバーが論文読み会を定期的に開催しています。私は直近でバッチサイズに関するものを読みましたので、それに関連する数値実験を報告しようと思います。

論文

前者の論文では、Deep Learningにおいて、SGDのバッチサイズを小さくした方が汎化性能の高くなる経験則について、バッチサイズとtrain loss functionの収束先のflatさ/sharpさという観点で分析をしています。バッチサイズが小さいと重みの更新幅の共分散が大きくなり、flatな(局所)解に収束しやすくなることで汎化性能が向上すると主張しています。

後者の論文(の前半部分)では、バッチサイズと重みの更新幅の関係性を学習率で調整した場合には汎化性能の差異がないと反論をしています。

読み会でも、バッチサイズ1にすれば(収束させるのが難しくなりそうですが)汎化性能が最良となるのか議論になりましたので、前者の論文がパラメータチューニングにおいて重要な示唆を与えているものの、そこまで強い主張ができるのか疑わしいと考えています。

今回やること

Deep Learningのパラメータチューニングについては専門家に任せるとして、勾配法でバッチサイズを小さくすれば汎化性能が高くなるというのは勾配ブースティングでも同じなので、XGBoostを用いてこれを検証してみました。 Hyperoptでチューニングして、バッチサイズは小さい方が良いという報告は聞こえてこないので結果は見えていそうですが、とりあえずやってみます。

数値実験

データセットCredit Card Fraud Detectionを用いました。 クレジットカードのトランザクションが不正かどうかをターゲットとしています。正例が0.17%とかなり不均衡なデータとなっています。

今回はバッチサイズ subsample, 学習率 learning_rate 以外はデフォルトのパラメータを用いることとします。 正則化パラメータの効き方がバッチサイズの大小によって異なることが予想されますが、ここでは捨象します。

clf = xgb.XGBClassifier(
    learning_rate=learning_rate,
    subsample=subsample,
    base_score=0.0017,
    n_estimators=num_round, n_jobs=16
)

まずは以下のパラメータで実験してみました。

Model learning_rate subsample
LB (Large Batch) 0.1 1.0
SB (Small Batch) 0.1 0.1

f:id:marugari2:20171204173739p:plain

ここではバッチサイズの小さい方がvalidationの精度が高くなりました。

学習率の調整

XGBoostの更新幅の分散は

 \displaystyle
\mathrm{Var}
\left( \varDelta w_M \right)
= \mathrm{Var}
\left( \eta \frac{G_M}{H_M} \right)
= \frac{\eta ^2}{M} \frac{1}{N} \mathrm{Var}
\left( \varDelta w_N \right)

となります。 NIPS論文に従えば、バッチサイズを1/100にするときには学習率を1/10するのが良いとわかります。 学習率を調整した場合の結果は以下のようになります。

Model learning_rate subsample
LB 0.1 1.0
SB adjusted 0.03 0.1
LB slow 0.03 1.0

f:id:marugari2:20171204173955p:plain

こちらの結果では learning_rate を小さくした効果が本質的でバッチサイズはあまり関係ないように見えます。 バッチサイズの大きい方が収束は速く、より小さい learning_rate とより多い num_round によって精度を上げやすいでしょう。

まとめ

バッチサイズの小さい方が汎化性能に優れるケースも確認できた一方で learning_rate こそが本質的に重要であると思われます。 当然ですが、ICLR論文の模式図のようにバッチサイズを小さくしたからといって劇的に汎化性能の向上は望むべくもないでしょう。

また、Deep LearningではGPUメモリの制約でバッチサイズを小さくしたいことが多い*1一方で、XGBoostでは行方向の圧縮が効いておりバッチサイズを小さくしてもリニアには高速化されず計算効率が悪くなるという事情もあります。

XGBoostのパラメータチューニングにおいては subsample を大きめで固定しておき learning_rate を小さく num_round を大きくする王道が、やはり強いというのを再認識しました。

参考

追記

DeepLearningの最適化と Hessian Freeの資料によるとHessianを使った最適化だと最適なバッチサイズも大きくなることが解説されていました。XGBoostはHessianを用いているため、論文で言われているような効果はそもそも出ないようです。Hessianを利用すると、flatならflatなりの更新量、sharpならsharpなりの更新量になるのでICLR論文のような状況は生じにくいですね。 Hessianを用いないscikit-learnのGBDTでどうなるのか関心あるところですが、再試する気力はないですね…

*1:たくさんGPUを持っているのでむしろバッチサイズを大きくしたい人達もいるようです。そういう背景があって論文にあるような研究がされてる訳ですね。