GTC Japan 2016において、NVIDIAの森野氏が、同社の推論エンジン「TensorRT」について発表を行った。CaffeやTheano、Torch、TensorFlowなどのフレームワークと呼ばれるソフトは、ニューラルネットの開発用のツールで、ネットの入力から、学習、推論の一連の機能を持っているが、TensorRTは、以前は「GPU Inference Engine」と呼ばれており、Caffeで学習を終わったネットワークのprototxtを入力として、高性能の推論を行うシステムを作るツールである。
TensorRTターゲットとしているのは、ビデオ画像のストリーミング識別、自動運転車のリアルタイム画像認識、巨大データセンタでのWebからの大量の認識要求を捌くなどのレーテンシとスループットを要求される用途である。
森野氏がCaffeとTensorRTとの性能の比較に当たって使用したモデルはCaffeの配付パッケージに含まれているGoogLeNetのモデルで、入力はILSVRC 12の学習データの平均値のイメージを使っている。
そして、CaffeのライブラリはNVIDIAのgithubに置かれているもので、TensorRTはRC1を使っている。
CaffeとTensorRTの比較に当たって使用したモデルや入力データ、フレームワークライブラリ (このレポートのすべての図は、GTC Japan 2016での森野氏の発表スライドを撮影したものである) |
推論の処理であるが、Caffeの方は標準的な処理を行っているが、TensorRTの方は、前処理にはCUDAのカスタム実装の前処理を使っている。また、推論部分は、Caffeではなく、TensorRTを使っているという違いがある。なお、TensorRTは標準のFP32での処理もできるが、精度は下がるが演算性能の上がるFP16やINT8で最適化した処理を行えるようになっている。
両者を実行時間を比較したのが次の表で、前処理は、Caffeでは3.0ms掛かっていたものがTensorRTでは0.8msと3.7倍高速になった。そして、推論は、Caffeの7.4msに対して、TensorRTは2.4msと3.1倍高速になっている。なお、ここで使用したGPUはQuadro M5000である。
これで標準のCaffeと比べて3倍余り高性能となっているが、TensorRTからもっと性能を引き出せないかということで、複数の推論のコンカレントな実行とバッチサイズを大きくするという使い方をトライした。
次の図では3つの推論を並行して実行するのであるが、CUDAストリームは2本という構成で走らせている。このように実行するスレッド数とストリーム数は一致していなくても良いという。
次の図はコンカレントに実行するスレッド数を変えて測定した結果を、処理時間(折れ線グラフ)とスループット(棒グラフ)で示したものである。この測定では、スレッド数とストリーム数は一致させている。
処理時間はスレッド数の増加に伴って減少する傾向であり、一方、スループットはスレッド数を増やすと増加する傾向にあるが、どちらも8スレッド程度で飽和している。しかし、どちらも8スレッドをコンカレントに実行することにより、1スレッドの場合と比較して、約2倍に性能アップしている。
1スレッドの場合は仕事が少なくGPUコアが遊んでいるのを、複数スレッドのコンカレント実行で空きを埋めていくことでスループットが上がっていると考えられる。なお、処理時間は全体の実行時間をスループットで割って求めていると思われ、全体の処理時間があまり増えないでスループットが増えていることを意味しており、個々の推論処理の開始から終了までの時間が短くなっているわけではないと思われる。
次の図はコンカレント実行した場合のプロファイラ出力の、各スレッドの実行状況の部分を拡大したもので、一番下が4ストリームのそれぞれの実行状況を示している。
この推論サーバをWebサーバと結合して、推論処理のスループットと処理レーテンシを計測した。Goのnet/httpパッケージを使って実装し、boomを使って同時リクエスト数を変えて測定を行っている。
次の図に示すように、推論リクエストを複数の推論実行ストリームに振り分けて並列実行するという状態で性能を計測している。
次の図は同時リクエスト数を1~32に変化させてスループットを測定した結果で、左はシリアル処理のケースで、右がコンカレント実行のスループットである。当然ながら、シリアル実行の場合は、同時リクエスト数を大きくしてもスループットはほぼ一定である。これに対してコンカレント実行の場合は、同時リクエスト数が増えるとスループットは向上するが、8スレッド程度で飽和している。この時、1リクエストに比べて、8リクエストになると、スループットは約2倍の650リクエスト/秒になっている。もちろん、使用したGPUのコア数などが違えば、飽和点は違ってくると考えられる。
また、同時リクエスト数8の場合、シリアル処理のレーテンシは22.1msであるのに対して、コンカレント処理の場合のレーテンシは14.2msに減少している。
同時リクエストはバラバラとリクエストが入ってくる状態であるが、バッチ処理は、一定数のリクエストをまとめて束にして処理するという方法である。一般に、束にするリクエスト数が大きい方がメモリアクセス数に比較して演算回数が増え、性能が高くできる。
次の図はバッチ数の増加による性能改善をプロットしたもので、折れ線グラフが実行時間、棒グラフがスループットである。なお、このグラフはTensorRTの推論部分の実行時間だけを示したものである。バッチサイズの1から128への増加で、スループットは2.5倍改善し、処理時間は2.6msから1.05msに改善している。
シリアルとコンカレント、そしてバッチ(バッチ数4)の構成で同時リクエスト数を変えてスループットを測定した結果が次の図である。最初はコンカレント実行の性能向上が目立つが、コンカレント実行の性能は8並列程度で飽和する。これに対してバッチ実行は性能が上がり続け、32同時リクエスト以上では一番高いスループットが得られており、シリアル実行に比べて約2.4倍のスループットである。そして、レーテンシも長くなっていない。
TensorRTは、Caffeの標準実装と比べると、前処理のカスタム実装で3.7倍の高速化を実現している。そして、NVIDIA GPUに最適化した実装で推論の性能を3.1倍に改善しているが、複数の推論をコンカレントに実行したり、バッチサイズを大きくしたりすると、さらに高い性能が得られる。