pyhaya’s diary

プログラミング、特にPythonについての記事を書きます。Djangoや機械学習などホットな話題をわかりやすく説明していきたいと思います。

fast.ai をサクッと動かす

機械学習のブーム到来によって、今までに様々なフレームワークが開発されてきました。有名なのは Google が開発している Tensorflow と Facebook が開発している PyTorch ですね。さらにこれらのフレームワークを手軽に試せるようなフレームワークも次々と登場してきました。Tensorflow ですと Keras が Tensorflow をバックエンドに使うようできます。PyTorch をバックエンドに使うフレームワークとして有名なのが fast.ai です。fast.ai は下のようなスローガンを掲げており、なるべく多くの人に深層学習に触れられる機会を与えることを目指していて、実際非常に使いやすいフレームワークです。

Being cool is about being exclusive, and that’s the opposite of what we want. We want to make deep learning as accessible as possible

この記事では、fast.ai の基本的な使い方について紹介したいと思います。

この記事で扱うこと

  • 動物の画像分類
  • ハイパーパラメータの調整
  • モデルの fine tune

データの準備

import fastai2.vision.all as fastai

path = fastai.untar_data(fastai.URLs.PETS)
pets = fastai.DataBlock(
    blocks = (fastai.ImageBlock, fastai.CategoryBlock),
    get_items = fastai.get_image_files,
    splitter = fastai.RandomSplitter(seed=42),
    get_y = fastai.using_attr(fastai.RegexLabeller(r"(.+)_\d+.jpg"), "name"),
    item_tfms = fastai.Resize(460),
    batch_tfms = fastai.aug_transforms(size=224, min_scale=0.75),
)

dls = pets.dataloaders(path/"images")

fast.ai に最初から用意されているペット画像を使って画像分類を試して見ます。fast.ai ではインポートにワイルドカード(*) を使うことが多いようですが、ここではわかりやすさのために fastai.vision.allfastai という名前でインポートします。

読み込むデータは、入力値が画像データ(ImageBlock) で 出力値がカテゴリ(CategoryBlock) です。カテゴリ名はファイル名から正規表現を使って抽出します(RegexLabeller(r"(.+)_\d+.jpg"), "name"))。さらに、画像の前処理としてサイズを揃え(Resize(460))、augmentation をします(aug_transforms(size=224, min_scale=0.75))。

きちんとデータが読み込まれたか確認してみます。

dls.show_batch(rows=2, cols=3)

うまく行っていれば下のように動物の写真が6枚表示されます。

f:id:pyhaya:20200316235953p:plain

また、DataBlock でどレくらいの画像が読み込まれ、どのような処理がなされたかは summary() メソッドを使って確認することができます。今、path には動物画像のデータセットを指定していますが、実際の画像はサブディレクトimages に入っているので summary() メソッドの引数には path/"images" で指定します。

pets.summary(path/"images")

出力が長いので一部を載せると下のような感じになります。

Setting-up type transforms pipelines
Collecting items from ~/.fastai/data/oxford-iiit-pet/images
Found 7390 items
2 datasets of sizes 5912,1478
Setting up Pipeline: PILBase.create
Setting up Pipeline: partial -> Categorize

Building one sample
  Pipeline: PILBase.create
    starting from
      ~/.fastai/data/oxford-iiit-pet/images/american_bulldog_30.jpg
    applying PILBase.create gives
      PILImage mode=RGB size=334x500
  Pipeline: partial -> Categorize
    starting from
      ~/.fastai/data/oxford-iiit-pet/images/american_bulldog_30.jpg
    applying partial gives
      american_bulldog
    applying Categorize gives
      TensorCategory(12)

Final sample: (PILImage mode=RGB size=334x500, TensorCategory(12))


Setting up after_item: Pipeline: Resize -> ToTensor
Setting up before_batch: Pipeline: 
Setting up after_batch: Pipeline: IntToFloatTensor -> AffineCoordTfm -> RandomResizedCropGPU -> LightingTfm

Building one batch
Applying item_tfms to the first sample:
  Pipeline: Resize -> ToTensor
    starting from
      (PILImage mode=RGB size=334x500, TensorCategory(12))
    applying Resize gives
...

訓練してみる

データは読み込めたので、訓練をしてみます。まずは試しに ResNet34 の学習済みモデルをfine tuneしてみます。

learn = fastai.cnn_learner(dls, fastai.resnet34, metrics=fastai.error_rate)
learn.fine_tune(2)

f:id:pyhaya:20200317000647p:plain

pandas の DataFrame を表示するときのようなデザインで各エポックの訓練状況が表示されます。さて訓練結果はどうなっているでしょうか?混同行列を見てみます。

interp = fastai.ClassificationInterpretation.from_learner(learn)
interp.plot_confusion_matrix(figsize=(12, 12), dpi=60)

f:id:pyhaya:20200317000824p:plain

2行のコードで seaborn を使ったときのようなきれいなグラフが表示されます。

ハイパーパラメータの調整

ハイパーパラメータの調整も、fast.ai ではそれを支援する機能があります。

lr_min, lr_steep = learn.lr_find()

この一つのコマンドで、学習率を変化させたときの loss の変化を調べることができます。loss が最も急激に減少する学習率と、最も小さくなる学習率が lr_steep, lr_min に入ります。これと同時に、loss の学習率依存性のグラフが表示されます。
f:id:pyhaya:20200319080522p:plain

モデルの細かい調整

モデルによっては、学習率を層によって変化させたいこともあります。fast.ai ではこのようなことも簡単にできます。

learn.fit_one_cycle(12, lr_max=slice(1e-6, 1e-4))

lr_max にスライスを指定することによって学習率を 1e-6 から 1e-4 まで変化させていくことが可能です。

また、モデルの学習を高速化させ、メモリ消費を抑える手法として混合精度の訓練があります。これも簡単に実現できます。

learn = fastai.cnn_learner(dls, fastai.resnet50, metrics=fastai.error_rate).to_fp16()

最後に、この混合精度モデルで、最初の3エポックは fine tune して、その後に全てのパラメータをフリーにして訓練してみます。

learn.fine_tune(6, freeze_epochs=3)
learn.recorder.plot_loss()

f:id:pyhaya:20200319081714p:plain

まとめ

この記事では、fast.ai の初歩的な使い方をザッと見てきました。データセットの準備や訓練が簡単にできることはもちろん、モデルの調整や訓練結果の確認のためのツールも非常に豊富にもっていることがわかると思います。私もまだ触り始めたばかりですがこれからどんどん使っていきたいと思います。