TensorRT Developer Guide
Overview
NVIDIA TensorRT™是一个C ++库,可以帮助NVIDIA图形处理器(GPU)进行高性能推理。
TensorRT通过合并张量和图层,转换权重,选择高效的中间数据格式,并根据图层参数和
测量的性能从大型内核目录中进行选择,从而对网络进行定义并对其进行优化。
TensorRT包含导入方法,可帮助您为TensorRT表达训练有素的深度学习模型以优化和运行。 它是一种优化工具,可以应用图形优化和图层融合,并利用各种高度优化的内核集合找到该模
型的最快实现,以及可用于在推理上下文中执行此网络的运行时方法。
install
c++简易安装
1,首先从官网 下载TensorRT安装文件
2, 解压缩文件
$ tar -xzvf TensorRT-4.0.0.3.Ubuntu-16.04.4.x86_64-gnu.cuda-9.0.cudnn7.0.tar.gz
3, 添加环境变量
$ vim ~/.bashrc
$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:~/TensorRT-4.0.0.3/lib
$ source ~/.bashrc
Working With TensorRT Using The C++ API
Instantiating TensorRT Objects in C++
首先,您都必须实现一个日志记录接口,TensorRT通过该接口打印错误,警告和信息性消息。
日志记录接口可用于创建多个运行时和构建器实例,但是日志记录接口是一个单例(整个应用程序
中只有一个类实例且这个实例所占资源在整个应用程序中是共享的),所以你必须为每个对象使用
同一个日志记录实例。
class Logger : public ILogger
{
void log(Severity severity, const char* msg) override
{
// suppress info-level messages
if (severity != Severity::kINFO)
std::cout << msg << std::endl;
}
} gLogger;
Creating A Network Definition In C++
使用TensorRT进行inference的第一步是从您的模型创建TensorRT网络。实现此目的的最简单方法是使用
TensorRT解析器库导入模型,该解析器库支持以下格式的序列化模型:
sampleMNIST(BVLC和NVCaffe)
sampleOnnxMNIST 1.0和1.1,以及
sampleUffMNIST(用于TensorFlow)
另一种方法是使用TensorRT API直接定义模型。这要求您进行少量API调用以定义网络图中的每个层,并为模型的训练参数实现自己的导入机制。
在任何一种情况下,您都明确需要告诉TensorRT需要哪些tensors作为inference的输出。未标记为输出的tensors被认为是可被优化的瞬态值。输出tensors的数量没有限制,但是,将tensors标记为输出可能会禁止对tensors进行一些优化。在推理时,您将为引擎提供一个指向输入和输出缓冲区的指针数组。
现在我们只讨论如何基于一个caffe模型,导出网络定义。
- Create the TensorRT builder and network.
IBuilder* builder = createInferBuilder(gLogger);
nvinfer1::INetworkDefinition* network = builder->createNetwork();
- Parse caffe model to populate network, then set the outputs
std::vector<std::string> outputs{"prob"};
ICaffeParser* parser = createCaffeParser();
const IBlobNameToTensor* blobNameToTensor = parser->parse(deployFile,
modelFile,
*network,
DataType::kFLOAT);
for (auto& s : outputs)
network->markOutput(*blobNameToTensor->find(s.c_str()));
builder->setMaxBatchSize(maxBatchSize);
builder->setMaxWorkspaceSize(1 << 20);
- Build engine
ICudaEngine* engine = builder->buildCudaEngine(*network);
- Serialize engine
IHostMemory *serializedModel = engine->serialize();
// store model to disk
// <…>
serializedModel->destroy();
Performing Inference In C++
- Deserialize engine we serialized earlier
IRuntime* runtime = createInferRuntime(gLogger);
//get model from disk or hostMemory
ICudaEngine* engine = runtime->deserializeCudaEngine(trtModelStream->data(), trtModelStream->size(), nullptr);
IExecutionContext* context = engine->createExecutionContext();
- Use the input and output blob names to get the corresponding input and output index
int inputIndex = engine.getBindingIndex(INPUT_BLOB_NAME);
int outputIndex = engine.getBindingIndex(OUTPUT_BLOB_NAME);
- allocate GPU buffers
Dims3 inputDims = static_cast<Dims3&&>(engine->getBindingDimensions(inputIndex));
outputDims = static_cast<Dims3&&>(engine->getBindingDimensions(outputIndex));
size_t inputSize = batchSize * inputDims.d[0] * inputDims.d[1] * inputDims.d[2] * sizeof(float);
size_t outputSize = batchSize * outputDims.d[0] * outputDims.d[1] * outputDims.d[2] * sizeof(float);
void* buffers[2];
cudaMalloc(&buffers[inputIndex], inputSize);
cudaMalloc(&buffers[outputIndex], outputSize)
//copy dato to gpu
cudaMemcpy(buffers[inputIndex], input, batchSize * INPUT_H * INPUT_W * sizeof(float));
- do interence and get output
context->execute(batchSize, buffers);
cudaMemcpy(output.data(), buffers[outputIndex], output_size_, cudaMemcpyDeviceToHost);
请阅读官方demo/sampleMNIST,demo路径为TensorRT-4.0.1.6/samples/sampleMNIST
Working With Mixed Precision
混合精度是在计算方法中组合使用不同的数值精度。 TensorRT可以存储权重和激活,并以32位浮点,16位浮点或量化的8位整数执行层。
使用低于FP32的精度可减少内存使用,允许部署更大的网络。 数据传输花费的时间更少,计算性能也会提高,尤其是在Tensor Core支持该精度的GPU上。
默认情况下,TensorRT使用FP32推理,但它也支持FP16和INT8。 在运行FP16推理时,它会自动将FP32权重转换为FP16权重。
注意:指定网络的精度定义应用程序的最低可接受精度。 如果对于某些特定的内核参数集更快,或者如果不存在低精度内核,则可以选择更高精度的内核。
bool useFp16 = builder->platformHasFastFp16();
DataType modelDataType = useFp16 ? DataType::kHALF : DataType::kFLOAT; // create a 16-bit model if it's natively supported
const IBlobNameToTensor *blobNameToTensor =
parser->parse(locateFile(deployFile).c_str(), // caffe deploy file
locateFile(modelFile).c_str(), // caffe model file
*network, // network definition that the parser will populate
modelDataType);
// set up the network for paired-fp16 format if available
if(useFp16)
builder->setFp16Mode(true);
customer layer
These are the operations that are supported in a Caffe framework:
Convolution
Pooling
InnerProduct
SoftMax
ReLU, TanH, and Sigmoid
LRN
Power
ElementWise
Concatenation
Deconvolution
BatchNormalization
Scale
Crop
Reduction
Reshape
Permute
Dropout
可能存在支持的层不满足模型的特定需求。 在这种情况下,用户可以通过使用C++ API实现自定义层来扩展TensorRT功能。 自定义层(通常称为插件)由应用程序实现和实例化,它们必须跨越TensorRT引擎的生命周期。
要在C++中添加自定义图层,请实现IPluginExt类。 对于基于Caffe的网络,如果使用TensorRT Caffe Parser,您还将实现nvcaffeparser1 :: IPluginFactoryExt和nvinfer1 :: IPluginFactory类。
具体流程请参考demo/samplePlugin ,路径为/TensorRT-4.0.1.6/samples/samplePlugin