fast.ai初心者目線の道案内

# はじめに


## fastaiとは

[fastai](https://www.fast.ai/)ライブラリを使用すると、最新のテクニックを使用してニューラルネットのトレーニングを簡潔に記述できます。 ニューラルネットの記述にはpytorch を使用しています。

　fastaiの機能は、[サンフランシスコ大学教員のjeremyさん](https://forums.fast.ai/u/jeremy)たちが[fast.ai](https://www.fast.ai/)というコミュニティで行っているディープラーニングの研究に基づいて実装されています。


## バージョンについて

fastaiはv0.7と、2018年10月にリリースされたv1でAPIが大きく異なります。古い方だと動作しないコードもあるので、コードを探すときはご注意ください。

courseもv0.7対応の2018年版「[Practical Deep Learning For Coders, Part 1](http://course18.fast.ai/) /  [Cutting Edge Deep Learning For Coders, Part 2](http://course18.fast.ai/part2.html)」ではなく、v1対応の2019年版「[Practical Deep Learning for Coders, v3](https://course.fast.ai/)」だけでよいと思います。

# 使い方の簡単な説明


## サンプルコード

```python
path = untar_data(URLs.MNIST_SAMPLE)
data = ImageDataBunch.from_folder(path)
learn = cnn_learner(data, models.resnet18, metrics=accuracy)  #１, ２
learn.lr_find()                                      #３
learn.recorder.plot()
learn.fit_one_cycle(1,max_lr=3e-2)                   #４        
learn.unfreeze()                                     #５
learn.fit_one_cycle(1,max_lr=slice(1e-6,1e-4))
```

「[lesson1-pets.ipynb](https://github.com/fastai/course-v3/blob/master/nbs/dl1/lesson1-pets.ipynb)」で使われているテクニックを一部抜き出して作成したものです。[NoteBookはこちら](https://github.com/lilacs2039/ColabNotebooks/blob/master/fastai/fastai%E8%AA%AC%E6%98%8E%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89.ipynb)。

これだけのコードに、以下のテクニックが含まれています。



1. RESNET18を利用して転移学習
2. 重み減衰（weightDecay）を適用（デフォルト）
3. 最適な学習率の探索
4. 1 Cycle Ruleで学習率を調整しながら学習
5. RESNET18の学習を有効化してFineTuning


## RESNET18を利用して転移学習

※ [fastaiのドキュメントに転移学習の説明あります。](https://docs.fast.ai/vision.learner.html#Transfer-learning)

　転移学習は、ImageNetのような巨大なデータセットで学習したモデルを流用して、手持ちのデータセットに対してモデルを学習させるというテクニックです。手持ちのデータセットのデータ数が少なすぎて、ランダムに初期化されたモデルを学習しにくいときに、特に有効です。


### 転移学習のモデル構造

　大抵の画像分類モデルの最後の層は小規模の線形層で終わる構造になっています。そこで、モデルの最後の方の線形層を独自のものに置き換えて、手持ちのデータセットに合わせて学習させます。

　以降、モデルの前半部・後半部を以下のように呼びます。



*   body
    *   モデルの前半の畳み込み層
    *   bodyの仕事は入力画像から画像特徴を抽出すること
    *   ImageNetのような巨大なデータセットで事前に学習された物を流用　
*   head
    *   モデルの後半の線形層、クラス分類を担当
    *   headの仕事は抽出された画像特徴から手持ちのデータセットのクラスを予測すること
    *   ランダムに初期化された新しいheadで差し替えて、手持ちのデータセットで一から学習を行う

モデルの学習は以下の二つのフェーズで行います。

1. bodyの重みを固定してheadのみを学習
2. bodyの重みの固定を解除してモデル全体を学習（Fine Tuning）


### cnn_learnerメソッドについて

　指定したDataBunchと学習済みモデルを指定して、learnerを作成するメソッド。デフォルトで、学習済みモデルのheadをカットして、独自のheadを付け加えます。

　独自headは以下のような構成になっています。



*   `AdaptiveConcatPool2d`レイヤ
*   `Flatten`レイヤ
*   以下からなるレイヤブロックを複数
    *   `nn.BatchNorm1d`,`nn.Dropout`,`nn.Linear`,`nn.ReLU`

　レイヤブロックに含まれる線形層の構成を指定することで、パラメータ数を調整できます。レイヤブロックの入力数は抽出した画像特徴の数となり、出力数はデータセットのクラス数となります（いずれも自ずと決まるので明示する必要なし）。隠れ層の入出力の数は`lin_frts`パラメータで指定することができます。

　デフォルトでは隠れ層の入出力数は512となります。つまり、以下のように２つのレイヤブロックを持ちます。



1. レイヤブロック１
    1. 入：bodyのアウトプット
    2. 出：512
2. レイヤブロック２
    3. 入：512
    4. 出：クラス数

※JupyterNotebookなら`model.learn`で確認できる。以下はheadの抜粋。（４）と（８）のLinearの入出力数に注目のこと。


```
 (1): Sequential(
    (0): AdaptiveConcatPool2d(
      (ap): AdaptiveAvgPool2d(output_size=1)
      (mp): AdaptiveMaxPool2d(output_size=1)
    )
    (1): Flatten()
    (2): BatchNorm1d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (3): Dropout(p=0.25)
    (4): Linear(in_features=1024, out_features=512, bias=True)
    (5): ReLU(inplace)
    (6): BatchNorm1d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (7): Dropout(p=0.5)
    (8): Linear(in_features=512, out_features=37, bias=True)
  )
```



## 重み減衰（weight decay）

**荷重減衰**は**正則化**という**過学習**を抑制するテクニックの１つです。

　正則化は、損失関数に罰金（penalty）項を付加することにより重み・係数が大きな値になることを防ぐことで過学習を抑制します。損失関数にL1ノルム「$λ||w||_1$」を付加するL1正則化とL2ノルム「$\frac{λ}{2} ||w||_2$」を付加するL2正則化があります（λは正則化の度合いを調整するハイパーパラメータ）。

　ニューラルネットワークの文脈では2次の正則化は**荷重減衰**と呼ばれます。

　sin波を多項式関数でフィッティングする例を通して、L2正則化の効果を確認します。

　下図はsin波にノイズを加えたデータのプロットです。これを１・３・９次関数の３種でフィッティングしました。9次関数によるフィッティングは無茶苦茶に発振したようになっており、関数sin(x)の表現として不適切です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186338/7cf2e673-33bf-a286-fec4-5ab269233a34.png)

９次関数に対して、損失関数にL2正則化項を加えてフィッティングしたのが下図です。上図の９次関数よりもsin波に近い形状になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186338/8da8ac5e-9fcd-a54d-39d1-f91b11e54e99.png)

L2正則化なし・ありの場合の9次関数の係数を比較しました。L2正則化ありの場合（右図）係数が小さくなっていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186338/be114a89-d172-6fca-e1f2-1e44643c443d.png)

[sin波を多項式関数でフィッティングするJupyterNotebookはこちらにおいておきました。](https://github.com/lilacs2039/ColabNotebooks/blob/master/%E6%AD%A3%E5%BC%A6%E6%B3%A2%E3%82%92%E5%A4%9A%E9%A0%85%E5%BC%8F%E9%96%A2%E6%95%B0%E3%81%A7%E5%9B%9E%E5%B8%B0.ipynb)


## 学習率の探索

※[fastaiのドキュメントに学習率の探索の説明あります。](https://docs.fast.ai/callbacks.one_cycle.html#The-1cycle-policy)

最適な学習率をグラフで確認できます。縦軸のlossの値が小さくなっている学習率ほど高速に学習が進みます。実際には最適値より少し小さい値を採用します（②のあたり）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186338/917e1350-4587-bee7-1591-4e8f4db9e748.png)

①の値のように、学習率が小さすぎると収束まで余分な時間がかかります。（下図のようなイメージ）
![lr0-01.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186338/ccd53fd0-b461-59e2-c4dc-4d805a518de8.gif)

逆に、③の値のように学習率が大きすぎると最短経路で学習が進まず、収束が遅くなります。（下図のようなイメージ）
![lr0-99.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186338/80ab8651-aceb-9a23-9c63-c77c2504025d.gif)

(グラフは[José Fernández Portal](https://forums.fast.ai/t/share-your-work-here/27676/300)さんの投稿より)


## 1 Cycle Rule

※[fastaiのドキュメントに1CyclePolicyの説明](https://docs.fast.ai/callbacks.one_cycle.html#The-1cycle-policy)あります。

「Leslie Smith’s 1cycle policy」とよばれるもので、学習をすばやく収束させる学習率調整方法です。[元論文の学習サイクル数の比較例](https://arxiv.org/pdf/1708.07120.pdf)では、よく使われる方法（学習が進むにつれて学習率を小さくする方法）で約8万サイクルかかっているところ、約1万サイクルで学習できています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186338/4f53d2a4-866c-9b16-2218-93590fce52c7.png)


学習時は下図のような学習率変化を繰り返します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186338/221923c1-b026-876f-ed73-248e8410c06d.png)


引数の`lr_max`で指定した学習率が最大値となり、`lr_max / dif_factor`の値が学習率の最小値となります。（デフォルトで25分の１）


# fastai関連の情報

fastai cource v3をやったとき日本語文献が少なく迷ったので、道案内の意味で各種情報をまとめておきます。


## fastaiライブラリの公式ドキュメント

[fastaiの公式ドキュメント](https://docs.fast.ai/)



*   環境構築方法、ライブラリの使い方、APIの説明　など一通りのことが書いてある。
*   特に、APIドキュメントの各モジュールのページ先頭にはモジュールの使い方・コード例だけでなく、ディープラーニング理論・テクニックの解説も載っている。Notebookを読んでいて気になるAPIがあったら、まずはモジュールの概要説明から読むと理解が進む。


## fastai cource v3（学習コース）関連



*   [fast.ai course v3トップページ](https://course.fast.ai/)
*   [fast.ai course v3　動画](https://course.fast.ai/videos/?lesson=1)
    *   大学の講義のような感じで、パワポによる理論の説明をはさみながら、JupyterNotebookでfastaiの説明をしてくれる。
    *   字幕はなくYouTubeの自動文字起こしも心もとない。聞き取れないなら↓の講義ノートと合わせて視聴すべし。
*   [hiromisさんの講義ノート](https://github.com/hiromis/notes)
    *   動画の内容を文字起こししたもの。やっぱり全部英語。
    *   講義内の重要なスライドなどは画像あり。
*   [fast.ai course v3 Jupyter Notebook](https://github.com/fastai/course-v3/tree/49a2b7472ae9288dd8aa7bdc43538a87eec80c94/nbs/dl1)
    *   講義で使用しているJupyterNotebook
    *   Google Colaboratoryで実行する際は、GPUインスタンスに切り替えてから以下のコマンドを最初に実行してfast.aiをセットアップすること。
    *   ``` \
!curl https://course-v3.fast.ai/setup/colab | bash \
```

<!-- Docs to Markdown version 1.0β17 -->