初心者が学ぶ学習率を操作する scheduler。

# scheduler とは
scheduler とは機械学習でモデルを学習させる際に学習が進むごとに学習率を変化させるモジュールのことです。

# なぜ学習率を変化させたいの？
学習率の設定にはジレンマが存在します。
学習率が低い→正確にlossの極小値が見つけやすいですが、学習に時間がかかります。また、極小値なので、最小値ではありません。（局所解）
学習率が高い→学習の時間は短くなりますが、学習率が高いとloss関数の底を飛び越してしまい、極小値を見つけにくいです。
そこで最初は学習率を高くし、学習がある程度進んだところで学習率を下げたくなりそうです。

![scheduler_desc_of_lr.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2882383/882dc686-ac83-da60-4a90-4ec25d0000e5.png)

# scheduler の基本的な使い方
## scheduler の種類
scheduler には様々な種類があり、それを提供しているライブラリも数多あります。
ここでは pytorch と huggingface が提供している主要な scheduler を紹介したいと思います

## pytorch 編
pytorch のスケジューラーは epoch ごとに学習率を更新します。
全データを学習する単位を epoch と呼びます。機械学習ではこの epoch を何回も繰り返します。

### CosineAnnealingLR
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2882383/7f053289-2efa-696c-caf4-b37141bfef54.png)
T_maxはmin_lrになるまでのエポック数を指定。その後、lrまで増えていく形です。
非常によく使われるスケジューラーで、画像認識のときによく見ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2882383/a5cc3c10-d8fc-30c9-1a57-e13c604a05f2.png)

### CosineAnnealingWarmRestarts
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2882383/a6018c51-5109-1e2f-5da4-3abad1918e97.png)
T_0のエポック数が経過したら restarts します。restarts とは初期の学習率に戻るということです。
T_mult は restarts ごとに restarts までのエポック数を T_mult 倍します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2882383/23db7521-a67b-4ac1-eb72-c5d05393bd18.png)

### ReduceLROnPlateau
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2882383/19f27912-07c2-770c-0651-4af1ee0a8215.png)
Factor: patience数のepochが経過したら学習率にfactorをかけます。減衰率。
Patience: lossが減少しないことを監視する期間です。

今までのスケジューラーと異なり、loss の監視を行います。
loss が下がらないときにのみ、学習率を下げます。
テーブルデータのときによく見かけます。テーブルデータは事前学習モデルを使うことがなく、最初から weight の計算をするため、学習率を大きくすることが多いです。そのようなときに、学習率を固定してしまうと前述したようなジレンマに陥ります。これを解決できるのがこのスケジューラーです。
最初に学習率を大きくしても、loss次第で徐々に学習率を落としてくれるので有用です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2882383/d4838d7f-497f-5ba0-23f9-63d52f6a4b67.png)


## huggingface 編
huggingface のスケジューラーは batch ごとに学習率を更新します。
batch とは全データのうちの一部のことです。
機械学習では全データを一気に学習に使うとメモリがもたないケースがあります。そこで、全データを batch という単位に分解して学習を行います。epoch 数が少ないようなケースでは batch 単位で学習率を変化させたほうがいいのかもしれません。

### get_linear_schedule_with_warmup
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2882383/ce605b20-e5b7-f4d6-98dd-d56ec57211ec.png)
num_warmup_steps: warmupが完了するstep数
num_trainig_steps  : trainingを行う総steps数
ここで言う step とは一つの batch の学習を行うことを指します。
warmup とは学習率を徐々に上げることを指します。この効果については後述します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2882383/3306b33e-897c-2321-e37c-3f437ea2d64b.png)

### get_cosine_schedule_with_warmup
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2882383/97d73016-9e2d-409d-fda2-4962212708f3.png)
num_cycles: cos波の数を指定
warm_up後にcos波の動きをします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2882383/e13c1ad4-bcc8-4b63-82fa-9a922d8e3c0a.png)

## 補足

### warmup
warmup とは学習率を徐々に上げることを指します。
事前学習モデルを fine tuning する際には学習率が最初から高いと weight が破壊されることがわかっています。これはせっかく事前に訓練した weight があるのに大きく更新をかけてしまうためです。そこで最初は warmup を行い、そこから学習率を徐々に下げていくことをします。このようなことができない場合には最初からある程度学習率を下げておいたほうがいいでしょう。
warmup に費やす step 数ですが、全体の10％程度を指定することが多いです。

### どれを使えばいいか
基本的に、最初はscheduler を使わないで組み、その後に scheduler を使っていく形がいいと思います。get_linear_schedule_with_warmup がシンプルで一番好きです。

### cos 波のように学習率を上げるケースはあるのか
基本的に warmup 以外で学習率を上げるケースはあまりないようです。単純に下げ続けるのがいいです。

## 参考文献
下記の記事を書いた方々に感謝いたします。
https://wonderfuru.com/scheduler/
https://www.kaggle.com/code/isbhargav/guide-to-pytorch-learning-rate-scheduling/notebook
https://www.kaggle.com/code/snnclsr/learning-rate-schedulers
https://towardsdatascience.com/learning-rate-scheduler-d8a55747dd90
https://huggingface.co/docs/transformers/main_classes/optimizer_schedules#schedules
https://pytorch.org/docs/stable/optim.html#

## 謝辞
読んでくださりありがとうございました。
間違いなどありましたらご指摘ください。