深層学習における学習率（Learning Rate)の学習モデル（予測精度）への影響について

# 1.概要
　これまで公開されているDatasetを用いて、Pytorchによる**Semantic Segmentation**の方法についていくつか紹介しました。
　
**Semantic Segmentation紹介記事**
[Pytorchによる航空画像の建物セグメンテーションの作成方法.](https://qiita.com/nigo1973/items/1d7495a963c23c97189c)
[PyTorchによるMulticlass Segmentation - 車載カメラ画像のマルチクラスセグメンテーションについて．](https://qiita.com/nigo1973/items/c62578fccc7230ba48f8)
[MMSegmentationによる多数クラス画像(Multi Class)のセマンティックセグメンテーション(Semantic Segmentation).](https://qiita.com/nigo1973/items/37c0980b00e4f1eb2c3f)
[航空写真から道路モデルを作成する方法](https://qiita.com/nigo1973/items/e5722c9e859343427293)

　ここで用いたSemantic Segmentationの学習モデルは、公開されているパラメータをそのまま使用していました。このモデルでは、学習率はあるエポック数にて段階的に変化させる単純なものでした。
 そこで学習率をエポック数にあわせて変えるとモデルの精度がどれほど変わるのか、今回は実験してました。
　偶然にも、Kaggleの有名人の方々が執筆された[「Kaggleに挑む深層学習プログラミングの極意」](https://www.kspub.co.jp/book/detail/5305133.html)にて、小嵜さん(@smly)さんが担当された「3章　画像分類入門」にて、学習率の影響を紹介されており、**大きめの学習率での最適化を行ってから学習率を小さくしていったほうがよい理由**を説明されています。ご関心があるかたは、是非こちらの本をご参考にしてください。
　（個人的ですが、2年ほど前に深層学習の画像技術を出版準備していると聞き、首をかなり長ーくして待っていました。 購入して、何度も読み直しています。）

　pytorchによる学習率カーブについては、以下に例がまとめられていますので、ご参考ください。

[Guide to Pytorch Learning Rate Scheduling](https://www.kaggle.com/code/isbhargav/guide-to-pytorch-learning-rate-scheduling/notebook)

　ここで用いた道路Datasetの入手方法や各種学習率カーブを用いたサンプルコードを[Google Colaboratory](https://colab.research.google.com/drive/10DQ-s10p8iYPBrN1bJAIVu8Vx7kZ1S97?usp=sharing)にアップしましたので，ご興味のある方は試してみてください．ご参考になれば幸いです。

# 2. PytorchのSchedulerを用いた学習率カーブ
 pytorchによる学習率カーブがどういった学習が進むとどのように変化するのか、繰り返しになりますが[こちら](https://www.kaggle.com/code/isbhargav/guide-to-pytorch-learning-rate-scheduling/notebook)をご参考ください。

　では、以前紹介した[航空写真から道路モデルを作成する方法](https://qiita.com/nigo1973/items/e5722c9e859343427293)をベースに、学習率をSchedulerを用いてエポック数にあわせて変更します。

```python
#StepLR 
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=20, gamma=0.4)

#MultiSteLR
#scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=[25,50,], gamma=0.1)

#LAMBDA LR
#lambda1 = lambda epoch: 0.955** epoch
#scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=lambda1)

#ExpotentialLR
#scheduler = torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.955)

#CosineAnnealing LR
#scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=10, eta_min=0)
```
ここでは、学習の最初と最後が同じになるよう、それぞれのパラメータを調整しています。具体的には、最初は1E-4とし、100エポックで1E-6になるようにしています。

今回はSchedulerを用いますので、モデル作成部分のコードも変更しました。

```python
max_score = 0


#train accurascy, train loss, val_accuracy, val_loss をグラフ化できるように設定．
x_epoch_data = []
train_dice_loss = []
train_iou_score = []
valid_dice_loss = []
valid_iou_score = []
lerning_rate = []

for i in range(0, 25): #学習モデルの精度を高めたいときは、こちらの数字を大きくします。ただし、それだけ学習に時間がかかります。

    print('\nEpoch: {}'.format(i))
    train_logs = train_epoch.run(train_loader)
    valid_logs = valid_epoch.run(valid_loader)

    x_epoch_data.append(i)
    train_dice_loss.append(train_logs['dice_loss'])
    train_iou_score.append(train_logs['iou_score'])
    valid_dice_loss.append(valid_logs['dice_loss'])
    valid_iou_score.append(valid_logs['iou_score'])
    lerning_rate.append(optimizer.param_groups[0]['lr'])

    # do something (save model, change lr, etc.)
    if max_score < valid_logs['iou_score']:
        max_score = valid_logs['iou_score']
        torch.save(model, './best_model_Unet_resnet50.pth') #modelを再利用するときは、モデル名を適切に変更
        print('Model saved!')

    scheduler.step() 
```
　前回との違いは、学習ループで、scheduler.step()を用いて、設定したSchedulerにあわせて学習率をエポック毎に変化させます。また、学習率の履歴も残しています。

では、各学習率カーブによる結果を示します。

# 3. 学習率カーブによる学習モデルの精度検証

![Screenshot from 2023-02-04 23-02-22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187602/fbd738e5-8e46-a86f-add8-5433a46f711a.png)
**Single Step LR**
![Screenshot from 2023-02-04 23-02-41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187602/bb3e6487-34eb-1dcf-f97c-65190ffac692.png)
**Multi Step LR**
![Screenshot from 2023-02-04 23-03-53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187602/731b57c0-49de-4e44-0106-7cdc394e48bb.png)
**Lambda LR**
![Screenshot from 2023-02-04 23-04-35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187602/9a0fd2db-634d-ded8-230b-1c3e0e484ea2.png)
**Exponential LR**
![Screenshot from 2023-02-04 23-05-30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187602/14837a8d-0077-7324-9b28-05524d81141d.png)
**Cosine Annealing LR**

 前回のMulti Stepの学習率カーブのときは、TrainデータのDice Lossが0.2以下にならなかったのですが、今回はLambdaLRやExponential LRでDice Lossが0.17まで減少しました。

Cosine Annealing LRについて、[「Kaggleに挑む深層学習プログラミングの極意」](https://www.kspub.co.jp/book/detail/5305133.html)で紹介されている、最終エポック数で学習率が最小となるように修正すると、こちらのような結果となりました。

![Screenshot from 2023-02-04 23-09-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187602/3b5ad2b0-fc22-3e6a-4f8a-3a24864e73c8.png)
**Cosine Annealing LR改**

このとき、Multi Stepのときとおなじく、Dice Lossは0.2以上となりました。こちらをみると、学習率の低下率は、エポック数にあわせてまずは大きく減少させておき、学習がすすんでからはその変化を小さくしたほうがよい結果となりました。これは、一般的な学習率とモデル精度との関係で紹介されている**学習を進めて学習率を小さくすることで最適解により近づける**に傾向があっていると思います。（例えば、[第3回　ディープラーニング最速入門 ― 仕組み理解×初実装（後編）](https://atmarkit.itmedia.co.jp/ait/articles/1912/16/news026.html)の（5）”学習方法”の設計とモデルの生成：学習率をご参照ください。図で紹介されていますので、イメージがつかみやすいと思います。）

　次に、学習や評価で用いなかったテストデータを用いて各学習モデルを評価します。

**出力**
| Learning Rate Method | dice_loss | iou_score |
| :--- | :---: | ---: |
| Single Step | 0.2949 | 0.6562 |
| Multi Step | 0.3354 | 0.6229 |
| Lambda | 0.2917 | 0.6587 |
| Exponential | 0.2823 | 0.6624 |
| Cosine Annelaing | 0.303 | 0.6303 |
| Cosine Annelaing改 | 0.331 | 0.6075 |

　これより、同じ学習量でも、学習率カーブにより予測精度に違いがあるのがわかりました。特に、今回は学習初期に大きく減少させた方が、最終的なモデル精度が向上しています。

# ４. 学習量による予測精度の改善について
　最後に、今回は"Lambda"の学習率カーブにて、学習量を大きくすることでモデル精度がどれだけ改善されるのか試してみました。ここでは、100エポックで学習率を1E-6まで減少させ、1000エポックまではその値を維持しました。結果が以下となります。

![Screenshot from 2023-02-04 23-25-38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187602/50f510ad-ac83-e5d1-3a65-546aedaaf6be.png)
**Lambda LR, epoch:1000**
 
　100エポックから学習率を同じにしても、学習量を増やすことでDice Lossが改善されているのがわかります。TrainデータのDice　Lossは最終的には0.1262まで改善されました。Trainデータのみ改善されていないことから、過学習が発生していないこともわかりました。
　
　それでではテストデータの予測結果を比較してみます。

**出力**
| Learning Rate Method | dice_loss | iou_score |
| :--- | :---: | ---: |
| Lambda, epoch:100 | 0.2917 | 0.6587 |
| Lambda, epoch:1000 | 0.2558 | 0.6869 |

やはり、学習量（エポック数）は正義ですね。学習するだけ精度が改善されています。

最後に、1000エポックの学習モデルを使った航空写真の道路の抽出結果です。

![Screenshot from 2023-02-04 23-29-38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187602/94802666-609a-b9f2-e3b3-9a7d0a720de1.png)

正解（中央）と比べて予測結果（右）がかなり一致しているのがわかります。前回と比べても改善されていますね。

# ５. まとめ
　国土地理院が公開したGISデータセットとして公開されている航空写真から道路を識別するデータセットを用いて、学習率カーブが学習モデルとその予測精度に与える影響について実験しました。

　大事なことは、[「Kaggleに挑む深層学習プログラミングの極意」](https://www.kspub.co.jp/book/detail/5305133.html)にも書かれていますが、まずは対象とするデータ・セットそのものの理解を深め、その後の改善方法として今回紹介したような各種の学習率カーブを用いて改善傾向を試してみるのがよいと思います。
　
　私が誤解している部分や知らないことなど多々あるかと思いますので、本記事に対して忌憚なくご意見いただければ嬉しいです。また、みなさの経験をコメントにて共有いただければ、さらに嬉しいです。


# 6. 参考記事
[GSIデータセット](https://gisstar.gsi.go.jp/gsi-dataset/index_ja.html)
[衛星画像のSegmentation（セグメンテーション）により建物地図を作成する．](https://qiita.com/nigo1973/items/78dea24fd997674ca8b9)
[Pytorchによる航空画像の建物セグメンテーションの作成方法.](https://qiita.com/nigo1973/items/1d7495a963c23c97189c)
[航空写真から道路モデルを作成する方法](https://qiita.com/nigo1973/items/e5722c9e859343427293)
[Kaggleに挑む深層学習プログラミングの極意](https://www.kspub.co.jp/book/detail/5305133.html)