前回の記事にも書いたが、dlshogiは、V100のTensorCoreがINT8に対応していないため、INT8対応を行っていなかった。
しかし、AWSのG4インスタンスでは、NVIDIA T4 Tensor Core GPUが利用できるため、INT8に対応することにした。
また、今後クラウドでA100が提供されたときに、すぐにINT8を試せるようになる。
dlshogiをINT8に対応させる際に、Pytorchで出力した可変バッチサイズのONNXモデルを使用するとキャリブレーションがうまくできないという問題が起きたため、解決方法について残しておく。
可変バッチサイズのONNXモデルでキャリブレーションした際のエラー
PyTorchで、以下のようにdynamic_axesを付けて、ONNXを出力し、
torch.onnx.export(model, (x1, x2), args.onnx, verbose = True, do_constant_folding = True, input_names = ['input1', 'input2'], output_names = ['output_policy', 'output_value'], dynamic_axes={ 'input1' : {0 : 'batch_size'}, 'input2' : {0 : 'batch_size'}, 'output_policy' : {0 : 'batch_size'}, 'output_value' : {0 : 'batch_size'}, })
TensorRTで、サンプルプログラムと同じように、キャリブレーションを行おうとすると、以下のエラーが発生する。
Calculating Maxima C:\source\rtSafe\safeRuntime.cpp (25) - Cuda Error in nvinfer1::internal::DefaultAllocator::allocate: 2 (out of memory) C:\source\rtSafe\safeRuntime.cpp (25) - Cuda Error in nvinfer1::internal::DefaultAllocator::allocate: 2 (out of memory)
issuesを調べたところ、同様のエラーが報告されていた。
When I use the TensorRT to infer MoblieNet in the INT8 mode,I meet the following errors.How can I solve the problems? · Issue #688 · NVIDIA/TensorRT · GitHub
しかし、再実行して解決したとしてクローズされていた。
こちらでは、何度やっても同様のエラーになる。
issuesでは、TensorRT 7.0では、dynamic shapeに対応していないため、TensorRT 7.1を使うように書き込みがあったので、TensorRT 7.1.3.4にしてみたが解決しない。
固定バッチサイズで試す
固定バッチサイズだと、うまくいくかもと思い試してみた。
PyTorchでONNX出力する際に、dynamic_axesを削除して、入力をバッチサイズ256にした。
再び、キャリブレーションを行ったが、今度は、別のエラーが発生した。
Calculating Maxima Starting Calibration with batch size 256. Explicit batch network detected and batch size specified, use execute without batch size instead. C:\source\builder\cudnnCalibrator.cpp (707) - Cuda Error in nvinfer1::builder::Histogram::add: 700 (an illegal memory access was encountered) FAILED_ALLOCATION: Unknown exception C:\source\builder\cudnnCalibrator.cpp (703) - Cuda Error in nvinfer1::builder::Histogram::add: 700 (an illegal memory access was encountered) FAILED_ALLOCATION: Unknown exception C:\source\rtSafe\cuda\caskConvolutionRunner.cpp (233) - Cuda Error in nvinfer1::rt::task::CaskConvolutionRunner::allocateContextResources: 700 (an illegal memory access was encountered) FAILED_EXECUTION: Unknown exception Calibrated batch 0 in 2.18174 seconds. Cuda failure Error: an illegal memory access was encountered Aborting...
メモリ関連のエラーなのでバッチサイズを小さくして試したところ、エラーはでなくなったが、作成されたキャリブレーションキャッシュを使用して推論してみると、floodgateからサンプリングした局面の予測精度は、
move accuracy = 0.00741186 value accuracy = 0.4999 value mse = 0.151279
となり、精度が全くでていない。
バッチサイズ1で試す
ダメ元でONNXを固定バッチサイズ1でキャリブレーションしてみたところ、
move accuracy = 0.460036 value accuracy = 0.721254 value mse = 0.0232871
となり、今度は精度が出るようになった。
ただし、キャリブレーションに数分程度の時間がかかる。
なお、TensorRTのキャリブレーション結果は、キャッシュに保存することが可能で、バッチサイズ1でキャリブレーションした結果を、可変バッチサイズのONNXモデルで使用することができた。
キャリブレーションのキャッシュは、以下のようなテキスト形式で記述されており、バッチサイズには依存していないようである。
TRT-7000-EntropyCalibration2 input1: 7f800000 input2: 7f800000 143: 3c0779a5 144: 3b59804a 145: 3b96d0e5 146: 3c209593 147: 3c244dfc 148: 3bd96b2c ...
精度比較
なんとかキャリブレーションができるようになったので、FP16モードと精度を比較した。
キャリブレーションのデータサイズを増やした場合に、どのように精度が変わるかも比較した(キャリブレーションにはfloodgateからサンプリングした局面をキャリブレーションに使用した)。
公式ドキュメントには、ImageNet分類ネットワークのキャリブレーションには約500枚の画像で十分と書かれている。
move accuracy | value accuracy | value mse | |
---|---|---|---|
FP16 | 0.467448 | 0.723958 | 0.0229941 |
1024サンプル | 0.460036 | 0.721254 | 0.0232871 |
4096サンプル | 0.460437 | 0.721755 | 0.0233805 |
8192サンプル | 0.462841 | 0.721855 | 0.0232868 |
16384サンプル | 0.463542 | 0.719351 | 0.0231744 |
32768サンプル | 0.460437 | 0.723558 | 0.0231636 |
1024サンプルでは、policyの精度が0.7%、valueの精度0.27%が落ち込んでいる。
キャリブレーションに使用するサンプル数を上げると、ある程度回復がみられるが、policyが上がるとvalueが下がったり安定していないようである。
FP32→FP16では、ほとんど精度が落ちなかったのと比較すると、ある程度精度は犠牲になるようだ。
推論速度
FP16とINT8の推論速度の比較は以下の通り。
floodagateからサンプリングした10万局面を、バッチサイズ256で推論した際の時間
モード | 推論時間(ms) |
---|---|
FP16 | 277.367 |
INT8 | 185.939 |
推論速度は、約1.49倍になっている。
NVIDIAの資料によると、FP16→INT8で、TFLOPSは2倍になるようなので、もっと推論速度が上がってほしいが、すべてTensorCoreで計算しているわけではないので今回の結果は妥当なのかもしれない。
出典:https://www.nvidia.com/content/apac/gtc/ja/pdf/2018/2051.pdf
まとめ
dlshogiのINT8対応について、キャリブレーションをうまく行うために苦労したので、解決方法を記事にまとめた。
INT8に対応したことで、推論速度が2080 Tiで、約1.49倍になった。
予測精度が落ちているため、推論速度が上がった分とバランスして強さにどれくらい影響がでるのか別途測定したい。