サポートベクター回顧

プログラミングとか機械学習とか画像処理などに興味がある人のブログというかメモというか。アウトプット苦手なので頑張ります。

機械学習のハイパーパラメータチューニングの勘所(主にDNNの話)

あくまで勘所、私のメモ的な感じでベストプラクティスではないです。問題設定やデータの種類、サイズによって本稿の内容が通用しない場合も大いにあると思います。

コンペの参加や実務・研究等での実装を繰り返すうちに更新していく予定です。というか私の経験がまだ全然浅いので、あまり参考にならないかもしれません。

学習率(Learning Rate)

  • 以下、主に深層学習(DNN)の学習率の話になります。
  • 個人的に一番大事。データセットによるが、大きすぎたり小さすぎたりすると収束しなかったりする。
  • 断定はできないが、データサイズが小さいほどここのチューニングが重要になりそう。
  • Adamならデフォルトの1e-3をまずは試して、うまく行かなかったら1e-2 ~ 1e-5のオーダーあたりをグリッドサーチするとよさそう。ファインチューニングするなら小さめの学習率のイメージ(1e-4 ~ 1e-5など、学習率が大きすぎると転移元の重みが壊れるから)。
  • テーブルデータだと1e-2あたりがよさそうなイメージ。
  • 学習率はある程度決めてしまって、コンペなどの締め切り終盤でいじらない方が良いと思います。学習率が狂うとほかのハイパラも狂ってしまうので。

バッチサイズ(Batch Size)

  • 一般的には大きいほど学習速度が上がって良いといわれているが、小さいほうが精度が上がるとも言われている。でも増やせるだけ増やしていいと思う。
  • 学習率みたいに、大きすぎても収束しないとかそういうことはないと思う?
  • 不均衡データの場合は大きめがいいかも。ミニバッチ内に多数派データしか存在しない場合学習が不安定になりそう。
  • batch normalizationを使う際はバッチサイズが小さいと精度が低いという報告もある。batch normalizationを使うならばできれば32、最低8は欲しいかも?
    https://doi.org/10.48550/arXiv.1803.08494
  • メモリ不足の際はgradient accumulationで増やせばいいが、batch normalizationのパラメータの計算の際には本来のバッチサイズに収まるデータしか使われないため注意。
  • バッチサイズも学習率同様、決めてしまったらいじらない方が良いと思います。
  • 私の場合、バッチサイズはなるべく32になるようにしようとしています。メモリ乗らなければgradient checkpointingや混合精度を駆使したりして、それでもだめならgradient accumulation。

エポック(Epoch)

  • 私は十分収束したところや過学習しそうなところで決め打ちしている。
  • epoch数の決め方は最初に多めのepochで学習して、目視 or early stoppingも使いながらよさげなところを見つける。この方法が正しいのか自信は全然ないが、、
  • Cross Validationする場合、各foldでearly stoppingでbestなエポックを決めるのはvalidationデータにoverfitしそうなのであまりしたくない。CVの結果が本来よりも良く見えてしまったり、たまたま出た良い結果が得られてしまったりするから。CVの全foldを通して同じepoch数になるようにしたい。
  • 過学習モデルはアンサンブルで強くなる印象があるので、CVでaveragingしたりseedでaveragingしたりする前提なら多少過学習気味でもいいと思う。(コンペの場合。研究・実務はちょっと分からない)

最適化関数(Optimizer)

  • 私はAdamかRAdamかAdamWのどれか使っている。でもしっかりチューニングしたSGDが一番強いというか汎化しやすいらしい。私がAdam系を使っている理由は収束が早く試行回数が回しやすいから。
  • 基本Adam or RAdamで、過学習する傾向があるならばAdamW?(もしくはRAdamにweight decay)。
  • RAdamは割と適当に使っても精度が出る頑健で便利なoptimizerだが、テーブルデータなどデータセットによっては不安定になるかも。→最近の経験上なんだかんだ経験上AdamかAdamWが一番安定している印象です。

荷重減衰(Weight Decay)

  • 過学習防止策。
  • 過学習してたら1e-2ぐらいかけるイメージ?あんまわかんない。
  • これを入れて効いたっていう経験はあんまりないが、小さいデータセットだと結構大事なのかな?とか思ったりはしてる。

ドロップアウトDrop Out)

  • 過学習防止策。DNN版バギングみたいなイメージ。
  • あんま分かってないけど、回帰じゃ使わないほうが良いとか言われている。
  • 分類問題はとりあえずdrop out rate = 0.2ぐらい使っておけばよさそう?小さいパラメータのモデルだと0.2、大きいモデルだと0.5ぐらいのイメージはある。個人的にはモデルによって変えるとチューニング面倒だしタスクに応じて低めか高めかチューニングした方が良い気はする。
  • 0.8みたいなクソデカrateがたまに効いたりする。

勾配クリッピング(Gradient Clipping)

  • 勾配爆発防止のやつ。
  • 自然言語問題でtransformersやRNN・LSTMを使う際は使ったほうがよさそう?huggingfaceのTrainerの公式実装ではデフォで1.0ついてたはず。
  • ResNetなどは残差接続で勾配爆発防止対策されているのであんまいらなさそう。
  • PyTorchで混合精度使うときはクリッピングする前に元のfp32にunscaleするのを忘れない。

学習率スケジューラ(Scheduler)

  • 私はPyTorchのOneCycleLRをよく使っています。パラメータはpct_start = 0.1 or 0.0, div_factor = 1.0e+3など。
  • Cosine AnnealingでT_max = max_epochでeta_min = 初期学習率 x 1e-2 or 0.0も以前は使ってたりする。どちらを使っても徐々に学習率を減衰させるやつだし多分あんま変わんない。
  • ReduceLROnPlateauもよく使われているイメージだが、個人的にはそれを使うとvalidationデータにoverfitするんじゃないかと思っているので私は使わない。early stoppingも使いたくないですし、trainの際にtrain以外の情報は参照したくない主義です。

モデルサイズに対するもろもろのチューニング

  • たとえば、deberta-baseからdeberta-largeに変えるとか、ResNet 18からResnet 101に変えるとか、小さいモデルから大きいモデルに変えたときとかの話。
  • 小さいモデルで使用したパラメータが大きいモデルでそのまま使えるかと言われると一概にそうとも言えない(気がする)。そのとき、大きいモデルは小さいモデルより学習率を小さくするか、バッチサイズを大きくするか、エポックを減らすのがいいと思う。なぜならば大きいモデルはパラメータ数が多く、小さいモデルと比較してover fitしやすいからである。