前面为了多了解一下TensorRT废话比较多,接下来尽量精简
二、C++ 版本的TensorRT
训练完模型以后使用TensorRT的必要步骤包括:
通过模型创建一个TensorRT的网络定义;
调用TensorRT构建器根据网络结构创建一个优化运行引擎;
序列化和反序列化这个引擎,以便在运行时快速重建;
将数据加载到引擎中来完成推断。
从本质上讲,C ++ API和Python API在应用领域来讲应该完全相同。 C ++ API能够用于任何性能要求高的场景,以及安全性很重要的场合,例如汽车行业。Python API的主要优点是数据预处理和后处理比较容易,因为有很多方便的库可以使用,比如NumPy和SciPy。
2.1在C++中初始化TensorRT对象
为了完成推断你需要使用IExecutionContext对象,而为了创建IExecutionContext对象,你首相需要创建一个ICudaEngine对象 (这是引擎)。而引擎的创建有以下两种方式:1.从已经训练好的模型那里创建网络定义。这种情况下可以选择将引擎序列化并保存以供以后使用;2.通过在磁盘中读取已经序列化的引擎。在这种情况下,性能会更好,因为绕过了解析模型和创建中间对象的步骤。
下面开始对整个初始化流程做一下说明;
1.创建全局iLogger类型的对象。它用作TensorRT API各种方法的参数。完成创建一个logger对象的简单例子:
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;
2.创建iBuilder类型的对象可以通过一个叫作createInferBuilder(gLogger)的全局TensorRT API方法来实现,也就是说你的代码里应该有这句:
private: Logger gLogger (这句的位置不是放在这里定义的,放这里是为了讲述方面)
IBuilder* builder = createInferBuilder(gLogger); 这里的这个gLogger就是上一步定义的类class Logger : public nvinfer1::ILogger
图1.使用iLogger作为输入参数创建iBuilder
3.接下来为iBuilder定义的名为createNetwork的方法用于创建iNetworkDefinition类型的对象。
INetworkDefinition* network = builder->createNetwork();
图2.createNetwork()方法用于创建网络
4.接下来创建一个以iNetwork定义为输入的解析器,解析器种类有三种,定义方式分别是:
- ONNX: parser = nvonnxparser::createParser(*network, gLogger);
- NVCaffe: ICaffeParser* parser = createCaffeParser();
- UFF: parser = createUffParser();
以caffe为例(其他两种有所不同,知道了再补充)
const IBlobNameToTensor* blobNameToTensor = parser->parse(deployFile,modelFile,
*network,DataType::kFLOAT);
这里的deployFile就是caffe的deploy.prototxt文件,modelFile是你训练好的模型文件,*network就是第3步定义的网络。
图3.解析模型文件
5.调用iBuilder的一个名为buildCudaEngine()的方法来创建一个iCudaEngine类型的对象,
图4.创建TensorRT引擎
类似于这样:ICudaEngine* engine = builder->buildCudaEngine(*network);
也可以选择将引擎序列化并转储到文件中(可选)
图4-1.创建TensorRT引擎
6.接下来用createExecutionContext方法用于执行推理。
图5.创建一个 execution context方法
类似于这样:Execontext = engine->createExecutionContext()
如果序列化引擎被保留并保存到文件中,则可以绕过上述大多数步骤。尽管可以避免手动创建CUDA context(系统会默认创建context),但不建议这么做。 建议在创建运行时(runtime)或构建器(builder)对象之前创建和配置CUDA context,
构建器或运行时将通过与已创建的线程相关联的GPU context来创建。虽然如果缺省context不存在时会默认自动创建它,但还是建议在创建运行时或构建器对象之前创建和配置CUDA context。(重复说明手动创建的必要性)