量子化を考慮した学習と NVIDIA Transfer Learning Toolkit を使用した INT8 精度の向上
ディープニューラルネットワーク (DNN) モデルは、ビデオストリームコンテンツの分析を必要とするアプリケーションで日常的に使用されています。これらのアプリケーションには、物体検出、分類、セグメンテーションなどが含まれます。通常、これらのモデルは、NVIDIA DGX1 のようなスタンドアロンのサーバー、データセンターやプライベートクラウド、パブリッククラウドで利用可能なサーバーのいずれかのハイエンド GPU を搭載したサーバー上で学習されます。
このようなシステムでは,広いダイナミックレンジの重みを利用するために,浮動小数点 32 ビット演算 (FP32) を使用することが多いです。しかし、モデルをトレーニングした後は、多くの場合、計算リソースの少ないハードウェア上のエッジにデプロイしなければなりません。多くの場合、重みに 8 ビットの整数 (INT8) を使用することが有効です。この課題は、トレーニング後に単純に重みを量子化してしまうと、特に重みのダイナミックレンジが広い場合には、精度の低いモデルになってしまうことです。
この投稿では、INT8 重みに最適化されたモデルを学習する方法を学びます。トレーニング中、システムは量子化を考慮した学習 (Quantization Aware Training, QAT) と呼ばれる手法によって、量子化を考慮した学習が可能です。
モデルの量子化
量子化とは、深層学習モデルを変換して、パラメータと計算をより低い精度で使用するプロセスです。従来、DNN のトレーニングと推論は、IEEE 単精度浮動小数点形式に依存しており、32 ビットを使用して浮動小数点モデルの重みとアクティベーションテンソルを表していました。詳細については、自動混合精度 (Automatic Mixed Precision, AMP) を参照してください。
ほとんどの DNN は、データセンターやクラウドで、NVIDIA V100 や A100の GPU を使用してトレーニングを行っているため、この計算リソースはトレーニング時には許容できるかもしれません。しかし、デプロイ時には、これらのモデルは、エッジでの計算リソースと電力予算がはるかに小さいデバイス上で実行する必要があります。フル 32 ビット表現を使用して DNN 推論を実行することは、エッジの計算、メモリ、電力の制約を考えると、リアルタイム解析には実用的ではありません。
モデルの構造やパラメータの数を犠牲にせずに計算リソースを削減するために、より低い精度で推論を実行することができます。当初、量子化推論はテンソルと重みを 16 ビットの浮動小数点数 (FP16) で表現した半精度で実行されていました。これにより、約 1.2~1.5 倍の計算量の節約になりましたが、まだ利用できる計算リソースとメモリ帯域幅に改善できる余地が残っていました。この代わりに、モデルはさらに低い精度で量子化され、重みとテンソルは 8 ビットの整数表現に用います。これにより、モデルのメモリ容量は 4 倍小さくなり、スループットは約 2~4 倍速くなりました。
8 ビット量子化は、計算とメモリリソースを節約するために魅力的ですが、損失の大きいプロセスです。量子化の際には、小さな範囲の浮動小数点数を一定数の情報範囲に絞り込みます。その結果、情報が失われます。
もともと 32 ビット表現で解決できた微細な違いは、8 ビット表現では同じ範囲に量子化されてしまうために失われてしまいます。これは、分数を整数として表現するときに遭遇する丸め誤差のようなものです。より低い計算精度で推論を行う際に精度を維持するためには、このような情報の損失に起因する誤差を軽減するように努めることが重要です。
NVIDIA Transfer Learning Toolkit (TLT) は、学習後の量子化 (Post-training Quantization, PTQ) と QAT の 2 つの方法で、量子化によるこの情報の損失をモデル化しようとします。
トレーニング後の量子化
この方法は、その名前が示すように、TLT でトレーニングされた後のモデルに適用されます。トレーニングは、FP32 で表現された重みとアクティベーションで行われます。十分なモデル精度でトレーニングが完了した後、TensorRT INT8 エントロピーキャリブレータを使用してモデルを調整します。
TensorRT の IInt8EntropyCalibratorV2 (エントロピーキャリブレータ) は、INT8 エンジンを構築する際にモデルを調整します。TensorRT が INT8 スケールファイルを生成する方法の詳細については、C ++を使用した INT8 キャリブレーションを参照してください。トレーニング後にモデルを調整する方法の詳細については、「TLT入門ガイド」を参照してください。
PTQ は量子化誤差を簡単にモデル化する方法を提供しますが、学習されたモデルの重みをより小さな範囲に効果的にスケーリングすることができるという固有の前提があります。しかし、このスケーリングではモデルの重みの統計量を維持できない場合があります。そのような例の 1 つは、NGC の PeopleNet モデルです。モデルは FP32 モードで表現されたテンソルで学習され、TensorRT INT8 エントロピーキャリブレーターを使用して調整されました。ただし、結果として得られた TensorRT エンジンは、図1に示すように、いくつかのスプリアスバウンディングボックス (*1) を生成し、モデル精度の低下させました。(*1: スプリアスバウンディングボックスは、各画像について、一定の確率で、ランダムな位置と寸法の追加のバウンディングボックスが、クラスのリストからランダムに選択されたラベルととも追加される現象。)
量子化を考慮した学習
QAT では、DNN を学習した後にアクティベーションテンソルにスケールファクタを計算するのではなく、モデルを学習する際に量子化誤差を考慮します。
トレーニンググラフは、トレーニングプロセスのフォワードパスでのより低い精度の動作をシミュレートするように修正されています。これにより、学習損失の一部として量子化誤差が導入され、オプティマイザは学習中に最小化しようとします。したがって、QAT は、トレーニング中の量子化誤差のモデル化に役立ち、デプロイ時のモデルの精度への影響を軽減します。
ただし、より低い精度の挙動をシミュレートするためにトレーニンググラフを修正するプロセスは複雑です。DNN レイヤーの重みのFakeQuantization ノードと Quantize-Dequantize (QDQ) ノードを中間アクティベーションテンソルに挿入してダイナミックレンジを計算するために、トレーニングコードを修正する必要があります。
これらの QDQ ノードの配置は、モデルの学習能力に影響を与えないようにするためにも重要です。これらのモデルは TensorRT 推論プラットフォームでの展開を目的としているため、融合された計算ブロックの最後にのみ QDQ ノードを含めるように注意してください。例えば、TensorRT は Conv -> Bias -> ReLU
とConv -> Bias -> BatchNormalization -> ReLU
の計算ブロックを組み合わせています。その場合、QDQ レイヤーを追加することは、ReLU アクティベーションの出力テンソルにのみ意味があります。詳細については、「量子化を考慮した学習」を参照してください。
すべてのアクティベーションレイヤータイプが量子化に適しているわけではありません。例えば、回帰層を持つネットワークでは、一般的に、これらの層の出力テンソルが 8 ビット量子化の範囲に拘束されないようにする必要があり、8 ビット量子化が提供できるよりも細かい粒度の表現を必要とする場合があります。これらのレイヤーは、量子化から除外されている場合に最適に機能します。
TLT を使用した量子化対応トレーニングの実行
TLT を使用してモデルをトレーニングする場合、コード開発は必要ありません。TLT は、効果的な QAT グラフを実装するためのすべての要件を抽象化します。量子化を考慮して学習するには、学習仕様ファイルのtraining_config
コンポーネントにフラグを追加します。これにより、tlt-train
コマンドを起動してモデルグラフを解析し、フォワードパス中に重みとアクティベーションの量子化を有効にしてモデルを効果的に学習できるように修正します。図 2 は、QAT から INT8 デプロイ可能モデルを生成するための推奨ワークフローを示しています。
- 枝刈りされていない物体検出モデルを学習します。
tlt-prune
を使用して、精度を落とさずに可能な限り計算量を節約するために、学習されたモデルを枝刈りします。- QAT を有効にしてこのモデルを再学習します。
- 再学習されたモデルを評価して、枝刈りされていないモデルで復元された精度を確認します。
- モデルをエクスポートして、DeepStream SDK または
tlt-converter
で読み込んで TensorRT エンジンを生成できる etlt ファイルと INT8 キャリブレーションキャッシュを生成します。tlt-export
時に TensorRT エンジンを生成することもできますが、このエンジンはtlt-export
が実行されたハードウェア上でのみデプロイ可能です。 - 生成した TensorRT エンジンを
tlt-evaluate
を用いて検証データセット上で評価します。QAT は、分類および Mask-RCNN モデルではサポートされていません。
ユースケースの例として、整数精度 (8 ビット表現) で展開するのに適した TLT PeopleNet モデルの QAT 対応版を学習する方法を説明します。PeopleNet モデルを事前学習済みの重みを使用して DetectNet_v2 モデルを学習する方法の詳細については、「NVIDIA Transfer Learning Toolkit を使用したカスタムの学習済みモデル (Pre-Trained Model) による学習」を参照してください。枝刈りされていない DetectNet_v2 モデルを学習し、それを枝刈りして、かなり小さい枝刈りされたモデルを生成するためのステップに従うことをお勧めします。
枝刈りされたモデルが生成されたら、再トレーニング仕様ファイルのmodel_config
コンポーネントを更新して、次の手順を指定します。
- 事前に学習された重みとして、枝刈りされたモデルを含めます。
load_graph
フラグを true に設定すると、新しく枝刈りされたモデル構造がインポートされます。
次のコード例は、更新されたモデル構成を示しています。
model_config {
pretrained_model_file: "/path/to/pruned/model"
load_graph:true
num_layers:34
arch:"resnet"
use_batch_norm:true
objective_set {
bbox {
scale:35.0
offset:0.5
}
cov {
}
}
training_precision {
backend_floatx:FLOAT32
}
}
次に、再学習仕様ファイルのtraining_config
コンポーネントを更新して、enable_qat
フラグを設定します。
training_config {
batch_size_per_gpu:24
num_epochs:120
enable_qat:true
learning_rate {
soft_start_annealing_schedule {
min_learning_rate:5e-06
max_learning_rate:0.0005
soft_start:0.1
annealing:0.7
}
}
regularizer {
type:L1
weight:3e-09
}
optimizer {
adam {
episilon:9.9e-09
beta1:0.9
beta2:0.999
}
}
cost_scaling {
initial_exponent:20.0
increment:0.005
decrement:1.0
}
checkpoint_interval:10
}
残りの仕様ファイルのコンポーネントは、枝刈りされていないモデルを学習した時の仕様ファイルと同じままである可能性があります。
このモデルのトレーニングを実行するには、更新された仕様ファイルを用いてtlt-train
コマンドを使用します。tlt-train
コマンドのコマンドラインの使用例は以下の通りです。
tlt-train detectnet_v2 -e $spec_file_path \
-r $experiment_dir_pruned_qat \
-k $KEY \
-n $model_file_string \
--gpus $N
次のパラメータが定義されています。
$spec_file_path
:学習仕様ファイルへの UNIX スタイルのパス。$experiment_dir_pruned_qat
:出力結果ディレクトリへの UNIX スタイルのパス。$KEY
:モデルをロードするためのキー文字列。$N
:学習中に使用される GPU の数。$model_file_string
:トレーニングが完了した後に保存される最終モデルファイルの文字列名。- モデルは下記パスに出力されます:
$experiment_dir_pruned_qat/weights/$model_file_string.tlt
学習が完了したら、tlt-evaluate
コマンドを使用して検証データセットでモデルを評価することで、このモデルの精度を検証することができます。
tlt-evaluate detectnet_v2 \
-e $spec_file_path \
-m $experiment_dir_pruned_qat/weights/$model_file_string.tlt \
-k $KEY \
クラスあたりの平均精度 (AP) は、PascalVOC チャレンジで述べられている Pascal VOC 評価ガイドラインに従って計算され、モデルの mean average precision (mAP) メトリックとともに端末に出力されます。QAT と非 QAT が学習済みモデルのコンパイル結果の詳細については、この記事のさらに下の「結果」のセクションを参照してください。QAT および非 QAT 学習済みモデルのコンパイル結果の詳細については、この記事のさらに下の「結果」のセクションを参照してください。
ここで計算された mAP は、QAT を有効にしないで学習したモデルの mAP に近いものです。モデルの性能が満足のいくものであると判断された後、tlt-export
コマンドを用いて出力することができます。tlt-export
コマンドは、モデルグラフを解析して量子化されたノードを探し、それらを剥離して、中間アクティベーションテンソルのダイナミックレンジスケールファクターを含む対応する calibration_cache
ファイルと共に、etlt_model
ファイルを生成します。etlt_model
ファイルとcalibration_cache
ファイルは、INT8 精度 (8ビット) TensorRT エ ンジンを生成するためにtlt-converter
によって使用されるか、DeepStream SDK で直接使用することができます。
次のコード例は、tlt-export
コマンドの使用法を示しています。
tlt-export detectnet_v2 \
-m $experiment_dir_pruned_qat/weights/$model_file_string.tlt \
-o $output_model_path \
-k $KEY \
--data_type int8 \
--batch_size N \
--cal_cache_file $calibration_cache_file \
--engine_file $engine_file_path
次のパラメータが定義されています。
$output_model_path
:etlt モデルファイルを出力する UNIX パス。$KEY
:モデルをロードして etlt モデルファイルを保存するための文字列キー。--data_type
:TensorRT ファイルの精度 (上記の例ではキャリブレーションキャッシュを生成するために INT8 に設定されます)。N
:出力 TensorRT エンジンのバッチサイズ値。$calibration_cache_file
:アクティベーションテンソルのスケールを含む出力キャッシュファイルへの UNIX パス。$engine_file_path
:出力 TensorRT エンジンファイルへの UNIX パス。
tlt-export
コマンドで生成されたエンジンは、export コマンドが実行されたプラットフォーム上でのみ推論を実行するために使用できます。このモデルを別のプラットフォームに展開するには、etlt_model
ファイルとcalibration_cache
を使って推論プラットフォーム上でtlt-converter
を実行します。
Jetsonプラットフォームにデプロイする場合は、対応する JetPack ビルドの TensorRT バージョンを反映させるために、calibration_cache
ファイルの最初の行をテキストエディタで編集します。例えば、JetPack 4.4 の場合、1行目の TensorRT バージョン番号を 7000 から 7100 に更新します。
QAT で生成されたキャリブレーションキャッシュファイルは、x86 ベース の GPU (NVIDIA T4、V100、および A100) と NVIDIA Jetson プラットフォーム (AGX Xavier および XavierNX) の両方でGPUコアでの展開にのみ互換性があります。
先に使用したtlt-export
コマンドを使用して生成したモデルは、DLA のINT8 モードでのデプロイには対応していません。このモデルを DLA でデプロイするには、QAT で学習された .tlt モデルファイルに PTQ を使用してキャリブレーションキャッシュファイルを生成する必要があります。これはtlt-export
実行時にコマンドラインでforce_ptq
フラグを設定することで行うことができます。このフラグを設定して DetectNet_v2 モデルをエクスポートするtlt-export
コマンドの例は以下のようになります。
tlt-export detectnet_v2 \
-e $spec_file_path \
-m $experiment_dir_pruned_qat/weights/$model_file_string.tlt \
-o $output_model_path \
-k $KEY \
--data_type int8 \
--batch_size N \
--cal_cache_file $calibration_cache_file \
--engine_file $engine_file_path \
--force_ptq
force_ptq
オプションを使用すると、モデルからスケールファクターが省略され、QAT で学習したモデル上で TensorRT IInt8EntroplyCalibrator2 を使用してスケールファクターが生成されます。この手法は,モデル内のすべての中間テンソルのスケールを生成します。GPU と異なり、DLA は現在、Conv -> Bias -> ReLU
とConv -> Bias -> BatchNormalization -> ReLU
のブロックを 1 つの演算子に融合させていません。そのため、すべての中間テンソルに対して量子化スケールが必要となります。tlt-train
、tlt-evaluate
、tlt-prune
、tlt-export
、およびtlt-converter
使用方法の詳細については、 TLT 入門ガイドを参照してください。
PeopleNet v2.0 モデルを INT8 モードで DLA 上に展開するために,tlt-export
のforce_ptq
モードを用いて量子化スケールを生成し,tlt-evaluate
を用いてモデルを評価しました。結果は、TLT 入門ガイドの専用モデルセクションにまとめられています。
結果
表 1 は、QAT で学習された INT8 モデルと、PTQ を使用して INT8 モードでデプロイされた FP32 トレーニングモデルの精度の比較を示しています。数値はベースライン FP32 の精度と比較しています。
QAT を用いて学習した場合、ベースライン FP32 との精度差は 1% 以内です。同じモデルに PTQ を適用すると、精度が大きく低下してモデルが使用できなくなります。QAT は INT8 精度で推論を実行するための有効な学習手法です。
同じモデルアーキテクチャで INT8 モデルと同等の精度を維持できることで、同じハードウェア上で推論性能を大幅に向上させることができます。表 2 は、FP16 と INT8 精度の 2 つの PeopleNet モデルについて、T4 での推論性能を比較しています。これら 2 つのモデルを平均してみると、推論 FPS が 2 倍近く増加していることがわかります。これは、モデルアーキテクチャや GPU を変更することなく、デプロイメントプラットフォーム上のストリーム数を効果的に 2 倍にできることを意味します。
ここに含まれるサンプル予測は、図 1 と同じ画像を示していますが、QAT を有効にして学習された INT8 モデル上で推論を実行しています。これでスプリアス検出がなくなり、精度が大幅に向上しました。
結論
量子化を考慮した学習により、精度を犠牲にすることなく、より低精度な INT8 展開のための DNN のトレーニングが可能になります。これは、学習中に量子化誤差をモデル化することで実現され、FP16 や FP32 に比べて精度を維持するのに役立ちます。PTQ は引き続き TLT でサポートされていますが、INT8 精度を使用してデプロイする場合は、QAT でのトレーニングをお勧めします。
この記事では、PeopleNet モデルをサンプルとして使用し、QAT を使用してモデルを学習する方法を説明しました。しかし、QAT は TLT でサポートされている他の物体検出モデルにも使用できます。QAT の詳細については、TLT 入門ガイドのトレーニングパイプラインの最適化セクションを参照してください。