tensorrt基本流程

复制代码
构建四件套:Builder + Network + Parser + Config → Engine
推理三件套:Runtime + Engine + Context → 结果

构建阶段(离线):

bash 复制代码
auto builder = createInferBuilder(logger);
auto network = builder->createNetworkV2(...);
auto parser = createParser(*network, logger);
parser->parseFromFile("model.onnx", ...);
auto config = builder->createBuilderConfig();
config->setFlag(kFP16);
config->setMaxWorkspaceSize(1_GiB);
auto engine = builder->buildSerializedNetwork(*network, *config);
saveToFile(engine, "model.engine");

推理阶段(在线):

bash 复制代码
auto runtime = createInferRuntime(logger);
auto engine = runtime->deserializeCudaEngine(data, size);
auto context = engine->createExecutionContext(); // 每线程一个
// 分配 buffer → memcpy in → execute → memcpy out

TensorRT 的执行流程是高性能推理的核心。下面我将以 C++ 中解析 ONNX 模型 → 生成 Engine → 加载并推理 为例,完整、清晰地解释 TensorRT 的标准工作流程,包括每个阶段的作用和创建方式。

🧩 整体流程概览(两阶段)

TensorRT 推理分为两个独立阶段:

阶段 目的 是否必须每次运行? 输出
1. 构建阶段(Build Phase) 将 ONNX 转为优化后的 TensorRT Engine ❌ 只需一次(可离线) .engine 文件
2. 推理阶段(Inference Phase) 加载 Engine,执行前向计算 ✅ 每次推理都要 推理结果

💡 最佳实践:构建一次,推理多次(Engine 可序列化保存,避免重复构建)


🔧 第一阶段:构建 Engine(从 ONNX 到 .engine)

步骤 1:创建 Builder

cpp 复制代码
auto builder = std::unique_ptr<nvinfer1::IBuilder>(
    nvinfer1::createInferBuilder(logger)
);
  • 作用:TensorRT 的"总工程师",负责创建网络和配置优化。
  • 参数 :需要一个 ILogger(日志回调)。

步骤 2:创建 Network Definition

cpp 复制代码
const auto explicitBatch = 1U << static_cast<uint32_t>(
    nvinfer1::NetworkDefinitionCreationFlag::kEXPLICIT_BATCH
);
auto network = std::unique_ptr<nvinfer1::INetworkDefinition>(
    builder->createNetworkV2(explicitBatch)
);
  • 作用:定义计算图(节点、输入输出、算子)。
  • 注意 :ONNX 使用显式 batch,必须开启 kEXPLICIT_BATCH
  • 💡 几乎所有现代模型(ONNX/TensorFlow/PyTorch 导出)都必须使用 kEXPLICIT_BATCH!
  • 告诉 TensorRT:batch 维度是张量 shape 的一部分(即 shape 形如 [N, C, H, W])
    这是 ONNX、PyTorch 导出模型的标准格式

步骤 3:创建 Parser 并解析 ONNX

cpp 复制代码
auto parser = std::unique_ptr<nvonnxparser::IParser>(
    nvonnxparser::createParser(*network, logger)
);

parser->parseFromFile("model.onnx", 
    static_cast<int>(nvinfer1::ILogger::Severity::kWARNING)
);
  • 作用 :将 ONNX 文件解析成 TensorRT 的 INetworkDefinition
  • 依赖库 :需要链接 nvonnxparser

步骤 4:配置 Builder Config

cpp 复制代码
auto config = std::unique_ptr<nvinfer1::IBuilderConfig>(
    builder->createBuilderConfig()
);
config->setMaxWorkspaceSize(1 << 30); // 1GB
config->setFlag(nvinfer1::BuilderFlag::kFP16); // 启用 FP16
  • 作用 :设置优化策略:
    • 工作空间大小(影响 kernel 选择)
    • 精度模式(FP32 / FP16 / INT8)
    • 动态 shape(如果需要)

动态batch推理(看需求设置)

bash 复制代码
auto profile = builder->createOptimizationProfile();
profile->setDimensions("input", OptProfileSelector::kMIN, Dims4{1, 3, 640, 640});
profile->setDimensions("input", OptProfileSelector::kOPT, Dims4{4, 3, 640, 640});
profile->setDimensions("input", OptProfileSelector::kMAX, Dims4{16, 3, 640, 640});
config->addOptimizationProfile(profile);
config->setFlag(nvinfer1::BuilderFlag::kFP16);

步骤 5:构建 Engine

cpp 复制代码
auto plan = std::unique_ptr<nvinfer1::IHostMemory>(
    builder->buildSerializedNetwork(*network, *config)
);
  • 作用:执行图优化(层融合、精度校准、内核选择等),生成可执行计划。
  • 输出IHostMemory 是序列化的 Engine(二进制 blob)。

步骤 6:保存 Engine 到文件(可选但推荐)

cpp 复制代码
std::ofstream engineFile("model.engine", std::ios::binary);
engineFile.write(static_cast<char*>(plan->data()), plan->size());
engineFile.close();
  • 好处:下次直接加载,省去构建时间(构建可能耗时几十秒)。

▶️ 第二阶段:加载 Engine 并推理

步骤 1:读取 Engine 文件

cpp 复制代码
std::ifstream file("model.engine", std::ios::binary);
file.seekg(0, std::ios::end);
size_t size = file.tellg();
file.seekg(0, std::ios::beg);
std::vector<char> engineData(size);
file.read(engineData.data(), size);
file.close();

步骤 2:创建 Runtime 并反序列化 Engine

cpp 复制代码
auto runtime = std::unique_ptr<nvinfer1::IRuntime>(
    nvinfer1::createInferRuntime(logger)
);

auto engine = std::unique_ptr<nvinfer1::ICudaEngine>(
    runtime->deserializeCudaEngine(engineData.data(), size)
);
  • Runtime:负责将序列化 Engine 加载到 GPU。
  • ICudaEngine:优化后的可执行模型(只读,线程安全)。

步骤 3:创建 Execution Context

cpp 复制代码
auto context = std::unique_ptr<nvinfer1::IExecutionContext>(
    engine->createExecutionContext()
);
  • 作用:持有推理时的状态(如中间张量内存)。
  • 注意每个线程应有自己的 IExecutionContext(非线程安全)。

步骤 4:准备输入/输出内存(GPU + CPU)

获取输入/输出绑定信息
cpp 复制代码
int inputIndex = engine->getBindingIndex("input");   // 绑定名来自 ONNX
int outputIndex = engine->getBindingIndex("output");

auto inputDims = context->getBindingDimensions(inputIndex);
auto outputDims = context->getBindingDimensions(outputIndex);
分配 GPU 内存
cpp 复制代码
void* buffers[2];
cudaMalloc(&buffers[inputIndex], volume(inputDims) * sizeof(float));
cudaMalloc(&buffers[outputIndex], volume(outputDims) * sizeof(float));
准备 CPU 输入数据
cpp 复制代码
std::vector<float> inputData(volume(inputDims));
// ... 填充 inputData ...
cudaMemcpy(buffers[inputIndex], inputData.data(), 
           volume(inputDims) * sizeof(float), cudaMemcpyHostToDevice);

步骤 5:执行推理

cpp 复制代码
bool status = context->executeV2(buffers);
if (!status) { /* handle error */ }
  • executeV2:同步执行推理(输入/输出指针数组)。
  • 也有异步版本 enqueueV2(配合 CUDA Stream)。

步骤 6:拷贝结果回 CPU

cpp 复制代码
std::vector<float> outputData(volume(outputDims));
cudaMemcpy(outputData.data(), buffers[outputIndex],
           volume(outputDims) * sizeof(float), cudaMemcpyDeviceToHost);

步骤 7:释放资源

cpp 复制代码
cudaFree(buffers[inputIndex]);
cudaFree(buffers[outputIndex]);
// unique_ptr 会自动释放 engine/context/runtime

📊 流程图总结

复制代码
[ONNX 文件]
     ↓
 Builder → Network → Parser → 解析 ONNX
     ↓
 BuilderConfig → 设置 FP16 / workspace
     ↓
 buildSerializedNetwork() → 生成序列化 Engine
     ↓
 保存为 .engine 文件(离线完成)

───────────────────────────────
[推理时]
     ↓
 Runtime ← deserializeCudaEngine(.engine)
     ↓
 ExecutionContext ← createExecutionContext()
     ↓
 分配 GPU 输入/输出缓冲区
     ↓
 cudaMemcpy (Host → Device)
     ↓
 executeV2() → 执行推理
     ↓
 cudaMemcpy (Device → Host)
     ↓
 得到结果

⚠️ 关键注意事项

  1. Engine 与硬件/驱动/TensorRT 版本绑定

    • 在 A100 上生成的 Engine 不能在 Jetson 上用
    • 升级驱动或 TRT 版本后需重新构建
  2. 动态 Shape 支持

    • 需在构建时设置 profile,推理时用 setBindingDimensions
  3. INT8 量化需要校准

    • 额外步骤:提供校准数据集,实现 IInt8Calibrator
  4. 多线程推理

    • 共享 ICudaEngine(线程安全)
    • 每个线程独占 IExecutionContext

✅ 总结

阶段 核心对象 作用
构建 IBuilder, INetworkDefinition, IParser 解析 ONNX,优化图,生成 Engine
推理 IRuntime, ICudaEngine, IExecutionContext 加载 Engine,分配内存,执行计算

🌟 记住:构建一次,推理千次;Engine 是性能的关键!

通过这种方式,TensorRT 能将 ONNX 模型加速数倍甚至数十倍,广泛应用于生产环境。希望这个详解对你有帮助!

相关推荐
taWSw5OjU20 分钟前
从模型评估、梯度难题到科学初始化:一步步解析深度学习的训练问题
人工智能·深度学习
Ricardo-Yang34 分钟前
SCNP语义分割边缘logits策略
数据结构·人工智能·python·深度学习·算法
新缸中之脑42 分钟前
微调BERT进行命名实体识别
人工智能·深度学习·bert
人机与认知实验室1 小时前
神经网络、数学、理性思维真能实现通用智能吗?
人工智能·深度学习·神经网络·机器学习
Gary jie2 小时前
OpenClaw4月更新的梦境记忆巩固系统
人工智能·深度学习·opencv·目标检测·机器学习·长短时记忆网络
大神的风范3 小时前
QT部署YOLO11实时检测
驱动开发·深度学习·qt·目标检测·计算机视觉
清空mega5 小时前
动手学深度学习|批量归一化(Batch Normalization)超详细讲解:为什么它能让深层网络更容易训练?
网络·深度学习·batch
LSQ的测试日记5 小时前
深度学习_YOLO,卡尔曼滤波和
人工智能·深度学习·yolo
bst@微胖子5 小时前
PyTorch深度学习框架之多分类交叉熵实现图像分类
pytorch·深度学习·分类
独隅6 小时前
Keras 的主要特点和适用场景
人工智能·深度学习·keras