こんにちは。
Deep Learningを自分でゼロから組んで(fine tuningとかではなく)、全部ゼロから学習させるのって大変ですよね。
特に、ハイパーパラメーターの設定にすごく悩みます。トップカンファレンスに出されているような高精度の論文では、そういうハイパーパラメーターはさも当然かのごとく設定されているので、まぁモデルを使い回す分には特に問題ないんですが、自分で決めようとすると本当に悩ましいです。
また、Deep Learingは学習に非常に時間がかかりますし、それぞれのハイパーパラメーターの相互関係とかもあり、問題の切り分けが難しいです。
その意味で、グリッドサーチなども対象を決めてやらざるをえず、その場合でもあたりをつけておきたいのが正直な所だと思います。
ということで、ハイパーパラメーターにはいくつも種類があるんですが、今回はその中でも、Batch sizeについてどうやって決めるかをまとめておこうと思います。
注意事項
この記事では、「私が今使っているデータに対してこうした」というものの中で、汎用的に当てはまるんじゃないかなってものを書いただけなので、「全てのデータに対して必ずこれが当てはまる」とは限りません。
また、私自身まだまだDeepの専門家集団から比べると弱者中の弱者ですので、もしかしたら間違えているかもしれません。
上記、未来の自分も含めお気をつけ下さい笑。
よく論文で見るBatch size
Deep Learningの論文を読んでいるとどうやって学習をさせたかみたいな話はほぼ乗っているので、そういうのを見ていてよく見かけるのは以下あたりではないかと思います(すみません、私の観測範囲ですが)。
- 1
- 32
- 128
- 256
- 512
だいたい、1だと完全に確率的勾配降下法になりますし、512だと学習速度をあげたかったのかなという気持ちが見えます。このあたりについてどれにするべきかというところを考察してみたいと思います。
mini-batch SGDにおけるBatch size
SGD以外にもAdamとか色々あるんですが、それについては以下の記事を参照してください。
SGDによるパラメーターの更新ですが、以下の式のような形で表わせます(参考)。
$$
\theta_{t+1} \longleftarrow \theta_{t} - \epsilon (t) \frac{1}{B} \sum^{B-1}_{b=0} \frac{\partial \mathcal{L} (\theta, \mathbf{m}_b )}{ \partial \theta }
$$
$B$ となっているところが、バッチのサイズです。 $B$ が1であれば、オンラインのSGDになりますし、逆に$B$ がデータ数全体であれば、バッチ学習になります(バッチ学習は確率的でもなくなるのですが)。
ミニバッチは、1〜データ全体の間の数を $B$ に指定することをさします。各エポックごとにランダムにミニバッチのセットが代わり、そのミニバッチそれぞれでパラメーターを更新します。
ミニバッチのサイズによって学習の何が変わるか
ミニバッチのサイズによって学習における何が変わるかなのですが、主に以下の3点が変わります(たぶん……おそらく……きっと……)。
- 1つのサンプルデータに対する反応度
- 1epochの計算速度
- メモリ使用量
それぞれ見ていきます。
■1つのサンプルデータに対する反応度
1つのサンプルデータって言葉を使うとちょっとなんかアレなんですが、要は例えば画像のデータセットがあったとして、その中の1枚の画像のこと、と考えてください。
こう考えたときに、更新式をもう一度見てみます。
$$
\theta_{t+1} \longleftarrow \theta_{t} - \epsilon (t) \frac{1}{B} \sum^{B-1}_{b=0} \frac{\partial \mathcal{L} (\theta, \mathbf{m}_b )}{ \partial \theta }
$$
ここで、ミニバッチの単位で重みが更新されていきます。平均をミニバッチ毎にとって、そのミニバッチごとにパラメーターを更新するわけです。
ということは、ミニバッチの単位が小さければ小さいほど、1つ1つのデータに敏感に反応すると考えることができます。逆にミニバッチの単位が大きければ大きいほど、平均化されるので、1つ1つのデータよりもミニバッチ全体の特徴を捉えるということになります。
ミニバッチのサイズが小さいほど、1つ1つのデータに敏感に反応することから、学習も難しくなるのですが、学習率などのパラメーターをいじることである程度対処できます。
■1epochの計算速度
1epochの計算速度が変わります(ここでいっているのは、学習の収束の速さなどではなく、単純に計算速度の話です)。パラメーターの更新の回数というのが、ミニバッチのサイズが小さいほど多くなるので、これは当然と言えば当然です。
なので、とにかく一回ネットワークの学習を一通りepoch数分だけ回してしまいたいと思ったら、1つのバッチサイズは大きくした方が早く終わります。
■メモリ使用量
ミニバッチ単位でデータを読みとり、それを使うとなると、これはミニバッチのサイズが大きければ大きいほど、メモリの使用量を食います。
私のミニバッチサイズの決め方
完全に独自流で誰に教わったわけでもありませんが、一人でやっているときは以下のような感じでやります。
1. 適当に32とか128とかにして、一回学習させてみる
2. もっと学習速度あげて、他のパラメーターをとりあえず色々試したいなぁっておもったら、ミニバッチのサイズをあげる
2. lossの揺れ幅が各epochで大きいなぁってなったら、ミニバッチのサイズを上げる
2. 揺れ幅が小さくて、データのサイズも大きくない場合は、ミニバッチのサイズを下げる
まず、1をやります。その後、状況によって色々変えるという風にしてパラメーターを変えるみたいな感じでやります。その時設定するミニバッチのサイズは、上にあげたよく使われているミニバッチのサイズから選びます(ここはあんまり気にしません)。
バッチサイズを変えて学習させてみた
適当なデータで、ネットワークを組んで、バッチサイズを変えて学習させて見た例をTensorboardで出してみました(本筋ではないので、詳細には書きませんが)。縦軸がloss、横軸がepochです。また、学習によってlossがかわりますが、横軸の間隔はほぼ同じです。
以下はデータ数だいたい1万くらいのデータのときに、ミニバッチサイズ32でやった時です。
めちゃブレブレっすね笑。で、以下がミニバッチサイズ128でやったときのやつです。
学習の挙動が割とかわっていることがわかります。また、各epochの速さも変わっていました。
また、今回はデータの値が結構大きく変わる傾向があったので、あまりデータに敏感に反応して学習が進むとうまくいかなさそうというのはありました。なので、少しバッチサイズは大きめで取ったほうがいいのかなぁと思ってました。
まとめ
データに依存するのですが、一度ネットワークにデータを適当なミニバッチのサイズでかけてみて、それを見ながら考えるというのでいいのかな、と思っています。
ただ、勾配降下法の学習率などをいじることで、学習の挙動などを制御することができるので、一概に上の通りというわけにはいかないですが、気持ちだけでも知っておくとだいぶ私は変わりました。
さいつよなどなたか、これよりもいい方法や上で間違えているところがあれば、教えてください……
それでは。
参考
- machine learning - How large should the batch size be for stochastic gradient descent? - Cross Validated
- Tradeoff batch size vs. number of iterations to train a neural network - Cross Validated
- machine learning - Choosing an appropriate minibatch size for stochastic gradient descent (SGD) - Cross Validated
- [1609.04836] On Large-Batch Training for Deep Learning: Generalization Gap and Sharp Minima