PyTorch 2.0 : 画像と動画 : 配備のために Vision Transformer を最適化する

PyTorch 2.0 チュートリアル : 画像と動画 : 配備のために Vision Transformer を最適化する (翻訳/解説)

翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 05/05/2023 (2.0.0)

* 本ページは、PyTorch 2.0 Tutorials の以下のページを翻訳した上で適宜、補足説明したものです:

* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

クラスキャット 人工知能 研究開発支援サービス

クラスキャット は人工知能・テレワークに関する各種サービスを提供しています。お気軽にご相談ください :

◆ 人工知能とビジネスをテーマに WEB セミナーを定期的に開催しています。スケジュール
  • お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。

お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。

  • 株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション
  • sales-info@classcat.com  ;  Website: www.classcat.com  ;   ClassCatJP

 

PyTorch 2.0 チュートリアル : 画像と動画 : 配備のために Vision Transformer を最適化する

Vision Transformer モデルは、あらゆる種類の SOTA 結果を獲得するために自然言語処理で導入された、最先端のアテンション・ベースの transformer モデルをコンピュータビジョン・タスクに応用します。Facebook Data-efficient 画像 Transformer DeiT は画像分類のために ImageNet 上で訓練された Vision Transformer モデルです。

このチュートリアルでは、最初に DeiT が何であるかそれをどのように利用するかをカバーし、それからモデルのスクリプト化、量子化、最適化そして iOS と Android apps での利用の完全なステップを通り抜けます。量子化、最適化モデルと非量子化、非最適化モデルのパフォーマンスも比較し、ステップとともにモデルに量子化と最適化を適用することの利益を示します。

 

DeiT とは何か

2012 年に深層学習がテイクオフしてから畳込みニューラルネットワーク (CNN) は画像分類のための主要モデルを持ってきましたが、CNN は典型的には SOTA 結果を獲得するには訓練のために何億もの画像を要求します。DeiT は遥かに少ないデータを必要とする vision transformer モデルで画像分類を遂行する際にトップクラスの CNN と競争するために訓練のためのリソースを計算し、これは DeiT の 2 つの主要コンポーネントにより可能にされます :

  • データ増強、これは遥かに大規模なデータセット上の訓練をシミュレートします ;
  • ネイティブ distillation (蒸留)、これは transformer ネットワークに CNN の出力から学習することを可能にします。

DeiT はデータとリソースへの制限されたアクセスで Transformer がコンピュータビジョン・タスクに成功的に適用できることを示します。DeiT のより多くの詳細については、レポジトリ論文 を見てください。

 

DeiT で画像を分類する

DeiT を使用してどのように画像を分類するかの詳細については DeiT レポジトリの README に従ってください、あるいは
素早いテストのためには、最初に必要なパッケージをインストールしてください :

pip install torch torchvision timm pandas requests

Google Colab で実行するには、以下のコマンドを実行して依存関係をインストールしてから :

!pip install timm pandas requests

下のスクリプトを実行します :

from PIL import Image
import torch
import timm
import requests
import torchvision.transforms as transforms
from timm.data.constants import IMAGENET_DEFAULT_MEAN, IMAGENET_DEFAULT_STD

print(torch.__version__)
# should be 1.8.0


model = torch.hub.load('facebookresearch/deit:main', 'deit_base_patch16_224', pretrained=True)
model.eval()

transform = transforms.Compose([
    transforms.Resize(256, interpolation=3),
    transforms.CenterCrop(224),
    transforms.ToTensor(),
    transforms.Normalize(IMAGENET_DEFAULT_MEAN, IMAGENET_DEFAULT_STD),
])

img = Image.open(requests.get("https://raw.githubusercontent.com/pytorch/ios-demo-app/master/HelloWorld/HelloWorld/HelloWorld/image.png", stream=True).raw)
img = transform(img)[None,]
out = model(img)
clsidx = torch.argmax(out)
print(clsidx.item())
2.0.0+cu117
Downloading: "https://github.com/facebookresearch/deit/zipball/main" to /var/lib/jenkins/.cache/torch/hub/main.zip
Downloading: "https://dl.fbaipublicfiles.com/deit/deit_base_patch16_224-b5f2ef4d.pth" to /var/lib/jenkins/.cache/torch/hub/checkpoints/deit_base_patch16_224-b5f2ef4d.pth

269

この出力は 269 になるはずです、これはクラスインデックスから ラベルファイル への ImageNet リストに従って、‘timber wolf, grey wolf, gray wolf, Canis lupus’ にマップされます。

画像を分類するために DeiT モデルを利用できることを検証した今、モデルが iOS と Android apps 上で動作できるようにどのように変更するかを見ましょう。

 

DeiT のスクリプト化

モバイル上でモデルを使用するため、最初にモデルをスクリプト化する必要があります。素早い概要のためには Script and Optimize レシピ を見てください。前のステップで使用された DeiT モデルをモバイル上で実行できる TorchScript 形式に変換するためには下のコードを実行してください。

model = torch.hub.load('facebookresearch/deit:main', 'deit_base_patch16_224', pretrained=True)
model.eval()
scripted_model = torch.jit.script(model)
scripted_model.save("fbdeit_scripted.pt")
Using cache found in /var/lib/jenkins/.cache/torch/hub/facebookresearch_deit_main

サイズ約 346MB のスクリプト化されたモデルファイル fbdeit_scripted.pt が生成されます。

 

DeiT を量子化する

ほぼ同じである推論精度を保持する一方で訓練モデルのサイズを本質的に減じるには、量子化がモデルに適用できます。DeiT で使用される transformer モデルのおかげで、動的量子化をモデルに容易に適用できます、何故ならば動的量子化は LSTM と transformer モデルのために最善に動作するからです (より詳細については ここ を見てください)。

今は下のコードを実行します :

# Use 'x86' for server inference (the old 'fbgemm' is still available but 'x86' is the recommended default) and ``qnnpack`` for mobile inference.
backend = "x86" # replaced with ``qnnpack`` causing much worse inference speed for quantized model on this notebook
model.qconfig = torch.quantization.get_default_qconfig(backend)
torch.backends.quantized.engine = backend

quantized_model = torch.quantization.quantize_dynamic(model, qconfig_spec={torch.nn.Linear}, dtype=torch.qint8)
scripted_quantized_model = torch.jit.script(quantized_model)
scripted_quantized_model.save("fbdeit_scripted_quantized.pt")
/opt/conda/lib/python3.10/site-packages/torch/ao/quantization/observer.py:214: UserWarning:

Please use quant_min and quant_max to specify the range for observers.                     reduce_range will be deprecated in a future release of PyTorch.

これはモデル fbdeit_quantized_scripted.pt のスクリプト化そして量子化されたバージョンを生成します、サイズ約 89MB を持ち、346MB の非量子化モデルサイズの 74% 縮小です!

同じ推論結果を生成するために scripted_quantized_model を利用できます :

out = scripted_quantized_model(img)
clsidx = torch.argmax(out)
print(clsidx.item())
# The same output 269 should be printed
269

 

DeiT を最適化する

モバイル上で量子化そしてスクリプト化されたモデルを使用する前の最後のステップはそれを最適化することです :

from torch.utils.mobile_optimizer import optimize_for_mobile
optimized_scripted_quantized_model = optimize_for_mobile(scripted_quantized_model)
optimized_scripted_quantized_model.save("fbdeit_optimized_scripted_quantized.pt")

生成された fbdeit_optimized_scripted_quantized.pt ファイルは量子化、スクリプト化、しかし非最適化モデルとおよそ同じサイズを持ちます。推論結果は同じままです。

out = optimized_scripted_quantized_model(img)
clsidx = torch.argmax(out)
print(clsidx.item())
# Again, the same output 269 should be printed
269

 

インタープリタを使用する

Lite インタープリタがどのくらいのモデルサイズ縮小と推論スピードアップの結果を出せるかを見るために、モデルの lite バージョンを作成しましょう。

optimized_scripted_quantized_model._save_for_lite_interpreter("fbdeit_optimized_scripted_quantized_lite.ptl")
ptl = torch.jit.load("fbdeit_optimized_scripted_quantized_lite.ptl")

モバイル上で lite バージョンを実行するとき lite モデルサイズは非 lite バージョンと同等ですが、推論スピードアップは期待されます。

 

推論スピードの比較

推論スピードが 4 つのモデル – 元のモデル、スクリプト化モデル、量子化とスクリプト化モデル、最適化・量子化とスクリプト化モデル – についてどのように異なるかを見るには、下のコードを実行します :

with torch.autograd.profiler.profile(use_cuda=False) as prof1:
    out = model(img)
with torch.autograd.profiler.profile(use_cuda=False) as prof2:
    out = scripted_model(img)
with torch.autograd.profiler.profile(use_cuda=False) as prof3:
    out = scripted_quantized_model(img)
with torch.autograd.profiler.profile(use_cuda=False) as prof4:
    out = optimized_scripted_quantized_model(img)
with torch.autograd.profiler.profile(use_cuda=False) as prof5:
    out = ptl(img)

print("original model: {:.2f}ms".format(prof1.self_cpu_time_total/1000))
print("scripted model: {:.2f}ms".format(prof2.self_cpu_time_total/1000))
print("scripted & quantized model: {:.2f}ms".format(prof3.self_cpu_time_total/1000))
print("scripted & quantized & optimized model: {:.2f}ms".format(prof4.self_cpu_time_total/1000))
print("lite model: {:.2f}ms".format(prof5.self_cpu_time_total/1000))
original model: 298.14ms
scripted model: 322.95ms
scripted & quantized model: 226.33ms
scripted & quantized & optimized model: 207.08ms
lite model: 210.38ms

Google Colab 上で実行した結果は :

original model: 1236.69ms
scripted model: 1226.72ms
scripted & quantized model: 593.19ms
scripted & quantized & optimized model: 598.01ms
lite model: 600.72ms

以下の結果は各モデルでかかった推論時間と元のモデルに相対する各モデルのパーセンテージ削減を要約しています。

import pandas as pd
import numpy as np

df = pd.DataFrame({'Model': ['original model','scripted model', 'scripted & quantized model', 'scripted & quantized & optimized model', 'lite model']})
df = pd.concat([df, pd.DataFrame([
    ["{:.2f}ms".format(prof1.self_cpu_time_total/1000), "0%"],
    ["{:.2f}ms".format(prof2.self_cpu_time_total/1000),
     "{:.2f}%".format((prof1.self_cpu_time_total-prof2.self_cpu_time_total)/prof1.self_cpu_time_total*100)],
    ["{:.2f}ms".format(prof3.self_cpu_time_total/1000),
     "{:.2f}%".format((prof1.self_cpu_time_total-prof3.self_cpu_time_total)/prof1.self_cpu_time_total*100)],
    ["{:.2f}ms".format(prof4.self_cpu_time_total/1000),
     "{:.2f}%".format((prof1.self_cpu_time_total-prof4.self_cpu_time_total)/prof1.self_cpu_time_total*100)],
    ["{:.2f}ms".format(prof5.self_cpu_time_total/1000),
     "{:.2f}%".format((prof1.self_cpu_time_total-prof5.self_cpu_time_total)/prof1.self_cpu_time_total*100)]],
    columns=['Inference Time', 'Reduction'])], axis=1)

print(df)

"""
        Model                             Inference Time    Reduction
0   original model                             1236.69ms           0%
1   scripted model                             1226.72ms        0.81%
2   scripted & quantized model                  593.19ms       52.03%
3   scripted & quantized & optimized model      598.01ms       51.64%
4   lite model                                  600.72ms       51.43%
"""
                                    Model Inference Time Reduction
0                          original model       298.14ms        0%
1                          scripted model       322.95ms    -8.32%
2              scripted & quantized model       226.33ms    24.09%
3  scripted & quantized & optimized model       207.08ms    30.54%
4                              lite model       210.38ms    29.44%

'\n        Model                             Inference Time    Reduction\n0\toriginal model                             1236.69ms           0%\n1\tscripted model                             1226.72ms        0.81%\n2\tscripted & quantized model                  593.19ms       52.03%\n3\tscripted & quantized & optimized model      598.01ms       51.64%\n4\tlite model                                  600.72ms       51.43%\n'

 

更に学習する

 

以上