100 TensorRT Puglin開發(fā)
1. 核心原理
- 定義計算邏輯:告訴 GPU 如何執(zhí)行這個特殊層的計算。
- 集成到 TensorRT:讓 TensorRT 在推理時調(diào)用你的計算邏輯。
2. 開發(fā)步驟
1. 創(chuàng)建一個插件類,繼承TensorRT的 IPluginV2 接口,實現(xiàn)關(guān)鍵函數(shù)
#include <NvInfer.h>
class MyPlugin : public nvinfer1::IPluginV2 {
public:
// 必須實現(xiàn)的函數(shù)
const char* getPluginType() const override { return "MyPlugin"; }
const char* getPluginVersion() const override { return "1"; }
int getNbOutputs() const override { return 1; } // 輸出張量數(shù)量
nvinfer1::Dims getOutputDimensions(int index, const nvinfer1::Dims* inputs, int numInputDims) override {
// 定義輸出張量的形狀(例如和輸入形狀相同)
return inputs[0];
}
// 其他函數(shù)(序列化、反序列化、初始化等)...
};
2. 實現(xiàn)計算邏輯(核心)
在自定義插件類,enqueue函數(shù)編寫CUDA核函數(shù),定義此算子的數(shù)據(jù)處理步驟
int MyPlugin::enqueue(
int batchSize,
const void* const* inputs, // 輸入數(shù)據(jù)指針數(shù)組
void* const* outputs, // 輸出數(shù)據(jù)指針數(shù)組
void* workspace, // 臨時顯存空間
cudaStream_t stream // CUDA 流
) {
// 調(diào)用 CUDA 核函數(shù)(例如逐元素加法)
const float* input = static_cast<const float*>(inputs[0]);
float* output = static_cast<float*>(outputs[0]);
int numElements = batchSize * inputDims.d[0] * inputDims.d[1] * ...; // 計算總元素數(shù)
myKernel<<<gridSize, blockSize, 0, stream>>>(input, output, numElements);
return 0;
}
// 示例 CUDA 核函數(shù)(每個線程處理一個元素)
__global__ void myKernel(const float* input, float* output, int numElements) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < numElements) {
output[idx] = input[idx] + 1.0f; // 自定義計算(例如每個元素加1)
}
}
3. 注冊插件
告訴TensorRT自己實現(xiàn)了某個算子
class MyPluginCreator : public nvinfer1::IPluginCreator {
public:
const char* getPluginName() const override { return "MyPlugin"; }
const char* getPluginVersion() const override { return "1"; }
nvinfer1::IPluginV2* createPlugin(const char* name, const nvinfer1::PluginFieldCollection* fc) override {
return new MyPlugin();
}
// 其他函數(shù)(反序列化等)...
};
// 注冊插件
REGISTER_TENSORRT_PLUGIN(MyPluginCreator);
4. 編譯成動態(tài)庫
# 示例編譯命令(Linux)
g++ -shared -o libmyplugin.so my_plugin.cpp -I/path/to/tensorrt/include -L/path/to/tensorrt/lib -lnvinfer
4. ONNX轉(zhuǎn)TensorRT,TensorRT自動調(diào)用注冊插件
import tensorrt as trt
# 加載插件庫
trt.init_libnvinfer_plugins(trt.Logger(), "")
with open("model.onnx", "rb") as f:
engine = runtime.deserialize_cuda_engine(f.read())
補充:
1. TensorRT原理補充
TensorRT流程:
- 將模型(例如ONNX)轉(zhuǎn)化為TensorRT內(nèi)部計算圖(由層節(jié)點和數(shù)據(jù)流邊組成)
- 優(yōu)化計算圖
- 生成引擎:將優(yōu)化后計算圖編譯成二進制文件,供推理時直接調(diào)用。
關(guān)于IPluginV2類
- TensorRT 的計算圖由多個“層”(Layer)組成,每個層必須遵守統(tǒng)一的接口規(guī)范。
- IPluginV2 就是這個規(guī)范,它定義了所有層必須實現(xiàn)的功能,例如:
- 計算邏輯:enqueue() 函數(shù)中實現(xiàn) GPU 核函數(shù)
- 內(nèi)存管理:configurePlugin() 定義輸入輸出內(nèi)存需求。
- 序列化與反序列化:serialize() 和 deserialize() 用于保存和加載模型。
- 形狀推導(dǎo):getOutputDimensions() 確定輸出張量形狀。
關(guān)于Creator 類的作用
- IPluginCreator 是插件的“工廠”,負(fù)責(zé)兩件事:
- 生產(chǎn)插件實例:當(dāng) TensorRT 解析到自定義層時,調(diào)用 createPlugin() 創(chuàng)建插件對象。
- 注冊插件信息:告訴 TensorRT 插件的名稱、版本、參數(shù)格式,方便后續(xù)查找和調(diào)用。
- TensorRT 在解析模型時,可能需要在不同階段(如構(gòu)建引擎、反序列化引擎)動態(tài)創(chuàng)建插件。Creator 類通過統(tǒng)一的接口管理插件的生命周期,實現(xiàn)“即插即用”。
2. TensorRT版本是否和GPU型號相關(guān)?在一個型號轉(zhuǎn)換的TensorRT文件,在另一個GPU型號可以直接使用嗎?
- TensorRT 生成的推理引擎文件(.engine)與 GPU 型號直接相關(guān),TensorRT 在優(yōu)化模型時,會根據(jù) GPU 的計算能力生成特定的內(nèi)核代碼。在 A 型號 GPU 上生成的 TensorRT 引擎文件,若直接拿到 B 型號 GPU 上使用,可能無法運行,除非兩者滿足特定條件。

浙公網(wǎng)安備 33010602011771號