より詳細な記録には、TensorRT の Python インターフェイスの使用、環境設定、モデル変換、静的および動的モデル推論がまとめられています。

インターネット上の TensorRT の紹介からの抜粋から始めましょう。

TensorRT は Nvidia が独自のプラットフォーム用に作成したアクセラレーション パッケージで、モデルの実行速度を向上させるために主に 2 つのことを行います。

  1. TensorRT は INT8 および FP16 計算をサポートします。深層学習ネットワークは通常、トレーニング時に 32 ビットまたは 16 ビットのデータを使用します。TensorRT は、推論を高速化するという目的を達成するために、ネットワーク推論においてそれほど高い精度を選択しません。
  2. TensorRT はネットワーク構造を再構築し、組み合わせ可能ないくつかの演算を組み合わせて、GPU の特性に合わせて最適化しました。ほとんどの深層学習フレームワークは GPU 向けにパフォーマンスが最適化されておらず、GPU の生産者および移植者である Nvidia は、当然のことながら、自社の GPU 用の高速化ツールである TensorRT を発売しました。ディープラーニングモデルでは、畳み込み層、バイアス層、リロード層などの最適化を行わないと、これら3層はcuDNNに対応するAPIを3回呼び出す必要がありますが、実際にはこれら3層をマージして実装することは完全に可能です, TensorRT は、マージ可能なネットワークをいくつかマージします。典型的な開始ブロックを介してこのようなマージ操作を見てみましょう。

TensorRT はモデルの推論最適化に使用されており、Python インターフェースも備えていますが、実際の使用テストの結果、Python インターフェースのモデル推論速度は基本的に C++ と同等でした。ここでは、環境の構成からモデルの変換、推論プロセス、およびモデルの INT8 量子化に至るまで、TensorRT Python インターフェイスのより詳細な記録を示します。時間があれば、それも記載します。筆者が使用しているバージョンは TensorRT7.0 版で、モデルの動的サイズの順推論をサポートしているバージョンであり、以下では静的推論と動的推論に分けて紹介します。

TensorRT 環境構成

tensorRT の構成は非常に簡単で、公式サイトに登録し、アンケートに記入するとダウンロードできます 筆者は TensorRT-7.0.0.11.CentOS-7.6.x86_64-gnu.cuda-9.0.cudnn7.6 を使用しています。 tar.gz バージョンを保存し、保存ディレクトリに移動して直接解凍し、lib の下にさまざまなコンパイル済みパッケージと、非常に重要な cuda 環境を設定します。

tar -zxvf TensorRT-7.0.0.11.CentOS-7.6.x86_64-gnu.cuda-9.0.cudnn7.6.tar.gz
sudo vim ~/.bashrc
#添加下面路径,注意改成自己的tensorRT的lib路径,cuda的路径
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/caidou/A/TensorRT-7.0.0.11/lib
export C_INCLUDE_PATH=/usr/local/cuda-9.0/include/:${C_INCLUDE_PATH}
export CPLUS_INCLUDE_PATH=/usr/local/cuda-9.0/include/:${CPLUS_INCLUDE_PATH}
#使其生效
source ~/.bashrc

次に、 pip は解凍後に適切なバージョンの python-tensorrt を python ディレクトリにインストールし、 pip は pycuda をインストールします。インポートは成功しました。

import tensorrt
import pycuda

TensorRT モデルの変換

モデルを変換するには主に 2 つの方法があります。1 つは、最初に pytorch または keras でトレーニングされたモデルを ONNX モデルに変換し、次に TensorRT を使用して ONNX モデルを直接解析する方法ですが、この方法では操作によって tensorrt モデルが変換されてしまう場合があります。または、ONNX に切り替えるときにバージョンが変わりすぎると、trt モデルが失敗しますが、このとき、tensorrt 独自の API を使用してネットワークを書き換えて、trt モデルに切り替えることができます。ここでは前者のみを記載しており、静的サイズ変換と動的サイズ変換に分かれており、API 変換を使用するための公式チュートリアルもあります。

動的ディメンションを使用した trt モデルへの変換

import tensorrt as trt
import pycuda.driver as cuda
import pycuda.autoinit
import common
import os
def build_engine(onnx_file_path,engine_file_path):
    """Takes an ONNX file and creates a TensorRT engine to run inference with"""
    TRT_LOGGER = trt.Logger(trt.Logger.WARNING)
    with trt.Builder(TRT_LOGGER) as builder, builder.create_network(common.EXPLICIT_BATCH) as network, trt.OnnxParser(network, TRT_LOGGER) as parser:
        builder.max_workspace_size = 1 << 28 # 256MiB
        builder.max_batch_size = 1
        config = builder.create_builder_config()
        config.max_workspace_size = common.GiB(6)
        profile = builder.create_optimization_profile()
        profile.set_shape("input_1_0", (1,100,100,3),(1,1024,1024,3), (1,2048,2048,3))
        idx = config.add_optimization_profile(profile)
        # Parse model file
        if not os.path.exists(onnx_file_path):
            print('ONNX file {} not found, please run yolov3_to_onnx.py first to generate it.'.format(onnx_file_path))
            exit(0)
        print('Loading ONNX file from path {}...'.format(onnx_file_path))
        with open(onnx_file_path, 'rb') as model:
            print('Beginning ONNX file parsing')
            if not parser.parse(model.read()):
                print ('ERROR: Failed to parse the ONNX file.')
                for error in range(parser.num_errors):
                    print (parser.get_error(error))
                return None
        print('Completed parsing of ONNX file')
        print('Building an engine from file {}; this may take a while...'.format(onnx_file_path))
        engine = builder.build_engine(network,config=config)
        print("Completed creating Engine")
        with open(engine_file_path, "wb") as f:
            f.write(engine.serialize())
        return engine
if __name__ =="__main__":
    onnx_path1 = '/home/caidou/project/trt_python/mode1_1_-1_-1_3.onnx'
    engine_path = '/home/caidou/trt_python/model_1_-1_-1_3.engine'
    build_engine(onnx_path1,engine_path)

それらに共通するのは公式です。

静的サイズに変換された trt モデル

import tensorrt as trt
import pycuda.driver as cuda
import pycuda.autoinit
import common
import os
def build_engine(onnx_file_path,engine_file_path):
    """Takes an ONNX file and creates a TensorRT engine to run inference with"""
    TRT_LOGGER = trt.Logger(trt.Logger.WARNING)
    with trt.Builder(TRT_LOGGER) as builder, builder.create_network(common.EXPLICIT_BATCH) as network, trt.OnnxParser(network, TRT_LOGGER) as parser:
        builder.max_workspace_size = 1 << 28 # 256MiB
        builder.max_batch_size = 1
        # Parse model file
        if not os.path.exists(onnx_file_path):
            print('ONNX file {} not found, please run yolov3_to_onnx.py first to generate it.'.format(onnx_file_path))
            exit(0)
        print('Loading ONNX file from path {}...'.format(onnx_file_path))
        with open(onnx_file_path, 'rb') as model:
            print('Beginning ONNX file parsing')
            if not parser.parse(model.read()):
                print ('ERROR: Failed to parse the ONNX file.')
                for error in range(parser.num_errors):
                    print (parser.get_error(error))
                return None
        print('Completed parsing of ONNX file')
        print('Building an engine from file {}; this may take a while...'.format(onnx_file_path))
        engine = builder.build_cuda_engine(network)
        print("Completed creating Engine")
        with open(engine_file_path, "wb") as f:
            f.write(engine.serialize())
        return engine
if __name__ =="__main__":
    onnx_path1 = '/home/caidou/project/trt_python/model4_256_256.onnx'
    engine_path = '/home/caidou/project/trt_python/model4_256_256.engine'
    build_engine(onnx_path1,engine_path)

サイズ範囲を設定する必要はありません。他にもいくつかの設定があります。エンジンを生成するときは API に注意してください。使用方法を誤るとエラーが報告されます。

 TensorRT モデルの推論

推論は依然として動的サイズと固定サイズに分かれています。動的推論の C++ バージョンにはより多くの情報があり、Python インターフェイスは比較的小さいです。固定サイズ推論の公式デモもあります。これは非同期推論と同期推論に分かれていますが、筆者がなぜ計測したのかは分かりませんが、速度差は小さいです。

Python 推論は、numpy 形式でのデータ入力を受け入れます。

動的推論

import tensorrt as trt
import pycuda.driver as cuda
#import pycuda.driver as cuda2
import pycuda.autoinit
import numpy as np
import cv2
def load_engine(engine_path):
    #TRT_LOGGER = trt.Logger(trt.Logger.WARNING)  # INFO
    TRT_LOGGER = trt.Logger(trt.Logger.ERROR)
    with open(engine_path, 'rb') as f, trt.Runtime(TRT_LOGGER) as runtime:
        return runtime.deserialize_cuda_engine(f.read())

path ='/home/caidou/trt_python/model_1_-1_-1_3.engine'
#这里不以某个具体模型做为推断例子.

# 1. 建立模型,构建上下文管理器
engine = load_engine(path)
context = engine.create_execution_context()
context.active_optimization_profile = 0

#2. 读取数据,数据处理为可以和网络结构输入对应起来的的shape,数据可增加预处理
imgpath = '/home/caidou/test/aaa.jpg'
image = cv2.imread(imgpath)
image = np.expand_dims(image, 0)  # Add batch dimension.  


#3.分配内存空间,并进行数据cpu到gpu的拷贝
#动态尺寸,每次都要set一下模型输入的shape,0代表的就是输入,输出根据具体的网络结构而定,可以是0,1,2,3...其中的某个头。
context.set_binding_shape(0, image.shape)
d_input = cuda.mem_alloc(image.nbytes)  #分配输入的内存。


output_shape = context.get_binding_shape(1) 
buffer = np.empty(output_shape, dtype=np.float32)
d_output = cuda.mem_alloc(buffer.nbytes)    #分配输出内存。
cuda.memcpy_htod(d_input,image)
bindings = [d_input ,d_output]

#4.进行推理,并将结果从gpu拷贝到cpu。
context.execute_v2(bindings)  #可异步和同步
cuda.memcpy_dtoh(buffer,d_output)  
output = buffer.reshape(output_shape)

#5.对推理结果进行后处理。这里只是举了一个简单例子,可以结合官方静态的yolov3案例完善。

全体的なパイプラインは上記の 1 ~ 5 です。

静的推論

静的推論は動的推論と似ていますが、毎回入出力メモリ空間を割り当てる必要がない点が異なります。

import tensorrt as trt
import pycuda.driver as cuda
#import pycuda.driver as cuda2
import pycuda.autoinit
import numpy as np
import cv2
path ='/home/caidou/trt_python/model_1_4_256_256.engine'
engine = load_engine(path)
imgpath = 'aaa.jpg'
context = engine.create_execution_context()
image1 = cv2.imread(imgpath)
image1 = cv2.resize(image1,(256,256))
image2 = image1.copy()
image3 = image1.copy()
image4 = image1.copy()
image = np.concatenate((image1,image2,image3,image4))
image = image.reshape(-1,256,256)

# image = np.expand_dims(image, axis=1)
image = image.astype(np.float32)

image = image.ravel()#数据平铺
outshape= context.get_binding_shape(1) 
output = np.empty((outshape), dtype=np.float32)
d_input = cuda.mem_alloc(1 * image.size * image.dtype.itemsize)
d_output = cuda.mem_alloc(1*output.size * output.dtype.itemsize)
bindings = [int(d_input), int(d_output)]
stream = cuda.Stream()
for i in tqdm.tqdm(range(600)):
    cuda.memcpy_htod(d_input,image)
    context.execute_v2(bindings)
    cuda.memcpy_dtoh(output, d_output)

TensorRT モデルの量子化

つづく...

この部分は時間ができたら追加します

おすすめ

転載: blog.csdn.net/qq_36276587/article/details/113175314