TadaoYamaokaの日記

山岡忠夫Homeで公開しているプログラムの開発ネタを中心に書いていきます。

dlshogiのINT8対応

前回の記事にも書いたが、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倍になった。
予測精度が落ちているため、推論速度が上がった分とバランスして強さにどれくらい影響がでるのか別途測定したい。