【Fast.ai Vision】Single-Label Classificationの基礎
サマリー
Fast.aiのversion2で関数が結構変わっていたので、Single-Label Classificationを行うために最低限の知識をメモとしてまとめる。 基本的にはこちらの書籍に書かれている。
Deep Learning for Coders With Fastai and Pytorch: AI Applications Without a Phd
- 作者:Howard, Jeremy,Gugger, Sylvain
- 発売日: 2020/08/11
- メディア: ペーパーバック
本格的に使う場合は、csvからのデータ取得やaugumentationも既存ツールでないものを使ったほうがいい、学習の仕方の工夫などがあるが、今回は取り扱わず、別記事とする。
環境準備
condaでInstallすることが推奨されている。まっさらな環境のときはcondaをオススメする。colabの場合はPytorchも使える状況なので、pip install
で問題ない。
# Colabの場合(すでにPytorch環境が整っている場合)
!pip install -Uqq fastai
# まっさらな環境の場合(Pytorch環境もなく、1から環境作る場合)
conda install -c fastai -c pytorch fastai
Colabではない環境でどうしてもpipで環境を作りたい場合は、以下で適切にPytorchのinstallの設定を調べてから行う。 pytorch.org
モジュールの読み込み
賛否両論あるが、Fastaiはこの様に一行ですべて読込させる方針。
from fastai.vision.all import *
どのような形で必要なモジュールを読み込んでいるのかを把握したい場合は、いかから追ってみるといい。必要なモジュールだけを、すべて個別で読み込もうと試みたが、ただ使うだけなら度々import errorが起きるため諦めて、Fastaiの方針にのることにした。
Data Blockについて
DataLoadersの準備
以前はDataBunchというクラスでDataSetsやDataLoadersを作成したがversion2以降では変更となったようだ
DataBlockは、以下の引数を与えるとのDatasetsまたはDataLoadersを作成できる。
今回は比較的簡単にpathを取得できる例で説明する。Multi-Label ClassificationやデータセットのPATHがcsvで提供されている場合のDataBlockの作り方は別記事にする。
blocks
はsinglelabelならblocks = (ImageBlock, CategoryBlock)
で- ImageBlockはTransformBlockのはPILで画像を読み込むための派生クラス
get_items
は画像ファイルのパスを取得する方法、例えばget_image_filesを使う。splitter
は、データを分割する方法、以下のsplitterから状況に応じて使い分ける。get_x
は、入力に何かを適用する必要があるなら記述。get_y
は、ターゲットに何かを適用する必要があるなら記述。多くは予測ラベルの取得方法の関数。例えば、画像ファイル名から0, 1にする関数や画像ファイル名から名前やカテゴリ名を取得する方法を記述。 例えば、RegexLabellerとusing_attrを使うなどする。item_tfms
は、batchが形成される前にアイテムに適用される変換を記述。GPUにコピーされる前に個々の画像に適用される。例えばresize。batch_tfms
は、batchが形成された後に適用される変換を記述。GPU上で一括して適用される。例えばaug_transformsなどを使う。
item_tfmsとbatch_tfmsの両者に使う関数は以下が参考になる。 Data augmentation in computer vision | fastai
# 例えば、path/"images"以下に画像データそれぞれのPathが入ってるとすると data = DataBlock(blocks = (ImageBlock, CategoryBlock), get_items=get_image_files, splitter=RandomSplitter(seed=42), get_y=using_attr(RegexLabeller(r'(.+)_\d+.jpg$'), 'name'), item_tfms=Resize(460), batch_tfms=aug_transforms(size=224, min_scale=0.75)) dls = data.dataloaders(path/"images") # 実際のカテゴリ、カテゴリ数を表示 print(dls.vocab) len(dls.vocab)
DataLoadersの確認
DataLoadersの中身をバッチ分確認したい場合は以下。 デフォルトでは、バッチサイズは64。
x, y = dls.one_batch() # y # TensorCategory([18, 36, 35, 22, 17, 26, 0, 21, 32, 34, 1, 7, 1, 20, 31, 15, 31, 34, 5, 1, 22, 33, 21, 26, 0, 9, 15, 7, 13, 16, 28, 23, 18, 5, 1, 5, 15, 6, 5, 12, 1, 24, 2, 16, 6, 5, 8, 11, 30, 5, 22, 34, 11, 18, 0, 19, 25, 28, 32, 9, 21, 6, 17, 13], device='cuda:0')
画像自体を確認するときは[show_batch] (https://docs.fast.ai/data.core.html#TfmdDL.show_batch)で表示できる。以下は、The Oxford-IIIT Pet Datasetを読み込んだときの例。
dls.show_batch(nrows=4, ncols=4, max_n=16)
学習(Fine turning)
learnerの設定
基本的に最低3つ設定する。
- DataLoaders
- モデル
- Metrics
モデルは自分で構築したものも使えるし、以下のpretrainedされたモデルアーキテクチャも使える。 pytorch.org
Metricsは自分で構築したものも使えるし、以下の用意されたMetricsを使える。
learn = cnn_learner(dls, resnet34, metrics=error_rate)
モデル構造のチェック
cnn_learnerで作っている場合は、選択したモデルの最後の層だけcutして、DataLoaderに合わせた数にセットされる。以下で確認できる。
learn.model
転移学習とFine turning
転移学習は、
事前に学習した重みや他のレイヤーの重みを変更せずに(freezing)、目的のタスクを正しく達成するように最終層の完全結合層(fully conect layer)はランダム重みを持つ新しいものに置き換えてこの重みを置き換えた最終層のみの重みだけを更新するように学習すること。
Fine turningは、
転移学習後の微調整で、転移学習後に他のレイヤーの重みの変更を許して(unfreezing)、目的のタスクを正しく達成する重みに置き換えて学習すること。
多くの場合で、以下のやり方で転移学習・Fine turningすることでよりLossが下がることが知られている。
- 最終層以外をfreezingして学習する。
- unfreezeする。
- 更に学習する。
Fastai version1のときは
learn.fit_one_cycle(1) unfreeze() learn.fit_one_cycle(1)
のようにやっていたが、version2から新たにfine_tuneというmethodが追加された。unfreezingで何epoch学習するかが引数。freezingで何epoch学習するかは別途設定できる(デフォルトでは1)
なので、上記と同義なのが以下
learn.fine_tune(1)
ただ、基本的には、fit_one_cycleとlr_findを組み合わせて、freezing時でも最適な学習率を設定し、unfreezingでも最適な学習率を設定し(最初は大きな値、徐々に小さく)学習することが望ましい。
以下に、適切な学習率を探索する方法について書いた。
適切な学習率の探索
Leslie Smithによって、learning rate finderというアイディアが考案された。 arxiv.org 内容の詳細は省くがその論文は以下なので、参考にするといい。学習率の良い値は、
- ダイバージェンス前の最小値の10分の1
- 勾配が一番急な時
learnerを設定したら、以下のようにすれば、上記の2つの値が返ってくる。
learn = cnn_learner(dls, resnet34, metrics=error_rate)
learn.lr_find()
# SuggestedLRs(lr_min=0.012022644281387329, lr_steep=0.0063095735386013985)
まず、freezingしている状態で実際にその値を見た上で適切な学習率を考える。上記の例だと、以下のようにするのが例となる。
learn = cnn_learner(dls, resnet34, metrics=error_rate) learn.fine_tune(2, base_lr=3e-3)
fit_one_cycleを使った改善
fit_one_cycleはfine_tuneを使わずにモデルを学習する方法として用意されていて、より自由度高く学習の設計ができる。低い学習率で学習を開始し、最初の部分では徐々に学習率を上げ、最後の部分では再び学習率を徐々に下げていくことが可能。
- 学習率を探索する。
- freezingして、最終層の重みだけを更新するように学習する。
- unfreezingする。再度学習率を探索する。
- すべての層の重みを更新するように学習する。
# 1. 学習率を探索する。 learn = cnn_learner(dls, resnet34, metrics=error_rate) learn.lr_find() SuggestedLRs(lr_min=0.012022644281387329, lr_steep=0.0063095735386013985)
# 2. 最終層の重みだけを更新するように学習する。 learn = cnn_learner(dls, resnet34, metrics=error_rate) learn.fit_one_cycle(3, 3e-3)
# 3. unfreezingする。再度学習率を探索する。
learn.unfreeze()
learn.lr_find()
上記の例だと、freezing前の探索時のLossの落ち込みに比べて、unfreezing後の探索時の急激なlossの落ち込みがないのは、学習がある程度進んでいるからと考えられる。この場合だと、以下のように学習をすすめるなど、考えられる。
# 4. すべての層の重みを更新するように学習する。 learn.fit_one_cycle(6, lr_max=1e-5)
Discriminative Learning Rates
Jason Yosinskiらによって、支持されているものとして、ネットワークの初期層には低い学習率を使い、最終層には高い学習率を使うのが良いとされている。論文は以下。 arxiv.org
例えば、これまでの内容をふまえると、以下のような流れで行うことができる。
learn = cnn_learner(dls, resnet34, metrics=error_rate) learn.fit_one_cycle(3, 3e-3) learn.unfreeze() learn.fit_one_cycle(12, lr_max=slice(1e-6,1e-4)) # lossのプロット learn.recorder.plot_loss()
Mixed Precision
より、深いネットワークを使ったときの問題点としては、
- メモリ不足
- 時間がかかる
解決策として、以下が考えられる。
- メモリ不足に関してはバッチサイズを減らして学習させる。
- 時間がかかることに関しては、Mixed Precisionとして、半精度浮動小数点(fp16)を使うことで数倍早くなる。
Fastai version2では半精度浮動小数点はfrom fastai.callback.fp16 import *
を読み込むことで使うことができる。
(fastaiのバージョンにもよる。callbackのうちfp16についてはfrom fastai.vision.all import *
で自動的に読み込まれることもある)
from fastai.callback.fp16 import * learn = cnn_learner(dls, resnet50, metrics=error_rate).to_fp16() learn.fine_tune(6, freeze_epochs=3)
精度解釈
学習時にvalidation lossで自分で決めたmetricで精度は理解できているものの、実際にどのクラスとどのクラスが間違えやすいか、その程度はどの程度かを把握するために、confusion matrixで予測があっているかを直感的に理解する。
confusion matrix
interp = ClassificationInterpretation.from_learner(learn) interp.plot_confusion_matrix(figsize=(12,12), dpi=60)
クラスを間違っているかのチェック
間違っているクラス同士をチェックするにはmost_confused
というメソッドが用意されている
interp.most_confused(min_val=5)
参考になる書籍
FastaiとPytorchを使って画像認識や協調フィルタリング・NLP関連のタスクを例として、かなり詳細まで書かれている。Fastaiを使っていくなら一読することをおすすめする。
Deep Learning for Coders With Fastai and Pytorch: AI Applications Without a Phd
- 作者:Howard, Jeremy,Gugger, Sylvain
- 発売日: 2020/08/11
- メディア: ペーパーバック