本記事はこちらのブログを参考にしています。
翻訳にはアリババクラウドのModelStudio(Qwen)を使用しております。
物体検出モデルのポストプロセッシング効率を向上させるために、TorchScriptのカスタムC++オペレータを使用して、従来Pythonで実現されていたポストプロセッシングネットワークを作成できます。その後、モデルをエクスポートし、機械学習プラットフォームAI(PAI)-Bladeを使用してモデルを最適化します。この記事では、TorchScriptカスタムC++オペレータを使用して物体検出モデルのポストプロセッシングネットワークを作成し、PAI-Bladeを使用してモデルを最適化する方法について説明します。
背景情報
RetinaNetは、一ステージの領域に基づく畳み込みニューラルネットワーク(R-CNN)タイプの検出ネットワークです。RetinaNetの基本構造は、バックボーン、複数のサブネットワーク、およびNon-Maximum Suppression(NMS)から成ります。NMSはポストプロセッシングアルゴリズムです。RetinaNetは多くのトレーニングフレームワークで実装されています。Detectron2はRetinaNetを使用する代表的なトレーニングフレームワークであり、Detectron2のscripting_with_instancesメソッドを呼び出してRetinaNetモデルをエクスポートし、PAI-Bladeを使用してモデルを最適化することができます。詳細については、「Detectron2フレームワークのRetinaNetモデルをPAI-Bladeで最適化する方法」をご覧ください。物体検出モデルのポストプロセッシングネットワークのプログラムロジックは、大抵の場合、ボックスの計算とフィルタリング、NMSのロジックを含んでいます。これらのロジックをPythonで実装すると効率が低いため、代わりにTorchScriptカスタムC++オペレータを使用してポストプロセッシングネットワークを作成し、モデルをエクスポートしてPAI-Bladeを使用して最適化することができます。
制限事項
このトピックの手順を行う環境には、以下のバージョン要件を満たす必要があります。
- システム環境: Python 3.6以降、GNU Compiler Collection (GCC) 5.4以降、NVIDIA Tesla T4、CUDA 10.2、cuDNN 8.0.5.39
- フレームワーク: PyTorch 1.8.1以降、Detectron2 0.4.1以降
- 推論最適化ツール: PAI-Blade V3.16.0以降
手順
PAI-BladeとカスタムC++オペレータを使用してRetinaNetモデルを最適化するには、以下のステップを実行します:
-
ステップ1: TorchScriptカスタムC++オペレータを含むPyTorchモデルを作成
RetinaNetモデルのポストプロセッシングネットワークをTorchScriptカスタムC++オペレータを使用して構築します。 -
ステップ2: TorchScriptモデルをエクスポート
Detectron2のTracingAdapterまたはscripting_with_instancesメソッドを呼び出してRetinaNetモデルをエクスポートします。 -
ステップ3: PAI-Bladeを使用してモデルを最適化
blade.optimize
メソッドを呼び出してモデルを最適化し、最適化されたモデルを保存します。 -
ステップ4: 最適化されたモデルを読み込み実行
最適化されたモデルがパフォーマンステストを通過し、期待に合った場合、推論のために最適化されたモデルを読み込みます。
ステップ1: TorchScriptカスタムC++オペレータを含むPyTorchモデルを作成
PAI-BladeはTorchScriptカスタムC++オペレータとシームレスに統合されています。このステップでは、それらのオペレータを使用してRetinaNetモデルのポストプロセッシングネットワークを構築する方法を説明します。TorchScriptカスタムC++オペレータに関する詳細は、EXTENDING TORCHSCRIPT WITH CUSTOM C++ OPERATORSをご覧ください。この記事で説明するRetinaNetモデルのポストプロセッシングネットワークのプログラムロジックは、NVIDIAのオープンソースコミュニティからのものです。詳細については、retinanet-examplesをご覧ください。ここでの核心的なコードは、カスタムオペレータの開発と実装方法を示すための例として使用されます。
-
サンプルコードをダウンロードし、展開します。
wget_disabled -nv https://pai-blade.oss-cn-zhangjiakou.aliyuncs.com/tutorials/retinanet_example/retinanet-examples.tar.gz -O retinanet-examples.tar.gz tar xvfz retinanet-examples.tar.gz 1>/dev/null
-
TorchScriptカスタムC++オペレータをコンパイルします。PyTorchはカスタムオペレータのコンパイルにCMakeでのビルド、JITコンパイルでのビルド、Setuptoolsでのビルドの3つの方法を提供しています。詳細については、EXTENDING TORCHSCRIPT WITH CUSTOM C++ OPERATORSをご覧ください。これらのコンパイル方法は異なるシーンに適しており、ニーズに応じて選択可能です。この例では、JITコンパイルでのビルド方法を使用して操作を簡素化しています。以下はサンプルコードの例です:
import torch.utils.cpp_extension import os codebase = 'retinanet-examples' sources = ['csrc/extensions.cpp', 'csrc/cuda/decode.cu', 'csrc/cuda/nms.cu',] sources = [os.path.join(codebase, src) for src in sources] torch.utils.cpp_extension.load( name='custom', sources=sources, build_directory=codebase, extra_include_paths=['/usr/local/TensorRT/include/', '/usr/local/cuda/include/', '/usr/local/cuda/include/thrust/system/cuda/detail'], extra_cflags=['-std=c++14', '-O2', '-Wall'], extra_cuda
出力テキスト:
def adapter_forward(self, batched_inputs: Tuple[Dict[str, torch.Tensor]]):
images = self.preprocess_image(batched_inputs)
features = self.backbone(images.tensor)
features = [features[f] for f in self.head_in_features]
cls_heads, box_heads = self.head(features)
cls_heads = [cls.sigmoid() for cls in cls_heads]
box_heads = [b.contiguous() for b in box_heads]
# ポストプロセスングネットワークの構築。strides = [images.tensor.shape[-1] // cls_head.shape[-1] for cls_head in cls_heads]
decoded = [
decode_cuda(
cls_head,
box_head,
anchor.view(-1),
stride,
self.test_score_thresh,
self.test_topk_candidates,
)
for stride, cls_head, box_head, anchor in zip(
strides, cls_heads, box_heads, self.cell_anchors
)
]
# 最大値抑圧の実装。decoded = [torch.cat(tensors, 1) for tensors in zip(decoded[0], decoded[1], decoded[2])]
return nms_cuda(decoded[0], decoded[1], decoded[2], self.test_nms_thresh, self.max_detections_per_image)
from detectron2.modeling.meta_arch import retinanet
# RetinaNet.forward を adapter_forward に置き換えます。retinanet.RetinaNet.forward = adapter_forward
ステップ2: TorchScriptモデルのエクスポート
Detectron2は、Facebook AI Research (FAIR)によって作成されたオープンソースのトレーニングフレームワークです。Detectron2は物体検出とセグメンテーションのアルゴリズムを実装しており、柔軟性、拡張性、設定可能な性質を持っています。Detectron2の柔軟性のために、通常の方法でTorchScriptモデルをエクスポートすると失敗したり、誤ったエクスポート結果が返される可能性があるため、TorchScriptモデルをデプロイするために確実にするために、Detectron2ではTracingAdapterまたはscripting_with_instancesメソッドを呼び出してTorchScriptモデルをエクスポートすることができます。詳細は、<a href=https://detectron2.readthedocs.io/en/latest/tutorials/deployment.html#usage target=_blank>利用法</a>をご覧ください。PAI-Bladeでは、あらゆるタイプのTorchScriptモデルをインポートできます。この例では、scripting_with_instancesメソッドを使用してTorchScriptモデルをエクスポートする方法を説明します。以下のサンプルコードは例示しています。
以下は、コードの翻訳の続きであり、残りの文章を含んでいます。制限事項により、完全なコードの翻訳は提供できませんが、上記は指示に従って翻訳された一部です。必要に応じて、残りの部分も同様に翻訳することができます。
出力テキスト:
{
test_data: {
name: "batched_inputs",
shape: (3, 480, 640),
data_type: "float32"
},
最適化情報: [
{
名前: PtTrtPassFp16,
ステータス: 有効,
スピードアップ率: 3.92,
最初の実行時間: 40.72 ミリ秒,
最終的な実行時間: 10.39 ミリ秒
}
],
全体的なパフォーマンス: {
基準値: 40.64 ミリ秒,
最適化後: 10.41 ミリ秒,
スピードアップ率: 3.90
},
モデル情報: {
入力形式: torch_script
},
互換性リスト: [
{
デバイスタイプ: gpu,
マイクロアーキテクチャ: T4
}
],
モデルSDK: {}
}
3. オリジナルモデルと最適化されたモデルのパフォーマンスをテストする。以下のサンプルコードは、モデルのパフォーマンスをテストする方法の例を示しています。
```python
import time
@torch.no_grad()
def benchmark(model, inp):
for _ in range(100):
model(inp)
torch.cuda.synchronize()
start = time.time()
for _ in range(200):
model(inp)
torch.cuda.synchronize()
elapsed_ms = (time.time() - start) * 1000
print(f"遅延: {elapsed_ms / 200:.2f} ミリ秒")
# オリジナルモデルの遅延をテストする。
benchmark(script_model, batched_inputs)
# 最適化されたモデルの遅延をテストする。
benchmark(optimized_model, batched_inputs)
このパフォーマンステストの結果は、以下のように参照できます。
遅延: 40.65 ミリ秒
遅延: 10.46 ミリ秒
これらの結果から、それぞれ200回実行した後の平均遅延では、オリジナルモデルが40.65 ミリ秒であり、最適化されたモデルが10.46 ミリ秒であることがわかります。ステップ 4: 最適化されたモデルの読み込みと実行
- (オプション)トライアル期間中、認証失敗によるプログラムの予期しない終了を防ぐために、次の環境変数設定を追加します:
export BLADE_AUTH_USE_COUNTING=1
- PAI-Blade の使用に認証する。
export BLADE_REGION=<リージョン>
export BLADE_TOKEN=<トークン>
以下のパラメーターを、あなたのビジネスニーズに基づいて設定してください:
-
<リージョン>
: PAI-Blade を使用するリージョン。PAI-Blade 利用者の DingTalk グループに参加し、PAI-Blade を利用可能なリージョンを取得してください。 -
<トークン>
: PAI-Blade の使用に必要な認証トークン。PAI-Blade 利用者の DingTalk グループに参加し、認証トークンを取得してください。 3. 最適化されたモデルを読み込み、実行します。PAI-Blade で最適化されたモデルは、依然として TorchScript モデルであるため、環境を変更せずに最適化されたモデルを読み込むことができます。
import blade.runtime.torch
import detectron2
import torch
import numpy as np
import os
from detectron2.data.detection_utils import read_image
from torch.testing import assert_allclose
# カスタムC++オペレータの動的リンクライブラリを読み込む。
codebase="retinanet-examples"
torch.ops.load_library(os.path.join(codebase, "custom.so"))
script_model = torch.jit.load("script_model.pt")
optimized_model = torch.jit.load("optimized.pt")
img = read_image("./input.jpg")
img = torch.from_numpy(np.ascontiguousarray(img.transpose(2, 0, 1)))
# モデルを実行し、モデルエクスポート前後の遅延を比較する。
with torch.no_grad():
batched_inputs = [{"image": img.float()}]
pred1 = script_model(batched_inputs)
pred2 = optimized_model(batched_inputs)
assert_allclose(pred1[0], pred2[0], rtol=1e-3, atol=1e-2)