共计 1623 个字符,预计需要花费 5 分钟才能阅读完成。
背景痛点
最近在项目中使用 ONNX Runtime 部署 YOLOv5 模型时,发现推理速度远低于预期。经过分析,主要存在以下性能瓶颈:

- CPU 利用率不足 50%,多核优势未发挥
- 前后处理(图像缩放、NMS)占整体耗时 40%
- 频繁的内存拷贝操作(Host-Device 之间)
- 默认使用 FP32 精度,计算资源浪费
这些痛点在实际边缘设备上更为明显,严重影响实时性要求。
技术方案对比
针对上述问题,我们测试了三种主流优化方案:
- 多线程并行处理
- 通过 SessionOptions 配置并发推理
-
适合批处理场景,吞吐量提升显著
-
模型量化
- FP16 量化:几乎无损,ARM 设备加速明显
-
INT8 量化:需要校准集,速度提升 2 - 4 倍
-
自定义算子优化
- 替换 ONNX 原生不高效的算子(如 Slice)
- 需要重新编译 ONNX Runtime
核心实现
多线程环境配置
Ort::SessionOptions session_options;
session_options.SetIntraOpNumThreads(4); // 算子内并行
session_options.SetInterOpNumThreads(2); // 算子间并行
session_options.SetExecutionMode(ExecutionMode::ORT_PARALLEL);
// 启用内存复用(减少 alloc/free 开销)Ort::MemoryInfo memory_info = Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtArenaAllocator, OrtMemType::OrtMemTypeDefault);
线程池实现
class InferencePool {
public:
InferencePool(int workers, const std::string& model_path) {for (int i = 0; i < workers; ++i) {sessions_.emplace_back(env_, model_path.c_str(), session_options);
}
}
void Run(const cv::Mat& frame) {auto& session = sessions_[next_idx_++ % sessions_.size()];
// ... 推理逻辑
}
private:
std::vector<Ort::Session> sessions_;
size_t next_idx_ = 0;
};
模型量化步骤
-
使用官方工具进行 FP16 转换:
python -m onnxruntime.tools.convert_onnx_models_to_ort \ --input_model yolov5s.onnx \ --output_directory ./optimized \ --float16 -
INT8 量化需要准备校准数据集(约 500 张样本)
性能测试
| 优化方案 | FPS (x86) | CPU 利用率 | 内存占用 |
|---|---|---|---|
| 基线(FP32) | 22 | 48% | 1.2GB |
| FP16 量化 | 35 | 65% | 800MB |
| INT8+ 多线程 | 68 | 95% | 600MB |
在树莓派 4B 上,INT8 量化方案可实现 10+FPS 的实时推理。
避坑指南
- 内存泄漏 :注意释放
Ort::Value对象 - 线程安全:每个线程使用独立的 Session 实例
- 量化精度:建议保留一个 FP32 版本用于效果对比
- 预处理优化:使用 OpenCV 的 UMat 减少拷贝
总结与延伸
经过优化,我们的 YOLOv5s 模型在 i7-11800H 上达到 68FPS,关键优化点包括:
- 使用 INT8 量化 + 多线程并行
- 预处理改用 GPU 加速(OpenCL)
- 自定义 NMS 算子(比原版快 3 倍)
完整 checklist:
– [] 验证量化后 mAP 下降不超过 2%
– [] 测试不同线程数配置(推荐 CPU 核数的 70%)
– [] 使用 perf 工具分析热点函数
对于追求极致性能的场景,可以尝试:
– 切换到 TensorRT(需转换模型格式)
– 使用 OpenVINO 优化 Intel 平台
– 尝试 MNN/TNN 等轻量推理引擎
正文完
