- 人工智能
- 计算机视觉
- 深度学习
【免费下载链接】YOLOX
YOLOX is a high-performance anchor-free YOLO, exceeding yolov3~v5 with MegEngine, ONNX, TensorRT, ncnn, and OpenVINO supported. Documentation: https://yolox.readthedocs.io/
本指南基于 YOLOX 仓库中的 OpenVINO C++ 部署文档,系统讲解如何将 YOLOX 模型转换为 OpenVINO 中间表示(IR),并借助仓库自带的 C++ 推理示例在 Intel 平台(CPU/GPU/VPU 等)上完成目标检测。读完本文,你将掌握从下载官方 OpenVINO 模型、配置 OpenVINO 环境、以 opset 10 导出 ONNX 并转为 IR 的完整链路,同时能读懂 yolox_openvino.cpp 中预处理、解码、NMS 与坐标还原的每一行实现,具备将 demo 迁移到自定义数据集或嵌入自身 C++ 项目的能力。
一、仓库中的 OpenVINO C++ Demo 一览
YOLOX 的 OpenVINO 部署示例位于demo/OpenVINO目录,其中:
- cpp/yolox_openvino.cpp:完整的 C++ 推理程序,基于 OpenVINO 2021 版 Inference Engine API 编写,输入模型(IR 或 ONNX)、图片与设备名,输出带检测框的
_demo.jpg; - cpp/CMakeLists.txt:CMake 构建脚本,依赖 OpenCV、InferenceEngine 与 ngraph 三个库;
- README.md:本指南对应的官方部署文档,涵盖模型下载、环境配置、模型转换、构建与运行四步;
- python/openvino_inference.py:功能等价的 Python 版推理脚本,可作为 C++ 结果的对照验证。
整个部署链路为:PyTorch 权重 → ONNX(opset 10)→ OpenVINO IR(.xml + .bin)→ C++ 推理。其中 ONNX 导出依赖 ONNXRuntime 部署文档 与 tools/export_onnx.py 脚本,本文会在转换章节一并讲透。
二、下载官方 OpenVINO 模型与规格对照
官方已为 YOLOX 全系列模型提供转换好的 OpenVINO 模型压缩包,格式为yolox_<model>_openvino.tar.gz,随 YOLOX v0.1.1rc0 版本发布。压缩包内即 demo 所需的 IR 文件(.xml拓扑描述与.bin权重),解压后可直接传给 C++ demo 的<XML_MODEL_PATH>参数。
各模型规格如下表(模型名链接到仓库中对应的实验配置,mAP 为 COCO 验证集指标):
| 模型 | 参数量 | GFLOPs | 测试尺寸 | mAP | 权重包 |
|---|---|---|---|---|---|
| YOLOX-Nano | 0.91M | 1.08 | 416x416 | 25.8 | yolox_nano_openvino.tar.gz |
| YOLOX-Tiny | 5.06M | 6.45 | 416x416 | 32.8 | yolox_tiny_openvino.tar.gz |
| YOLOX-S | 9.0M | 26.8 | 640x640 | 40.5 | yolox_s_openvino.tar.gz |
| YOLOX-M | 25.3M | 73.8 | 640x640 | 47.2 | yolox_m_openvino.tar.gz |
| YOLOX-L | 54.2M | 155.6 | 640x640 | 50.1 | yolox_l_openvino.tar.gz |
| YOLOX-Darknet53 | 63.72M | 185.3 | 640x640 | 48.0 | yolox_dark_openvino.tar.gz |
| YOLOX-X | 99.1M | 281.9 | 640x640 | 51.5 | yolox_x_openvino.tar.gz |
选择要点:
- 追求极速与低算力平台(如嵌入式/边缘设备)选择YOLOX-Nano / YOLOX-Tiny,其测试尺寸为 416x416,与 demo 源码中默认的
INPUT_W = INPUT_H = 416(见 yolox_openvino.cpp)完全一致; - 追求精度则选YOLOX-L / YOLOX-X(640x640,mAP 50+);
- YOLOX-Darknet53对应实验配置 exps/default/yolov3.py,即 Darknet53 骨干版 YOLOX。
若模型测试尺寸不是 416x416,则必须在转换阶段指定对应的--input_shape,并同步修改 C++ 源码中的输入宽高常量,详见下文第四节。
三、安装 OpenVINO Toolkit 并配置环境
官方文档要求安装 OpenVINO 2021 版本工具包(安装方式请以 OpenVINO 官方安装指南为准,仓库文档原文指向其官网 get_started 页面)。安装完成后,关键路径为/opt/intel/openvino_2021,其下包含setupvars.sh环境脚本与 Model Optimizer 转换工具。
3.1 临时配置环境(每次开新终端都要执行)
source /opt/intel/openvino_2021/bin/setupvars.sh该命令会把 OpenVINO 的动态库、Model Optimizer 等工具路径注入当前 shell。由于只对当前会话生效,每次新建终端窗口后都必须重新执行。
3.2 永久配置环境(推荐)
Step1.编辑 shell 配置文件:
vim ~/.bashrcStep2.在文件末尾追加一行:
source /opt/intel/openvino_2021/bin/setupvars.shStep3.保存退出后使其立即生效:
source ~/.bashrc配置完成后,setupvars.sh会在每个交互式终端启动时自动执行,后续构建与运行 demo 前无需再手动 source。
四、模型转换:PyTorch → ONNX → OpenVINO IR
OpenVINO 不直接消费 PyTorch 权重,需要先导出 ONNX,再用 Model Optimizer(mo.py)转为 OpenVINO IR。
4.1 第一步:导出 ONNX(opset 必须为 10)
关键前提:官方文档明确强调,若后续要转换为 OpenVINO,导出 ONNX 时必须指定--opset 10,否则下一步 Model Optimizer 转换会失败。而 tools/export_onnx.py 中 opset 的默认值是 11,因此必须显式传参。
以 YOLOX-Tiny 为例:
cd <YOLOX_HOME> python3 tools/export_onnx.py --output-name yolox_tiny.onnx -n yolox-tiny -c yolox_tiny.pth -o 10脚本核心参数(源自 tools/export_onnx.py 的参数定义):
--output-name:导出 ONNX 文件名,默认yolox.onnx;-n, --name:指定预置模型名,可取yolox-nano / yolox-tiny / yolox-s / yolox-m / yolox-l / yolox-x / yolov3;-f, --exp_file:指定自定义实验配置文件(.py)路径,与-n二选一;-c, --ckpt:训练得到的权重文件路径;-o, --opset:ONNX opset 版本,默认 11,转 OpenVINO 时必须设为 10;--no-onnxsim:禁用 onnx-simplifier 简化,默认会启用简化并校验;--dynamic:是否导出动态 batch 输入;--input/--output:输入/输出节点名,默认分别为images/output;--decode_in_inference:是否在导出模型内部完成解码。
以-f指定实验文件的方式(等价写法):
python3 tools/export_onnx.py --output-name yolox_tiny.onnx -f exps/default/yolox_tiny.py -c yolox_tiny.pth -o 10自定义模型则用:
python3 tools/export_onnx.py --output-name your_yolox.onnx -f exps/your_dir/your_yolox.py -c your_yolox.pth -o 10关于输入尺寸:脚本使用torch.randn(batch_size, 3, exp.test_size[0], exp.test_size[1])构造 dummy input(见 tools/export_onnx.py),即 ONNX 的输入形状由实验配置的test_size决定。例如 exps/default/yolox_tiny.py 中test_size = (416, 416),而 exps/default/yolox_s.py 未显式覆盖test_size,继承默认的 640x640。若想自定义导出尺寸,需在实验配置中调整test_size(或按官方 ONNX 文档方式修改 dummy input 构造),并确保与 C++ demo 的INPUT_W/INPUT_H一致。
4.2 第二步:安装 Model Optimizer 的 ONNX 转换依赖
进入 Model Optimizer 目录并安装 ONNX 转换所需的 Python 依赖:
cd <INSTALL_DIR>/openvino_2021/deployment_tools/model_optimizer sudo ./install_prerequisites/install_prerequisites_onnx.sh4.3 第三步:ONNX → OpenVINO IR
仍在 Model Optimizer 目录下执行:
python3 mo.py --input_model <ONNX_MODEL> --input_shape <INPUT_SHAPE> [--data_type FP16]参数说明:
--input_model:上一步导出的 ONNX 文件;--input_shape:必须与 ONNX 导出时的输入形状一致,格式如[1,3,416,416];--data_type FP16:可选,将权重压缩为 FP16,可减小模型体积并提升部分设备上的推理速度。
官方示例(YOLOX-Tiny,416 输入):
python3 mo.py --input_model yolox_tiny.onnx --input_shape [1,3,416,416] --data_type FP16一致性检查:转换时指定的--input_shape必须与 C++ 源码中定义的输入宽高常量保持一致,即 yolox_openvino.cpp 中的INPUT_W = 416与INPUT_H = 416;否则推理时输入 Blob 尺寸不匹配,会直接报错。
转换成功后,工作目录会生成同名的.xml与.bin文件,二者共同构成 OpenVINO IR,后续传给 demo 的是.xml路径。
五、C++ 推理源码深度解析
理解了模型来源后,我们来逐段拆解 yolox_openvino.cpp 的完整推理流程。该程序严格遵循 OpenVINO 2021 推理样板的标准八步,同时内嵌了 YOLOX 特有的解码与后处理逻辑,可直接作为移植到其他推理框架的参考。
5.1 命令行参数与关键常量
main函数首先校验参数个数(yolox_openvino.cpp):
if (argc != 4) { tcout << "Usage : " << argv[0] << " <path_to_model> <path_to_image> <device_name>" << std::endl; return EXIT_FAILURE; }即运行格式为./yolox_openvino <XML_MODEL_PATH> <IMAGE_PATH> <DEVICE>。
文件顶部定义了几个影响检测行为的关键常量(yolox_openvino.cpp):
| 常量 | 默认值 | 含义 |
|---|---|---|
NMS_THRESH | 0.45 | NMS 的 IoU 阈值 |
BBOX_CONF_THRESH | 0.3 | 候选框置信度阈值 |
INPUT_W/INPUT_H | 416 / 416 | 网络输入尺寸 |
NUM_CLASSES | 80 | COCO 类别数,自定义数据集需修改 |
5.2 推理主流程(OpenVINO 标准八步)
主流程代码(yolox_openvino.cpp)依次为:
- 初始化 Inference Engine Core:
Core ie;(2021 版新 API,替代旧版InferencePlugin); - 读取模型:
ie.ReadNetwork(input_model)可同时读取 IR(.xml)或 ONNX(.onnx);随后校验拓扑必须为单输入单输出,否则抛出异常; - 配置输入输出:获取输入输出节点名,并将输出精度强制设为
FP32(output_info->setPrecision(Precision::FP32)),保证解码时按 float 解释数据; - 加载模型到设备:
ie.LoadNetwork(network, device_name),device_name即运行参数<DEVICE>,常见取值CPU、GPU、MYRIAD(Intel Movidius VPU)、HDDL、HETERO等,与 python/openvino_inference.py 中-d参数支持的设备列表一致; - 创建推理请求:
infer_request = executable_network.CreateInferRequest(); - 准备输入:读图、letterbox 缩放、写入输入 Blob(见 5.3);
- 执行推理:
infer_request.Infer()(同步推理); - 处理输出:读取输出 Blob,经解码 + NMS + 坐标还原后绘制保存(见 5.4~5.6)。
5.3 预处理:letterbox 等比缩放 + 灰度填充
static_resize(yolox_openvino.cpp)实现标准 YOLOX letterbox:
float r = std::min(INPUT_W / (img.cols*1.0), INPUT_H / (img.rows*1.0)); int unpad_w = r * img.cols; int unpad_h = r * img.rows; cv::resize(img, re, re.size()); cv::Mat out(INPUT_H, INPUT_W, CV_8UC3, cv::Scalar(114, 114, 114)); // 114 灰度填充 re.copyTo(out(cv::Rect(0, 0, re.cols, re.rows)));即按比例缩放图片至 416x416 内,多余区域用 RGB(114,114,114) 填充(与训练时数据增强的填充值一致),避免直接拉伸导致的形变。
blobFromImage(yolox_openvino.cpp)将cv::Mat的 HWC 数据按 NCHW 顺序写入内存 Blob,注意这里只做类型转换(uint8 → float),不做 /255 归一化——因为导出 ONNX 时模型内部已包含归一化层。
5.4 解码:无锚框输出解析
YOLOX 是无锚框(anchor-free)检测器,输出为各 stride 特征图网格上的原始预测,需配合网格坐标解码为边界框。源码实现分两步:
generate_grids_and_stride(yolox_openvino.cpp):按strides = {8, 16, 32}(对应 PAFPN 三个检测层)枚举每个网格坐标(grid0, grid1)与对应 stride;generate_yolox_proposals(yolox_openvino.cpp):逐网格解码,代码注释明确标注了与 yolox/models/yolo_head.py 中 decode 逻辑的一致性:
// outputs[..., :2] = (outputs[..., :2] + grids) * strides // outputs[..., 2:4] = torch.exp(outputs[..., 2:4]) * strides float x_center = (feat_ptr[basic_pos + 0] + grid0) * stride; float y_center = (feat_ptr[basic_pos + 1] + grid1) * stride; float w = exp(feat_ptr[basic_pos + 2]) * stride; float h = exp(feat_ptr[basic_pos + 3]) * stride;随后计算目标置信度与类别分数的乘积box_prob = box_objectness * box_cls_score,仅保留大于BBOX_CONF_THRESH(0.3)的候选框。
5.5 NMS:按置信度降序排序 + IoU 抑制
qsort_descent_inplace(yolox_openvino.cpp):快速排序将候选框按置信度降序排列,递归分支用 OpenMP#pragma omp parallel sections并行化;nms_sorted_bboxes(yolox_openvino.cpp):按序贪婪选择,若与已保留框的 IoU 大于NMS_THRESH(0.45)则剔除,实现标准单类别 NMS(遍历所有类别,等价于将 80 类视为一个大类做一次 NMS)。
5.6 坐标还原、裁剪与可视化
decode_outputs(yolox_openvino.cpp)在 NMS 之后把框坐标从 416x416 空间还原到原始图像空间:
float x0 = (objects[i].rect.x) / scale; // scale 为预处理时的缩放比 ... x0 = std::max(std::min(x0, (float)(img_w - 1)), 0.f); // 裁剪到图像边界draw_objects(yolox_openvino.cpp)完成:
- 对每个检测框按类别取固定调色板颜色绘制矩形与标签文本(
class_names数组为完整 COCO 80 类列表); - 在 stderr 打印结构化结果:
label = prob at x y w h; - 将结果图保存为当前目录下的
_demo.jpg。
六、CMake 构建详解
CMakeLists.txt 内容非常精简,依赖三个通过find_package查找的库:
cmake_minimum_required(VERSION 3.4.1) set(CMAKE_CXX_STANDARD 14) project(yolox_openvino_demo) find_package(OpenCV REQUIRED) find_package(InferenceEngine REQUIRED) find_package(ngraph REQUIRED) ... add_executable(yolox_openvino yolox_openvino.cpp) target_link_libraries(yolox_openvino ${InferenceEngine_LIBRARIES} ${NGRAPH_LIBRARIES} ${OpenCV_LIBS})要点:
- 要求 C++14 标准与 CMake 3.4.1+;
InferenceEngine与ngraph两个包的查找路径正是由第三节setupvars.sh注入的,必须先 source 环境脚本再执行 cmake,否则会因找不到包而配置失败;- 需要系统已安装 OpenCV(
cv::imread / cv::resize / cv::rectangle等均来自 OpenCV)。
Linux 下完整构建步骤:
source /opt/intel/openvino_2021/bin/setupvars.sh mkdir build cd build cmake .. make构建成功后,build目录下生成可执行文件yolox_openvino。
七、运行 Demo 并验证结果
./yolox_openvino <XML_MODEL_PATH> <IMAGE_PATH> <DEVICE>例如(使用转换好的 YOLOX-Tiny IR 与 CPU 设备):
./yolox_openvino yolox_tiny.xml dog.jpg CPU运行说明与验证手段:
- 程序要求恰好 4 个参数(可执行文件名 + 模型 + 图片 + 设备),参数个数不对会打印 Usage 后退出;
- 推理过程中会在 stderr 逐行打印检测结果,格式为
label = prob at x y w h(如16 = 0.93152 at 104.00 170.00 261.00 x 379.00); - 检测结果图保存在当前工作目录的
_demo.jpg,可直接查看;若需 GUI 显示,可取消draw_objects末尾cv::imshow / cv::waitKey的注释; - 设备名可尝试
CPU、GPU(需安装 GPU 插件)或MYRIAD(需接入 Intel NCS2 等 VPU 设备)。
若同时安装了 Python 环境,可用 python/openvino_inference.py 做交叉验证:
python3 openvino_inference.py -m yolox_tiny.xml -i dog.jpg -o demo_output -s 0.3 -d CPUPython 版内部复用 yolox/utils/demo_utils.py 中的demo_postprocess / multiclass_nms / vis等工具函数,与 C++ 版在解码与 NMS 策略上保持等价。
八、常见问题与注意事项
- opset 必须是 10:导出 ONNX 时若使用默认 opset 11(或更高),Model Optimizer 转换会失败,务必加
-o 10; - 输入形状三方一致:
mo.py的--input_shape、ONNX 导出时的test_size、C++ 源码的INPUT_W/INPUT_H必须统一。换用 640x640 模型(如 YOLOX-S)时,请同步修改 yolox_openvino.cpp 中的常量并重新编译; - 单输入单输出限制:demo 只支持单输入单输出拓扑,若自定义模型导出后输入输出节点异常(例如开启了多输出解码),需调整导出配置;
- 自定义数据集:修改
NUM_CLASSES为实际类别数,并同步替换class_names数组与color_list长度(yolox_openvino.cpp); - FP16 模型:使用
--data_type FP16转换可缩小体积,代码中已强制输出精度为 FP32 供解码使用,不受影响; - 每次构建前 source 环境:新终端必须先执行
source /opt/intel/openvino_2021/bin/setupvars.sh(或配置进~/.bashrc),否则 CMake 无法找到 InferenceEngine/ngraph。
至此,从官方权重、ONNX 导出、IR 转换到 C++ 推理的完整 YOLOX OpenVINO 部署链路已全部打通,你可以基于 yolox_openvino.cpp 快速集成到自己的边缘端或服务端 C++ 推理工程中。
- 人工智能
- 计算机视觉
- 深度学习
【免费下载链接】YOLOX
YOLOX is a high-performance anchor-free YOLO, exceeding yolov3~v5 with MegEngine, ONNX, TensorRT, ncnn, and OpenVINO supported. Documentation: https://yolox.readthedocs.io/
相关推荐
YOLOX 基于 OpenVINO 的部署实战:模型转换、Python 与 C++ 推理全流程指南
YOLOX 基于 OpenVINO 的部署实战:模型转换、Python 与 C++ 推理全流程指南 YOLOX 是一款高性能的 anchor free 检测框架
人工智能计算机视觉深度学习YOLOX ncnn部署实战:C++推理与模型转换全链路解析
YOLOX ncnn部署实战:C++推理与模型转换全链路解析 YOLOX 是旷视开源的高性能无锚点(anchor free)目标检测模型,性能超过 YOLOv3
人工智能计算机视觉深度学习CAMEL 开源贡献指南:环境搭建、测试与文档流水线、代码审查与编码规范全解
CAMEL 开源贡献指南:环境搭建、测试与文档流水线、代码审查与编码规范全解 本篇技术文章基于 CAMEL 仓库根目录的 CONTRIBUTING.md htt
人工智能计算机视觉深度学习
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考