Transformerモデルの高速化

Cheif Research Officerの西鳥羽 (Jiro Nishitoba (@jnishi) | Twitter) です。

前回はONNX runtimeを利用した高速化を紹介いたしました。今回はさらなる高速化をしたいと思います。 NVIDIA社のTensorRTおよびIntel社のOpenVINOを利用します。

onnxruntimeのインストール

OpenVINOやTensorRTを用いる場合*1、onnxruntimeをソースからビルドしてインストールします。なお、OpenVINOやTensorRTは既にインストールされているものとします。これらのインストールはOpenVINOのinstallation instructionやTensorRTのInstallation Guideを参考にしてください。

以下のコマンドでonnxruntimeの取得とビルドを行います。詳しくはBuild ONNX Runtime for inferencing及びBuild ONNX Runtime with Execution Providersを参考にしてください。

git clone --recursive git@github.com:microsoft/onnxruntime.git
cd onnxruntime
source  /opt/intel/openvino_2021/bin/setupvars.sh # OpenVINOの有効化
./build.sh --use_cuda --cuda_home /usr/local/cuda --cudnn_home /usr/lib/x86_64-linux-gnu --use_tensorrt --tensorrt_home /usr --use_openvino CPU_FP32 --config RelWithDebInfo  --build_shared_lib --use_openmp --build_wheel --parallel

なお、--cuda_home --cudnn_home --tensorrt_home で指定しているディレクトリはUbuntu 20.04にてDebパッケージでインストールした際のデフォルトのパスになります。ご自身の環境に合わせて変更してください。

OpenVINOを用いたCPUでの推論の高速化

CPUのモデルの推論をOpenVINOを利用して高速化します。OpenVINOはIntel社がオープンソースで提供している推論用ライブラリです。IntelのCPU、GPUおよびFPGA上での計算に特化して高速な推論を行います。

OpenVINOを用いる場合には providers["OpenVINOExecutionProvider"] を指定します。 前回のブログでCUDAの指定を行っていた部分を以下のように変更します。

# ONNX形式のモデルから推論用モデルを作成
session = InferenceSession(args.onnx_path, providers=["OpenVINOExecutionProvider"])

以上でOpenVINOを用いた推論が行われます。

以下に速度比較を行っています。前回のブログと同じように事前学習済みモデルとして cl-tohoku/bert-large-japanese を利用し、livedoorニュースコーパスの記事を学習データ:評価データを4:1に分割し、カテゴリ推定でファインチューニングを行いました。Hugging Face Transformersのモデル、ONNXのCPU実行、ONNXのOpenVINO実行における推論時間を測定しています。評価データ全件に対して推論を行いその1件当たりの平均時間で比較しています。なおOpenVINOでの推論において、8秒近く時間のかかっている推論が4件あり、それらは異常値として平均からは取り除いています。

f:id:Christopher-727:20220329115244p:plain
CPUにおける推論時間の比較

Hugging Face Transformersでの実行よりもOpenVINOによる実行の方が高速ですが、ONNXのCPU実行よりも速度が低下しています。8秒以上かかる例も含めてOpenVINOをうまく扱えてないような感じがします。

TensorRTを用いたGPUでの推論の高速化

GPUモデルの推論をTensorRTを利用して高速化します。TensorRTはNVIDIA社がオープンソースで提供しているGPU上での推論ライブラリです。INT8やFP16への量子化やNeural Networkの最適化などを行い、GPU上での推論を高速化します。

TensorRTを用いる場合には providers["TensorRTExecutionProvider"] を指定します。 前回のブログでCUDAの指定を行っていた部分を以下のように変更します。

# ONNX形式のモデルから推論用モデルを作成
session = InferenceSession(args.onnx_path, providers=["TensorRTExecutionProvider"])

以上でTensorRTでの推論が行われます。注意点としては sessionを用いた推論の初回実行時にはTensorRT向けのモデルのビルドが行われるため、実行に数十秒くらいの時間がかかります。2回目以降の推論は高速に行われます*2

以下に速度比較を行っています。こちらも同じように事前学習済みモデルとして cl-tohoku/bert-large-japanese を利用し、livedoorニュースコーパスの記事を学習データ:評価データを4:1に分割し、カテゴリ推定でファインチューニングを行いました。Hugging Face Transformersのモデル、ONNXのCUDA実行、ONNXのTensorRT実行における推論時間を測定しています。評価データ全件に対して推論を行いその1件当たりの平均時間で比較しています。なおTensorRTでの推論において、1秒以上時間のかかっている推論は推論だけでなくモデルのビルドが行われていると思われるので平均からは取り除いています。

f:id:Christopher-727:20220329115311p:plain
GPUにおける推論時間の比較

Hugging Face TransformersのモデルとONNX CUDAでの実行を比較すると、前回のブログでもふれたとおり約2.4倍の高速化となっています。TensorRTを用いるとCUDAでの実行から更に1.35倍の高速化となっています。Neural Networkの最適化が行われるタイミングを管理しないといけない課題はありますが、効果は出ているようです。

まとめ

CPUのメーカーおよびGPUのメーカーが公開している高速化ライブラリを通じて推論がどれだけ早くなるかを試してみました。NVIDIA社のTensorRTを利用したところ初回や、何度も実行していると偶にビルドで時間がかかる時があるものの、CUDA実行と比較して1.35倍の高速化となりました。Intel社のOpenVINOの方は処理が速くはなりませんでしたが、こちらはうまく扱えていない様子なので今後何かわかりましたら続報を上げたいと思います。

*1:TensorRTだけを用いる場合はpypyにて公開されているパッケージでも利用可能です。onnxruntime-gpuパッケージで利用できます。

*2:ただ、推論を何度も実行しているとまたモデルのビルドが行われるようです。後述の実験の際に初回推論以外にも1回数秒かかる実行が存在しました。