TensorRT加速模型推理的原理
- 深度学习模型在训练时经常用32位或者16位的数据,然而在推理时并不一定需要这么高的精度,所以TensorRT支持16位或者8位的推理,可以对模型的inference进行加速
- TensorRT对于网络结构进行了重构,把一些能够合并的运算合并在了一起,针对GPU的特性做了优化
网络结构垂直整合
将目前主流神经网络的conv、BN、Relu三个层融合为了一个层,所谓CBR
网络水平组合
水平组合是指将输入为相同张量和执行相同操作的层融合一起
TensorRT使用流程
1. 初始化
Logger:日志记录器,可用于记录模型编译的过程
创建logger:
class Logger : public ILogger
{
void log(Severity severity, const char* msg) noexcept override
{
// 抑制信息级别的消息
if (severity <= Severity::kWARNING)
cout << msg << endl;
}
};
Logger logger;
Builder:可用于创建 Network,对模型进行序列化生成engine
Network:由 Builder 的创建,最初只是一个空的容器
创建builder,并用builder创建network:
auto builder = unique_ptr<IBuilder>(createInferBuilder(logger));
// flag为0:同时支持动态和静态输出
// flag为1:仅支持静态输出
auto network = unique_ptr<INetworkDefinition>(builder->createNetworkV2(flag));
2. 转换模型
Parser:用于解析 Onnx 等模型
ONNX解析器:
auto parser = unique_ptr<nvonnxparser::IParser>(nvonnxparser::createParser(*network, logger));
// IParser 是一个用于解析ONNX(Open Neural Network Exchange)模型文件的类。
// IParser 类的主要功能是将ONNX模型文件解析为TensorRT可以理解的网络定义
解析模型:
parser->parseFromFile(file_path, static_cast<int32_t>(ILogger::Severity::kWARNING));
3. 读取模型並构建推理引擎以及推理上下文
context:上接 engine,下接 inference,因此解释为上下文
用builder创建config,并用config做一些初始化设置:
// 创建构建配置,用来指定trt如何优化模型
auto config = unique_ptr<IBuilderConfig>(builder->createBuilderConfig());
// 工作空间大小
config->setMemoryPoolLimit(MemoryPoolType::kWORKSPACE, 1U << 20);
// 设置精度
config->setFlag(nvinfer1::BuilderFlag::kFP16);
用buider创建engine(推理引擎):
auto engine = unique_ptr<IHostMemory>(builder->buildSerializedNetwork(*network, *config));
对engine进行序列化与反序列化:
// engine的序列化
IHostMemory *serializedModel = engine->serialize();
// 保存
std::ofstream p("saved.engine", std::ios::binary);
if (!p)
{
std::cerr << "Could not open plan output file" << std::endl;
assert(false);
}
p.write(reinterpret_cast<const char*>(serialized_engine->data()), serialized_engine->size());
// 安全删除
engine->destroy();
network->destroy();
builder->destroy();
serializedModel->destroy();
// 创建runtime
auto runtime = unique_ptr<IRuntime>(createInferRuntime(logger));
// 读取engine,反序列化
auto plan = load_engine_file(engine_file_path);
auto engine = shared_ptr<ICudaEngine>(runtime->deserializeCudaEngine(plan.data(), plan.size()));
用engine创建context(推理上下文):
auto context = unique_ptr<IExecutionContext>(engine->createExecutionContext());
context->setTensorAddress(INPUT_NAME, inputBuffer);
context->setTensorAddress(OUTPUT_NAME, outputBuffer);
// 如果engine的输入是动态大小,则还需要额外指定input shapes
context->setInputShape(INPUT_NAME, inputDims);
4. 执行推理
// 创建cuda流
cudaStream_t stream;
cudaStreamCreate(&stream);
//执行推理
context->enqueueV3(stream);
cudaStreamSynchronize(stream);
cudaStreamDestroy(stream);