使用 LibTorch 在 C++ 中部署运行 Ultralytics YOLO:零配置多任务推理实战指南
本指南以 examples/cpp/LibTorch 示例为线索,讲解如何用 PyTorch 官方 C++ API(LibTorch)与 OpenCV 编写一个支持 YOLOv8 / YOLO11 / YOLO26 全部任务(目标检测、实例分割、姿态估计、旋转框 OBB、图像分类与语义分割)的本地推理程序。读完本文你将掌握 TorchScript 模型的导出、CMake 工程搭建、基于模型元数据的"零配置"加载,以及从张量输出到可视化结果的完整 C++ 实现链路。
示例概览:它解决了什么问题
Ultralytics YOLO 的推理通常以 Python 调用为主,但生产级边缘设备与桌面应用常常需要把模型嵌入 C++ 程序。仓库在 examples/cpp/LibTorch 下提供了一套完整的 C++ 应用:它把任意已导出的 .torchscript 模型作为输入,自动从模型自身携带的元数据读取任务类型、类别名与输入尺寸,并自动选择对应的后处理逻辑,无需任何手工配置。
该示例目录结构如下:
- main.cc:命令行入口,负责解析参数、读图、调用推理与输出结果;
- inference.h 与 inference.cc:核心
Predictor类,封装模型加载、元数据解析与前向推理; - CMakeLists.txt:基于 CMake 的构建脚本;
- examples/cpp/common:所有 C++ 示例共享的纯头文件工具集,包括统一结果类型、CLI 参数解析、前后处理与画图逻辑(本示例通过 include 路径自动引入)。
核心特性
- 覆盖全部任务:detect(目标检测)、segment(实例分割)、pose(姿态估计)、OBB(旋转框)、classify(图像分类),以及 YOLO26 的 semantic(语义分割),对应文档见 docs/en/tasks/detect.md、segment.md、pose.md、obb.md、classify.md 与 semantic.md。
- 覆盖全部模型代际:Ultralytics YOLOv8、YOLO11 与 YOLO26(对应 docs/en/models/yolov8.md、yolo11.md、yolo26.md),并且能自动识别传统 grid 输出(YOLOv8/11)与 YOLO26 的 end-to-end(端到端)输出布局,无需手工指定。
- 零配置:任务类型、类别名与
imgsz(推理输入尺寸)全部来自 Ultralytics 导出时内嵌进 TorchScript 的config.txt元数据。
依赖要求
| 依赖 | 最低版本 | 说明 |
|---|---|---|
| OpenCV | >= 4.0.0 | 图像读写、预处理、后处理(NMS)与标注绘制 |
| C++ 标准 | >= 17 | CMake 中以 CMAKE_CXX_STANDARD 17 强制启用 |
| CMake | >= 3.18 | 构建系统,与示例中 cmake_minimum_required 一致 |
| LibTorch | >= 1.12.1 | PyTorch 的 C++ 发行版,提供 torch::jit 推理 API |
LibTorch 需要从 PyTorch 官网按操作系统与 CUDA 版本选择下载。若使用 GPU 推理,下载的 LibTorch 必须与你的 CUDA 环境匹配,否则 --cuda 无法生效。
第一步:把模型导出为 TorchScript
TorchScript 是 PyTorch 的序列化模型格式,可脱离 Python 环境由 LibTorch 直接加载。使用 Ultralytics 的 export 模式即可导出任意任务、任意代际的模型:
yolo export model=yolo26n.pt imgsz=640 format=torchscript # detect 检测
yolo export model=yolo26n-seg.pt imgsz=640 format=torchscript # 实例分割
yolo export model=yolo26n-pose.pt imgsz=640 format=torchscript # 姿态估计
yolo export model=yolo26n-obb.pt imgsz=640 format=torchscript # 旋转框 OBB
yolo export model=yolo26n-cls.pt imgsz=640 format=torchscript # 图像分类
yolo export model=yolo26n-sem.pt imgsz=640 format=torchscript # 语义分割(YOLO26)
更完整的导出参数说明可参阅 docs/en/modes/export.md。YOLOv8 / YOLO11 的 grid 模型同样适用,其输出布局会在运行时被自动识别。
导出时内嵌的 config.txt 元数据
这一"零配置"能力的源头在导出实现中:仓库的 ultralytics/utils/export/torchscript.py 会先把元数据字典序列化为 JSON,再作为额外文件 config.txt 随模型一起保存:
extra_files = {"config.txt": json.dumps(metadata or {})} # torch._C.ExtraFilesMap()
ts.save(output_file, _extra_files=extra_files)
这份元数据由 ultralytics/engine/exporter.py 在导出时构造,包含 task、names(类别字典)、imgsz、stride、end2end(是否为端到端输出)等关键字段。推理端只需把同一份 JSON 原样取出即可实现"拿到什么模型就按它的配置跑"。
第二步:编译构建
仓库中提供了完整的 CMakeLists.txt。构建步骤如下:
git clone https://github.com/ultralytics/ultralytics.git
cd ultralytics/examples/cpp/LibTorch
mkdir build && cd build
# 若 OpenCV / LibTorch 未被自动探测到,追加下面的路径参数:
# -DCMAKE_PREFIX_PATH="/path/to/libtorch;/path/to/opencv"
cmake .. && cmake --build . --config Release
构建脚本的要点(对应 examples/cpp/LibTorch/CMakeLists.txt):
- 分别通过
find_package(OpenCV REQUIRED)与find_package(Torch REQUIRED)定位依赖,并把Torch_DIR/OpenCV_DIR作为可覆写的查找提示; set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TORCH_CXX_FLAGS}")追加 LibTorch 要求的编译选项;- 以
main.cc+inference.cc两个翻译单元生成可执行文件yolo_libtorch; - 共享工具自动引入:通过
target_include_directories(... ../common)把 examples/cpp/common 加入 include 路径,因此同目录下的main.cc可以直接#include "yolo_render.hpp"、#include "yolo_cli.hpp"; - Windows(MSVC)场景下脚本预留了一段把 Torch DLL 复制到输出目录的逻辑(参照 PyTorch 的 #25457 讨论,防止内存错误),默认处于注释状态,可按需启用。
共享头文件里的"全家桶"
examples/cpp/common 目录下各头文件职责如下:
- yolo_types.hpp:
Task枚举与统一的单目标结果结构Result(包含class_id、confidence、box、OBB 的angle、Pose 的keypoints/keypoint_scores、Segment 的mask); - yolo_cli.hpp:
ArgValue/HasFlag等极简命令行解析工具; - yolo_postprocess.hpp:预处理与全任务后处理函数,纯函数式、不依赖具体推理后端,可在 ONNX Runtime、OpenVINO 等示例间复用;
- yolo_render.hpp / yolo_draw.hpp / yolo_show.hpp:结果标注绘制、控制台打印与窗口显示。
第三步:运行推理
编译产物 yolo_libtorch 的用法如下。若 LibTorch 未安装到系统库路径,需先导出动态库路径:
# 将 LibTorch 的库目录加入动态链接器搜索路径
export LD_LIBRARY_PATH=/path/to/libtorch/lib:$LD_LIBRARY_PATH
# 默认参数:--model yolo26n.torchscript --source bus.jpg --conf 0.25 --iou 0.45 --out result.jpg
./yolo_libtorch --model yolo26n.torchscript --source bus.jpg
./yolo_libtorch --model yolo26n-seg.torchscript --source bus.jpg --out seg.jpg
./yolo_libtorch --model yolo26n-pose.torchscript --source bus.jpg --show
命令行参数
| 参数 | 默认值 | 说明 |
|---|---|---|
--model |
yolo26n.torchscript |
已导出的 TorchScript 模型路径(支持任意任务) |
--source |
bus.jpg |
输入图片路径 |
--conf |
0.25 |
置信度阈值 |
--iou |
0.45 |
NMS IoU 阈值(仅对 grid 输出模型生效,端到端输出已内置 NMS) |
--out |
result.jpg |
结果图片输出路径 |
--cuda |
关闭 | 若 LibTorch 构建与硬件支持则使用 CUDA 推理 |
--show |
关闭 | 额外弹出一个显示窗口 |
这些默认值直接定义在 inference.h 的 Config 结构与 main.cc 的参数解析中,可对照查看。
预期输出行为:标注结果始终写入 --out 指定的文件;每个检测框的关键信息会打印到控制台。程序启动时会打印模型信息,例如:
Model: yolo26n.torchscript | task: detect | classes: 80
task 与 classes 数量来自模型元数据而非硬编码——这正是"点哪跑哪"的体现。
源码剖析:Predictor 如何做到"零配置"
入口 main.cc 的流程很直白:解析命令行 → cv::imread 读图 → 构造 yolo::Predictor → 打印任务信息 → predict() 推理 → 渲染并保存。真正的玄机在 Predictor 中。
模型加载与元数据解析
构造函数位于 inference.cc,执行三步关键操作:
- 设备选择:仅当
config.cuda == true且torch::cuda::is_available()时才把设备切到 CUDA; - 带附加文件加载模型:以
extra_files["config.txt"] = ""为占位调用torch::jit::load,让加载器把导出时写入的config.txt回填进来; - 解析元数据:load_metadata 用正则从 JSON 字符串中提取
task与imgsz(取首元素),并同时兼容 Python dict(0: 'person')与 JSON("0": "person")两种类别键值风格构建names_列表;解析不到类别时回退到内置的 COCO 80 类列表(见 coco_names.hpp)。
前向推理与输出分发
predict()(inference.cc)是整个示例的主干:
- 调用共享头文件中的
Preprocess/ToBlob完成letterbox 填充(检测类任务)或中心裁剪(分类任务)、BGR→RGB 转换与 HWC→CHW 归一化,得到[1, 3, imgsz, imgsz]的 float 张量(见 yolo_postprocess.hpp); - 在
torch::NoGradGuard下通过module_.forward({input_tensor})执行前向; - 统一收集输出:由于不同任务的 TorchScript 输出类型不同(单个 Tensor、Tuple 或 TensorList),代码对三种情况分别取张量,segment 特有的 4D proto 张量与主输出(2D/3D)一并收集——4D 张量记为辅助输出
aux_idx,其余记为main_idx; - 依据解析出的
Task枚举分发到不同后处理函数;semantic 任务把逐像素类别图写入semantic输出参数并返回空结果列表,其余任务返回Result列表。
grid 与 end-to-end 输出的自动判别
后处理共享函数通过维度比较区分输出布局:以 [1, dim1, dim2] 为例,若 dim1 > dim2(如 [1, 300, 6])即端到端输出,是已经过内置 NMS 的定长候选集,只需按置信度阈值过滤并按 x1,y1,x2,y2,conf,cls 布局解析;否则按 YOLOv8/11 经典的 [1, 4+nc, 8400] 通道主序 grid 处理。该逻辑实现在 yolo_postprocess.hpp 中,pose / OBB 同理。
各任务后处理要点(源码级)
- Detect:grid 分支对每条锚点做类别 argmax、
cv::dnn::NMSBoxesBatched做类内抑制;end2end 分支直接读取已排序的候选行。 - Pose:keypoint 坐标为原图坐标并附逐点置信度,grid 分支以
dim1 = 5 + nkpt*3推算关键点数(yolo_postprocess.hpp)。 - OBB:每行末尾携带旋转角
angle,先以轴对齐矩形为代理做 NMS,绘制时再还原为cv::RotatedRect(yolo_postprocess.hpp)。 - Segment:利用检测头输出与 4D proto 张量做矩阵乘法,经 sigmoid、双线性放大、按 0.5 阈值二值化并裁到目标框范围,产出原图尺寸的 8-bit 掩膜(yolo_postprocess.hpp)。
- Semantic:对每个像素在所有类别通道上 argmax,得到逐像素类别图后做最近邻放大回原图尺寸(yolo_postprocess.hpp)。
- Classify:取置信度最高的 top-5 类别输出(yolo_postprocess.hpp)。
结果渲染
main.cc 调用 yolo_render.hpp 中的 RenderAndPrint:检测/分割/姿态任务逐目标绘制边框、掩膜、骨架与 名称 置信度 标签并打印控制台;OBB 额外输出角度;分类在左上角列出 Top-5;语义分割则把类别图直接覆盖到画布。最终 cv::imwrite 写出到 --out,--show 开启时再弹出窗口。
注意事项与边界条件
--iou仅对 grid 模型生效:YOLO26 端到端输出的 NMS 在导出阶段已融合进图内,运行期的 IoU 阈值不会影响其候选筛选;- 分类模型走中心裁剪而非 letterbox:
Preprocess依据task == Classify选择不同的缩放策略,这与 Python 侧训练/推理语义保持一致; - COCO 之外的类别:若模型类别超过内置 COCO 表(如 ImageNet 1000 类),会优先使用
config.txt中解析出的names_,完全缺失时才回退到内置列表并以数字 ID 兜底(见 yolo_cli.hpp 的NameOf); - CUDA 生效条件:
--cuda只是开关,真正起效还需要 LibTorch 为 CUDA 构建且当前设备可用,二者缺一不可; - Windows 用户:请按 CMakeLists 中的注释启用 Torch DLL 复制逻辑,否则可能遇到 DLL 加载导致的内存错误;
- 运行环境:示例默认读入名为
bus.jpg的本地图片并输出result.jpg,请确保输入文件存在于当前工作目录或改用--source指定绝对路径。
延伸阅读
如果你想了解其他推理后端的 C++ 用法(同一套前后处理逻辑可平移复用),可参考 examples/cpp/ONNXRuntime、examples/cpp/OpenVINO 等示例;各示例共用 examples/cpp/common 中的头文件。任务与模型的完整知识可继续阅读 docs/en/tasks/index.md 与 docs/en/models/index.md。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0631
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00