最近在学习tensorrt,写篇博客记录一下,本博客只针对入门使用者。
NVIDIA® TensorRT™ is an SDK for optimizing trained deep learning models to enable high-performance inference. TensorRT contains a deep learning inference optimizer for trained deep learning models, and a runtime for execution.
简单来说tensorrt是一个高性能推理部署框架,包括两个主要部分:优化器、执行器。
环境搭建主要包括三个部分:tensorrt, cuda, cudnn
建议使用docker,如百度paddle项目提供的gpu docker,里面已经安装好了cuda和cudnn,然后再下载一个 tensorrt即可。
docker下载:nvidia-docker pull registry.baidubce.com/paddlepaddle/paddle:2.2.2-gpu-cuda11.2-cudnn8
参考链接:百度paddlepaddle框架
tensorrt下载:
进入官网下载压缩包 官网下载链接
运行docker后,在自己的目录下下载Tensorrt安装包,解压,里面有头文件、库、可执行命令以及各种demo等。
cuda可以简单理解为一个工作台,一个编译器,一种语言。
cudnn是用cuda定义的专用的深度学习加速库。
如果把cuda类比成c++语言、 g++编译器, 那cudnn就是用c++写的一个动态库。
paddle docker环境下:cuda的已经安装好了,目录是:/usr/local/cuda/,里面有所需要的头文件和库。 cudnn动态库的目录是:/usr/lib/x86_64-linux-gnu/libcudnn.so
假设有一个很简单的模型,模型只有唯一的一层conv2d :kernel-size=2*2;stride=1;假设输入是shape为[1,1,4,4]的全1数据,那么输出就是shape为[1,1,3,3]的tensor,且数值都为4。
完整的demo代码如下:
#include "NvInfer.h"
#include
#include
#include
class Logger : public nvinfer1::ILogger
{
public:
void log(Severity severity, const char* msg) noexcept override
{
// suppress info-level messages
if (severity <= Severity::kVERBOSE)
std::cout << msg << std::endl;
}
};
int main() {
Logger logger;
// Create an instance of the builder:
nvinfer1::IBuilder* builder = nvinfer1::createInferBuilder(logger);
// Create a Network Definition
uint32_t flag = 1U << static_cast<uint32_t>(nvinfer1::NetworkDefinitionCreationFlag::kEXPLICIT_BATCH);
nvinfer1::INetworkDefinition* network = builder->createNetworkV2(flag);
// Add the Input layer to the network
auto input_data = network->addInput("input", nvinfer1::DataType::kFLOAT, nvinfer1::Dims4{1, 1, 4, 4});
// Add the Convolution layer with hidden layer input nodes, strides and weights for filter and bias.
std::vector<float>filter(2*2, 1.0);
nvinfer1::Weights filter_w{nvinfer1::DataType::kFLOAT, filter.data(), 4};
nvinfer1::Weights bias_w{nvinfer1::DataType::kFLOAT, nullptr, 0};
auto conv2d = network->addConvolution(
*input_data, 1, nvinfer1::DimsHW{2, 2}, filter_w, bias_w);
conv2d->setStride(nvinfer1::DimsHW{1, 1});
// Add a name for the output of the conv2d layer so that the tensor can be bound to a memory buffer at inference time:
conv2d->getOutput(0)->setName("output");
// Mark it as the output of the entire network:
network->markOutput(*conv2d->getOutput(0));
// Building an Engine(optimize the network)
nvinfer1::IBuilderConfig* config = builder->createBuilderConfig();
nvinfer1::IHostMemory* serializedModel = builder->buildSerializedNetwork(*network, *config);
nvinfer1::IRuntime* runtime = nvinfer1::createInferRuntime(logger);
nvinfer1::ICudaEngine* engine = runtime->deserializeCudaEngine(serializedModel->data(), serializedModel->size());
// Prepare input_data
int32_t inputIndex = engine->getBindingIndex("input");
int32_t outputIndex = engine->getBindingIndex("output");
std::vector<float> input(4*4, 1.0);
std::vector<float> output(3*3);
void *GPU_input_Buffer_ptr; // a host ptr point to a GPU buffer
void *GPU_output_Buffer_ptr; // a host ptr point to a GPU buffer
void* buffers[2];
cudaMalloc(&GPU_input_Buffer_ptr, sizeof(float)*4*4); //malloc gpu buffer for input
cudaMalloc(&GPU_output_Buffer_ptr, sizeof(float)*3*3); //malloc gpu buffer for output
cudaMemcpy(GPU_input_Buffer_ptr, input.data(), input.size()*sizeof(float), cudaMemcpyHostToDevice); // copy input data from cpu to gpu
buffers[inputIndex] = static_cast<void*>(GPU_input_Buffer_ptr);
buffers[outputIndex] = static_cast<void*>(GPU_output_Buffer_ptr);
// Performing Inference
nvinfer1::IExecutionContext *context = engine->createExecutionContext();
context->executeV2(buffers);
// copy result data from gpu to cpu
cudaMemcpy(output.data(), GPU_output_Buffer_ptr, output.size()*sizeof(float), cudaMemcpyDeviceToHost);
// display output
std::cout << "output is : \n";
for(auto i : output)
std::cout << i << " ";
std::cout << std::endl;
}
本demo涉及的api来自参考文档:
开发者文档第6.4.1节 和 第三节 The C++ API
代码很简单清晰,官方文档较完善,这里不再多述。
唯一一点是,代码中使用了cuda的两个api(位于头文件#include
cud api参考文档
demo中使用的其他api位于头文件NvInfer.h中,在下载的TensorRT-8.2.3.0安装包中。
cuda所在目录:/usr/local/cuda/
cudnn库路径:/usr/lib/x86_64-linux-gnu/libcudnn.so
下载的TensorRT-8.2.3.0根目录: /TensorRT-8.2.3.0
编译指令如下:
g++ -std=c++11 /weishengying/main.cc \
-I /TensorRT-8.2.3.0/include/ \
-I /usr/local/cuda/include \
-L /usr/local/cuda/lib64 -lcudart \
-L /usr/lib/x86_64-linux-gnu/ -lcudnn \
-L /TensorRT-8.2.3.0/lib/ -lnvinfer
./a.out
最终结果为:
output is :
4 4 4 4 4 4 4 4 4
TensorRT github 仓库