fastaiを使って30行以内のコードで画像判別モデルを作成する

# この記事の目的
fast.aiコースという、機械学習を学べる無料のコースをご存知でしょうか？
[fast.aiコース](https://course.fast.ai/)
このコースの受講記録を残す目的で、この記事を書いています。この記事では02.Productionの一部を整理しています。
## 画像判別モデル作成の全体フロー
今回は犬の画像を渡すと犬種を判別するモデルを作成します。以下の流れで進めていきます。
ライブラリのインポート
学習用データの準備
準備したデータの整備
モデル学習の実行
モデル学習結果の確認
## 環境
Google Cloabで作業しています。

# ライブラリのインポート
画像判別モデル作成に必要なライブラリをインポートします。
```python
! [ -e /content ] && pip install -Uqq fastbook
#[ -e /content ]:contentというパスがあるかを判断する条件文。google colab環境にはcontentというパスがデフォルトであるため、google colab環境の場合に実行されるコマンド
#-U:パッケージをアップデート
#qq:ログの出力をError,Criticalレベルに限定
from fastbook import *
from fastai.vision.widgets import *
```
# 学習用データの準備
画像判別モデル作成には、学習元用のデータが必要です。今回は画像を検索し、それを学習用のデータとします。
## 学習用データを格納するパスを定義する
```python
path = Path('dogs')
path.mkdir()
```
ここで使用しているPathはパスを文字列ではなく、パスとして使うことができるオブジェクトです。詳細はこちらをご参照ください。
[Pathオブジェクト](https://docs.python.org/ja/3/library/pathlib.html#basic-use)

## 画像を検索し、結果を格納する
```python
# 今回は3種類の犬種を判別するモデルを作る
dog_types = 'ShibaInu','Kooikerhondje','LabradorRetriever'

# 犬種毎に検索した画像をパスに格納する
for o in dog_types:
  dest = (path/o)
  dest.mkdir(exist_ok=True,parents=True)
  results = search_images_ddg(f'dog {o}')
  download_images(dest,urls=results)
```
[path.mkdir](https://docs.python.org/ja/3/library/pathlib.html#pathlib.Path.mkdir)
exist_ok:作成しようとしているパスが存在している場合の挙動を定義
parents:親ディレクトリが存在している場合の挙動を定義

[search_images_ddg](https://github.com/fastai/fastbook/blob/master/utils.py#L45)
DuckDuckGoの画像検索結果のURLを文字列で返す

[download_images](https://docs.fast.ai/vision.utils.html#download_images)
urlsで指定されたURLの画像をdestで定義されたパスにダウンロードする

## 表示できない画像は削除する
```python
# dogs配下の画像ファイルのパスを文字列で取得
fns = get_image_files(path)
# 表示できない画像を抽出
failed = verify_images(fns)
# 表示できない画像はdogs配下から削除
failed.map(Path.unlink)
```
[get_image_files](download_images)
パス内の画像を再帰的に取得する
[veriry_images](https://docs.fast.ai/vision.utils.html#verify_images)
開けない画像を返す
[path.unlink](https://docs.python.org/ja/3/library/pathlib.html#pathlib.Path.unlink)
ファイルを削除する

# 準備したデータの整備
fastaiでは学習用のデータをDataBlockというオブジェクトで定義します。
## DataBlockを定義する
```python
dogs = DataBlock(
    blocks=(ImageBlock,CategoryBlock),
    get_items=get_image_files,
    splitter=RandomSplitter(valid_pct=0.2, seed=42),
    get_y=parent_label,
    item_tfms=Resize(128)
)
```
[datablock](https://docs.fast.ai/data.block.html#datablock)
モデル学習に使用するデータの定義
[datablock tutorial](https://docs.fast.ai/tutorial.datablock.html)
Datablockの定義にあたっては以下のことを検討します。
インプット、アウトプットデータのタイプ:画像データがインプット、画像のカテゴリがアウトプット
データはどこにあるか：指定されたパス配下[get_image_files](https://docs.fast.ai/data.transforms.html#get_image_files)
インプットデータに何かを適用する必要があるか：無し
アウトプットデータに何かを適用する必要があるか：親ディレクトリの名前をつける[parent_label](https://docs.fast.ai/data.transforms.html#get_image_files)
データをどのように分割するか：ランダム
バッチ形成前に何かを適用する必要があるか：サイズ変更
バッチ形成後に何かを適用する必要があるか：無し

## 画像データを読みこませる
```python
dls = dogs.dataloaders(path)
```
[dataloaders](https://docs.fast.ai/data.load.html#dataloader)
定義したDabaBlockに画像が格納されたパスを渡すことで、学習用のデータとする
### 学習データを拡張する
```python
dogs = dogs.new(item_tfms=Resize(128), batch_tfms=aug_transforms(mult=2))
dls = dogs.dataloaders(path)
dls.train.show_batch(max_n=8, nrows=2, unique=True)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920198/7c2b86a9-e151-ab0b-2772-5e5dbf9e5b9c.png)
[aug_transforms](https://docs.fast.ai/vision.augment.html#aug_transforms)
反転、回転、ズーム、明るさの変換などをランダムで行い、学習用のデータを拡張する
# モデル学習の実行
学習用のデータの定義が完了したので、そのデータを用いて、モデルを学習させます。
## モデルを定義する
```python
learn = vision_learner(dls, resnet18, metrics=error_rate)
```
[vision_learner](https://docs.fast.ai/vision.learner.html#learner-convenience-functions)
学習用データ、モデルアーキテクチャ、メトリックを指定して、モデルを定義する
[metrics](https://docs.fast.ai/vision.learner.html#learner-convenience-functions)
メトリックとして定義できる関数
## モデル学習を実行する
```python
learn.fine_tune(4)
```
[fine_tune](https://docs.fast.ai/callback.schedule.html#learner.fine_tune)
事前学習されたモデルを使う
# モデル学習結果の確認
モデルの学習結果を確認します。
## 混同行列を表示する
```python
interp = ClassificationInterpretation.from_learner(learn)
interp.plot_confusion_matrix()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920198/1c42940c-9fab-92fc-f1f9-1030ef904684.png)
[interp](https://docs.fast.ai/interpret.html#interpretation)
モデルの予測結果を把握するために使用するオブジェクト
## 損失が大きいものを表示する
```python
interp.plot_top_losses(3, nrows=3)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920198/b33a0bcd-7b6c-ab2a-dfd9-66b3a1bf7c21.png)
# まとめ
簡易的な画像判別モデルの作成ができました。今後モデルの精度向上方法等について整理していきます。