fast.ai で deep learning を勉強しよう(5)Performance Tips and Tricks

fast.ai を WindowsPC で勉強する時の環境整備の話です。

Windows10 Python3.7.1 fastai 1.0.57 Pytorch1.2.0 (py3.7_cuda100_cudnn7_1) cudatoolkit10.0.130 cudnn7.6.0

画像読込の高速化

fast.ai に書かれている Performance Tips and Tricks を解説します。

Performance Tips and Tricks | fastai

Jupyter から下記を実行すると、ここに書かれている環境がすでに整っているかどうかの確認ができます。

import fastai.utils
fastai.utils.check_perf()

Anaconda Prompt から確認する時は次のようになります。

python -c "import fastai.utils; fastai.utils.check_perf()"

実行するとチェック結果が表示されます。

・推奨項目がある場合

*** libjpeg-turbo status
✘ libjpeg-turbo is not on. 
It's recommended you install libjpeg-turbo 
to speed up JPEG decoding. 
See https://docs.fast.ai/performance.html#libjpeg-turbo

*** Pillow-SIMD status
✘ Running Pillow 5.4.1; 
It's recommended you install Pillow-SIMD 
to speed up image resizing and other operations. 
See https://docs.fast.ai/performance.html#pillow-simd

*** CUDA status
✘ You are running pytorch built against cuda 8.0, 
your NVIDIA driver 431.36 supports cuda10. 
See https://pytorch.org/get-started/locally/ 
to install pytorch built against the faster CUDA version.

・既に対応済の場合

*** libjpeg-turbo status
✔ libjpeg-turbo is on

*** Pillow-SIMD status
✔ Running Pillow-SIMD 6.0.0.post0

*** CUDA status
✔ Running the latest CUDA 10.0 with NVIDIA driver 431.36

チェック結果に対応すると、CPUでJPEG画像を読み込んで解凍する部分が高速化されるので、機械学習のトレーニング時間が短縮されると言っています。

libjpeg-turbo のインストール

SIMD instructions (MMX, SSE2, AVX2, NEON, AltiVec) を使用して JPEG の圧縮/回答を libjpeg よりも高速で実行するライブラリーとの事です。

libtiff を uninstall して libjpeg-turbo をインストールします。 Jupyter から作業をする時には「!」を先頭につけてコマンドを実行します。

!conda uninstall --force jpeg libtiff -y
!conda install -c conda-forge libjpeg-turbo

Pillow-SIMD のインストール

SIMD instructions (MMX, SSE2, AVX2, NEON, AltiVec) を使用して 画像処理を高速化する為に、Pillow を Pillow-SIMD に置き換えます。 Pillow-SIMD のベンチマークがここにあります。

Pillow Performance

バイナリーの入手とインストール

Windows用はコンパイルされたものが用意されていないので、次の非公式サイトから対応するものをダウンロードします。 Python Extension Packages for Windows - Christoph Gohlke

ダウンロードしたファイルの保存先を指定してPillow-SIMDをインストールします。 以下はpython3.7のダウンロードファイルを Jupyter からインストールする場合です。

!pip install 保存ディレクトリ\Pillow_SIMD‑6.0.0.post0+avx2‑cp37‑cp37m‑win_amd64.whl
Pillow-SIMD インストールの確認方法

Pillow-SIMD が使われるようになったかどうかは、次の様にして Pillow のバージョンを表示してみます。

from PIL import Image
print(Image.PILLOW_VERSION)

Pillow のバージョンに .postX が付いているならば SIMD版が使われています。

CUDAバージョンアップ

現時点での Pytorch の CUDA 対応バージョンは 10.0 のようなので、CUDA10.0.130 をダウンロードしてインストールします。cudnnも対応するものをNVIDIAからダウンロードして対応するフォルダーにコピーします。

cudnn-10.0-windows10-x64-v7.6.2.24.zip

f:id:feynman911:20190826141749j:plain

以前のバージョンのCUDAとは別のフォルダーにインストールされるので、前バージョンはそのまま残しておいても問題ありません。 新しいバージョンがインストールされると、環境変数にそれがセットされるので、通常は新しい方が使用される環境となります。

f:id:feynman911:20190826141623j:plain

旧バージョンを削除したい場合には、「設定」の「アプリと機能」から削除したいものをアンインストールします。アンインストールしても手動でコピーしたcudnnはそのまま残るので、消したい場合には、フォルダーを開いて手動で削除します。

cudatoolkit のバージョンを CUDAのバージョンに合わせます。

f:id:feynman911:20190826143731j:plain

GPU Notes CUDAメモリー量の確認

Working with GPU | fastai

fastai のライブラリーをインストールします。

!conda install nvidia-ml-py3 -c fastai

次の様に実行すると有効なGPUバイスがリストアップされます。

from pynvml import *
nvmlInit()
try:
    deviceCount = nvmlDeviceGetCount()
    for i in range(deviceCount):
        handle = nvmlDeviceGetHandleByIndex(i)
        print("Device", i, ":", nvmlDeviceGetName(handle))
except NVMLError as error:
    print(error)

また、次のように実行するとDevice0のメモリーの使用量を見ることができます。

from pynvml import *
nvmlInit()
handle = nvmlDeviceGetHandleByIndex(0)
info = nvmlDeviceGetMemoryInfo(handle)
print("Total memory:", info.total)
print("Free memory:", info.free)
print("Used memory:", info.used)

ただ確認するだけならば、ELSA System Graph を使用した方が簡単です。

下記のコマンドで確保されたGPUモリーを開放する事ができます。

import torch
torch.cuda.empty_cache()

モリー不足対策

CUDA out of memory が出てエラーで実行できない時はメモリーの消費量を抑える必要があります。

バッチサイズを小さくする

DataBunch の引数のバッチサイズ bs の値を小さくします。
バッチサイズは省略されると64です。

画像サイズを小さくする

引数のリサイズ画像サイズを小さくします。

data = ImageDataBunch.from_name_re(path_img, fnames, pat, ds_tfms=get_transforms(), size=224, bs=bs ).normalize(imagenet_stats)

size = 224 は 224x224画素にすることを表しています。

計算を16bit にする

callbacks.fp16 | fastai

レーニング時の計算精度を16bitに落とすことで、メモリーの消費量を少なくすることができます。 例えば

learn = Learner.create_unet(data,models.resnet34,metrics).to_fp16()

の様に to_fp16( ) を付けます。

CPUで処理したい時

GPUのメモリーが少なくて処理できないのでメインメモリーで処理したい時には
はじめに

defaults.device = torch.device('cpu')

を追加します。

使用済メモリーの解放

restartせずに別の事をしたい時に使用しないGPUモリーを開放したい時には次の様にlearnerをdestroyする事で解放されます。

learn.destroy()

learnerを保存する時にオプションを付けて開放することも出来ます。

learn.export('raind_model.pkl', destroy = true)

fastai用 Jupyter の起動バッチファイル作成

ショートカットを作成してワンクリックで fastai 環境の Jupyter を立ち上げるには、リンク先を次のようにします。

C:\A3\python.exe C:\A3\cwp.py C:\A3\envs\fastai C:\A3\envs\fastai\python.exe C:\A3\envs\fastai\scripts\jupyter-notebook-script.py C:\Python

リンク先の文字の意味は以下のようなものなので、各自の環境で修正する必要があります。
C:\A3 : Anacondaインストールフォルダー
fastai : fastai仮想環境
C:\Python : Jupyter で開くフォルダー

学習結果を保存して使用する時

学習後、結果をファイルに保存しておきます。

learn.export('trained_model.pkl')

使用する時に、それを読み出します。

from fastai.vision import *
path = Path('data/bears')
learn = load_learner(path,'trained_model.pkl')

判定したい画像を読み込んでpredictに渡します。

img = open_image(path/'black'/'00000022.jpg')
pred_class, pred_idx, outputs = learn.predict(img)
pred_class