Python API vs C++ API of TensorRT
本質上,C++ API和Python API應該在支持您的需求方面接近相同。pythonapi的主要優點是數據預處理和后處理都很容易使用,因為您可以使用各種庫,如NumPy和SciPy。 在安全性很重要的情況下,例如,在汽車中,C++ API應該被使用。有關C++ API的更多信息,請參見使用C++ API。
有關如何使用Python優化性能的更多信息,請參閱how Do I optimize My Python performance?來自TensorRT最佳實踐指南。
Procedure
- Import TensorRT:
import tensorrt as trt
- Implement a logging interface through which TensorRT reports errors, warnings, and informational messages. The following code shows how to implement the logging interface. In this case, we have suppressed informational messages, and report only warnings and errors. There is a simple logger included in the TensorRT Python bindings.
TRT_LOGGER = trt.Logger(trt.Logger.WARNING)
使用TensorRT執行推理的第一步是從模型創建一個TensorRT網絡。
實現這一點的最簡單方法是使用TensorRT解析器庫導入模型, (see Importing A Model Using A Parser In Python, Importing From Caffe Using Python, Importing From TensorFlow Using Python, and Importing From ONNX Using Python), which supports serialized models in the following formats:
- Caffe (both BVLC and NVCaffe)
- Supports ONNX releases up to ONNX 1.6, and ONNX opsets 7 to 11, and
- UFF (used for TensorFlow)
An alternative is to define the model directly using the TensorRT Network API, (see Creating A Network Definition From Scratch Using The Python API). This requires you to make a small number of API calls to define each layer in the network graph and to implement your own import mechanism for the model’s trained parameters.
下面的步驟說明了如何使用OnnxParser和pythonapi直接導入ONNX模型。 關於這個任務
有關更多信息,請參閱使用Python(introductive_parser_samples)示例將Caffe、TensorFlow和ONNX模型導入TensorRT的簡介。
注:
一般來說,較新版本的OnnxParser設計為向后兼容,因此,遇到由早期版本的ONNX導出器生成的模型文件不會引起問題。當更改不向后兼容時,可能會出現一些異常。在本例中,將早期的ONNX模型文件轉換為更高版本的支持版本。有關此主題的詳細信息,請參閱ONNX Model Opset Version Converter。
用戶模型也有可能是由一個支持比TensorRT附帶的ONNX解析器支持的操作集更新的導出工具生成的。在這種情況下,檢查發布到GitHub的TensorRT的最新版本onnx-tensorrt是否支持所需的版本。有關更多信息,請參閱Python中使用Object Detection With The ONNX TensorRT Backend In Python (yolov3_onnx)示例。
支持的版本由onnx_trt中的BACKEND_optset_version變量定義_后端.cpp. 從GitHub下載並構建最新版本的ONNXTensorRT解析器。可以在這里找到構建說明:用於TensorRT backend for ONNX后端。
在tensorrt7.0中,ONNX解析器只支持全維模式,這意味着必須使用explicitBatch標志集創建網絡定義。有關詳細信息,請參見使用動態形狀Working With Dynamic Shapes。
builder的功能之一是搜索其CUDA內核目錄,以獲得最快的實現,因此有必要使用相同的GPU來構建優化引擎將運行的GPU。
關於這個任務
IBuilderConfig有許多屬性,您可以設置這些屬性來控制諸如網絡運行的精度,以及自動調整參數,例如在確定哪個內核最快時,TensorRT應該為每個內核計時多少次(迭代次數越多,運行時間越長,但是對噪聲的敏感度較低。)您還可以查詢構建器,以找出硬件本機支持哪些混合精度類型。
一個特別重要的屬性是最大工作空間大小。
層算法通常需要臨時工作空間。此參數限制網絡中任何層可以使用的最大大小。如果提供的划痕不足,則可能是TensorRT無法找到給定層的實現。
有關用Python構建引擎的更多信息,請參閱使用Python(introductive_parser_samples)示例將Caffe、TensorFlow和ONNX模型導入TensorRT的簡介。
Procedure
- Build the engine using the builder object:
with trt.Builder(TRT_LOGGER) as builder, builder.create_builder_config() as config:
config.max_workspace_size = 1 << 20 # This determines the amount of memory available to the builder when building an optimized engine and should generally be set as high as possible.
with builder.build_engine(network, config) as engine:
# Do inference here.
When the engine is built, TensorRT makes copies of the weights.
- Perform inference. To perform inference, follow the instructions outlined in Performing Inference In Python.
- 4. Serializing A Model In Python
從這里開始,您可以序列化引擎,也可以直接使用引擎進行推斷。在使用模型進行推理之前,序列化和反序列化模型是可選的步驟—如果需要,可以直接使用引擎對象進行推理。
關於這個任務
序列化時,您正在將引擎轉換為一種格式,以便存儲並在以后用於推斷。要用於推斷,只需對引擎進行反序列化。序列化和反序列化是可選的。由於從網絡定義創建引擎可能很耗時,因此可以避免每次應用程序重新運行時重新生成引擎,方法是序列化一次引擎並在推斷時反序列化它。因此,在構建引擎之后,用戶通常希望序列化它以備以后使用。
注意:序列化引擎不能跨平台或TensorRT版本移植。引擎是特定於確切的GPU模型,他們是建立在(除了平台和TensorRT版本)。
- Serialize the model to a modelstream:
serialized_engine = engine.serialize()
- Deserialize modelstream to perform inference. Deserializing requires creation of a runtime object:
with trt.Runtime(TRT_LOGGER) as runtime: engine = runtime.deserialize_cuda_engine(serialized_engine)
It is also possible to save a serialized engine to a file, and read it back from the file:
- Serialize the engine and write to a file:
- with open(“sample.engine”, “wb”) as f:
f.write(engine.serialize())
- Read the engine from the file and deserialize:
- with open(“sample.engine”, “rb”) as f, trt.Runtime(TRT_LOGGER) as runtime:
engine = runtime.deserialize_cuda_engine(f.read())
下面的步驟說明了如何在Python中執行推理,現在您有了一個引擎。
Procedure
為輸入和輸出分配一些主機和設備緩沖區。本例假設context.all_binding_dimensions == True,並且引擎在binding_index=0時有一個輸入,在binding_index=1時有一個輸出:
# Determine dimensions and create page-locked memory buffers (i.e. won't be swapped to disk) to hold host inputs/outputs.
h_input = cuda.pagelocked_empty(trt.volume(context.get_binding_shape(0)), dtype=np.float32)
h_output = cuda.pagelocked_empty(trt.volume(context.get_binding_shape(1)), dtype=np.float32)
# Allocate device memory for inputs and outputs.
d_input = cuda.mem_alloc(h_input.nbytes)
d_output = cuda.mem_alloc(h_output.nbytes)
# Create a stream in which to copy inputs/outputs and run inference.
stream = cuda.Stream()
創建一些空間來存儲中間激活值。由於引擎保存網絡定義和訓練參數,因此需要額外的空間。這些在執行上下文中保存:
with engine.create_execution_context() as context:
# Transfer input data to the GPU.
cuda.memcpy_htod_async(d_input, h_input, stream)
# Run inference.
context.execute_async_v2(bindings=[int(d_input), int(d_output)], stream_handle=stream.handle)
# Transfer predictions back from the GPU.
cuda.memcpy_dtoh_async(h_output, d_output, stream)
# Synchronize the stream
stream.synchronize()
# Return the host output.
return h_output
一個引擎可以有多個執行上下文,允許一組權重用於多個重疊的推理任務。例如,您可以使用一個引擎和每個流一個上下文來處理並行CUDA流中的圖像。每個上下文都將在與引擎相同的GPU上創建。