C++ 集成
本章面向在自有 C++ 工程内集成 ONNXRuntime-MUSA-M1000 的场景,适用于模型需在本地推理、不便外发的情况。
发布通道同时提供预编译的 C++ 运行库(include/ + lib/),通过 CMake FetchContent 链接。接口与 ONNX Runtime 上游 release 兼容,差异仅在于新增 MUSAExecutionProvider。
开始前请先完成环境准备与部署。该章的驱动、MUSA SDK 与 LD_LIBRARY_PATH 要求对 C++ 路线同样适用。Python 路线见安装与验证。
运行库有两种取用方式:本章 Step1 起为工程内引入(下载 tarball,由工程自己管理路径与版本);设备批量部署可改用 deb 安装包安装到系统目录,见方式二。
运行库
| 项目 | 值 |
|---|---|
| 文件名 | onnxruntime-linux-aarch64-1.23.0-release.tgz |
| 下载地址 | https://mt-vaas-web.tos-cn-beijing.volces.com/release/ort_musa/OrtMusaV0.27.7_M1000/M1000-SDK5.1.0/onnxruntime-linux-aarch64-1.23.0-release.tgz |
| SHA256 | 7e18c1875127d520fbe2421d39b63ac5d3035b323ae12e4622e748f557cb1e71 |
| 大小 | 12,433,667 字节 |
解压后的目录结构:
onnxruntime-linux-aarch64/
├── include/
│ ├── onnxruntime_c_api.h
│ ├── onnxruntime_cxx_api.h
│ ├── onnxruntime_cxx_inline.h
│ ├── onnxruntime_float16.h
│ ├── onnxruntime_lite_custom_op.h
│ ├── onnxruntime_run_options_config_keys.h
│ ├── onnxruntime_session_options_config_keys.h
│ ├── provider_options.h
│ ├── musa_provider_options.h
│ └── core/providers/{resource.h, custom_op_context.h}
└── lib/
├── libonnxruntime.so → libonnxruntime.so.1 → libonnxruntime.so.1.23.0
├── libonnxruntime_providers_musa.so
├── libonnxruntime_providers_shared.so
├── cmake/onnxruntime/*.cmake
└── pkgconfig/libonnxruntime.pc
libonnxruntime_providers_musa.so 是 MUSA Execution Provider,在创建 session 时才被动态加载。
C++ 运行时的 Ort::GetVersionString() 只返回 1.23.0,不含版本标识后缀。
C++ 路线无法从二进制自证引擎版本。版本以下载地址中的路径段 OrtMusaV0.27.7_M1000/M1000-SDK5.1.0 与同目录 SHA256SUMS 内的 wheel 文件名为准。
Step1 编译工具链
| 用途 | 最低 cmake 版本 |
|---|---|
| 接入自有工程(本章 Step3 起) | 3.22,Ubuntu 22.04 的 apt install cmake 提供 3.22.1,满足要求 |
| 运行 Step2 的示例包 | 3.23,示例包 CMakeLists.txt 首行有此声明 |
另需 gcc ≥ 9.4(支持 C++17),Ubuntu 22.04 自带的 11.4.0 满足要求。
用低于 3.23 的 cmake 配置示例包会直接失败:
CMake Error at CMakeLists.txt:1 (cmake_minimum_required):
CMake 3.23 or higher is required. You are running version 3.22.6
安装 cmake ≥ 3.23 使用官方 aarch64 预编译包,解压即用,不需要 root 权限:
curl -fsSLO https://cmake.org/files/v3.31/cmake-3.31.6-linux-aarch64.tar.gz
echo "b4cc788d63112b2749b40627e719eb5d3b8ed8f00c36d77189f4019cfe64bc9e cmake-3.31.6-linux-aarch64.tar.gz" | LC_ALL=C sha256sum -c -
tar xzf cmake-3.31.6-linux-aarch64.tar.gz
export PATH="$PWD/cmake-3.31.6-linux-aarch64/bin:$PATH"
cmake --version | head -1
预期输出:
cmake-3.31.6-linux-aarch64.tar.gz: OK
cmake version 3.31.6
注意:export PATH 只对当前 shell 生效,新开终端需重新执行,或写入个人 shell 配置。上述 SHA256 取自官方校验清单 https://cmake.org/files/v3.31/cmake-3.31.6-SHA-256.txt。
Step2 快速验证
示例包包含 CMakeLists、main.cc 与一个通用的 mobilenet_v2 模型,用于在接入自有工程之前先验证链路。需要 cmake ≥ 3.23。
curl -fsSLO https://mt-vaas-web.tos-cn-beijing.volces.com/release/ort_musa/feature-demos/cpp/ort_musa_cpp_demo.tar.gz
echo "aa823ce86013eb60c3447b56d7e7ee33581df5cea4cedfeb47bb084152fd295f ort_musa_cpp_demo.tar.gz" | LC_ALL=C sha256sum -c -
tar xzf ort_musa_cpp_demo.tar.gz && cd ort_musa_cpp_demo
mkdir -p build && cd build
cmake -DORTMUSA_TARBALL_URL=https://mt-vaas-web.tos-cn-beijing.volces.com/release/ort_musa/OrtMusaV0.27.7_M1000/M1000-SDK5.1.0/onnxruntime-linux-aarch64-1.23.0-release.tgz \
-DORTMUSA_TARBALL_HASH=SHA256=7e18c1875127d520fbe2421d39b63ac5d3035b323ae12e4622e748f557cb1e71 ..
make -j4
export LD_LIBRARY_PATH=/usr/local/musa/lib:$LD_LIBRARY_PATH
./ort_musa_cpp_demo ../models/mobilenet_v2_fp16.onnx 0
预期输出:
model = ../models/mobilenet_v2_fp16.onnx
device_id = 0
providers : MUSAExecutionProvider CPUExecutionProvider
output : [1, 1000]
inference : <耗时> ms (mean of 20, after 3 warmup)
PASS: MUSA EP C++ inference completed.
注意:以下三项同时满足即表示链路已跑通——providers 中含 MUSAExecutionProvider;output 为 [1, 1000];末行为 PASS: MUSA EP C++ inference completed.。inference 一行随设备负载波动,仅用于说明输出格式。
两个 -D 参数必须同时给出,且不能省略。
示例包 CMakeLists.txt 内置的默认下载地址指向另一平台(x86_64)的运行库,在 M1000 上不覆盖会下载到 x86_64 包并在链接阶段失败。URL 与 SHA256 成对,只改其一会导致校验失败。
注意:cmake 配置阶段会下载并校验 12.4 MB 的运行库,耗时取决于网络,期间无进度显示。make 只编译一个源文件,为秒级。配置阶段出现的 DOWNLOAD_EXTRACT_TIMESTAMP / CMP0135 警告为 cmake 的开发者提示,不影响构建结果。
注意:示例包 main.cc 中设置了 prefer_nhwc = 1。该开关的适用性见下文性能特性开关。
Step3 接入自有工程
将下列片段加入工程的 CMakeLists.txt,your_target 替换为工程中的可执行或库 target。该片段最低要求 cmake 3.22。
include(FetchContent)
# 使用 CACHE STRING,以便命令行 -D 覆盖(离线编译需要)。普通 set 会覆盖 -D 传入的值。
set(ORTMUSA_TARBALL_URL "https://mt-vaas-web.tos-cn-beijing.volces.com/release/ort_musa/OrtMusaV0.27.7_M1000/M1000-SDK5.1.0/onnxruntime-linux-aarch64-1.23.0-release.tgz"
CACHE STRING "OrtMusa C++ tarball URL")
set(ORTMUSA_TARBALL_HASH "SHA256=7e18c1875127d520fbe2421d39b63ac5d3035b323ae12e4622e748f557cb1e71"
CACHE STRING "OrtMusa C++ tarball hash")
FetchContent_Declare(onnxruntime URL ${ORTMUSA_TARBALL_URL} URL_HASH ${ORTMUSA_TARBALL_HASH})
FetchContent_MakeAvailable(onnxruntime)
find_library(location_onnxruntime onnxruntime
PATHS "${onnxruntime_SOURCE_DIR}/lib" NO_CMAKE_SYSTEM_PATH REQUIRED)
add_library(onnxruntime SHARED IMPORTED)
set_target_properties(onnxruntime PROPERTIES
IMPORTED_LOCATION ${location_onnxruntime}
INTERFACE_INCLUDE_DIRECTORIES "${onnxruntime_SOURCE_DIR}/include")
target_link_libraries(your_target PRIVATE onnxruntime)
# BUILD_RPATH 使 build 目录内可直接运行;INSTALL_RPATH 使安装后仍能定位运行库
set_target_properties(your_target PROPERTIES
BUILD_RPATH "${onnxruntime_SOURCE_DIR}/lib"
INSTALL_RPATH "$ORIGIN/../lib")
安装规则,使 INSTALL_RPATH 的 $ORIGIN/../lib 生效,将引擎运行库与可执行文件一并安装:
install(TARGETS your_target RUNTIME DESTINATION bin)
install(DIRECTORY "${onnxruntime_SOURCE_DIR}/lib/" DESTINATION lib
FILES_MATCHING PATTERN "*.so*")
Step4 验证部署
readelf 显示 RUNPATH、ldd 检查主程序无缺失,都不足以说明部署成功。
MUSA Execution Provider 在创建 session 时才被动态加载,且其自身还有 MUSA SDK 的传递依赖。三项须逐一确认。
cmake --install build --prefix "$PWD/install"
readelf -d install/bin/your_target | grep -E "RPATH|RUNPATH"
export LD_LIBRARY_PATH=/usr/local/musa/lib:$LD_LIBRARY_PATH
ldd install/lib/libonnxruntime_providers_musa.so | grep -E "musart|mudnn|mublas|not found"
预期输出的关键行:
0x000000000000001d (RUNPATH) Library runpath: [$ORIGIN/../lib]
libmusart.so.5 => /usr/local/musa/lib/libmusart.so.5
libmudnn.so.3 => /usr/local/musa/lib/libmudnn.so.3
libmudnn_xmma.so => /usr/local/musa/lib/libmudnn_xmma.so
libmublas.so.1 => /usr/local/musa/lib/libmublas.so.1
注意:判定标准是输出中不出现 not found。除上述四条直接依赖外,ldd 还会列出若干 libmudnn_*.so 子库,均应指向 /usr/local/musa/lib,属正常。这些库由 MUSA SDK 提供,标准安装即包含。
第三项:从任意其他目录(如 cd /tmp)运行一次安装后的程序,确认能够创建 session 并完成推理。
两类库的定位分工:引擎自带库(libonnxruntime.so*、libonnxruntime_providers_musa.so、libonnxruntime_providers_shared.so)由 INSTALL_RPATH 解决;MUSA 运行时(libmusart、libmudnn 等)由 SDK 安装路径提供,需保证 LD_LIBRARY_PATH 包含 /usr/local/musa/lib。
LD_LIBRARY_PATH 由登录环境提供。
通过脚本、cron 或非交互 SSH 执行时不会加载登录环境配置,该变量为空,程序会在创建 session 时抛出异常并中止:
Failed to load library libonnxruntime_providers_musa.so with error:
libmusart.so.5: cannot open shared object file: No such file or directory
这类场景请显式导出 export LD_LIBRARY_PATH=/usr/local/musa/lib:$LD_LIBRARY_PATH。
推理代码
#include <onnxruntime_cxx_api.h>
#include <musa_provider_options.h>
Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "app");
Ort::SessionOptions so;
OrtMUSAProviderOptions musa{}; // 花括号不可省略,见下方说明
musa.device_id = 0; // M1000 为单卡设备,保持 0
so.AppendExecutionProvider_MUSA(musa);
Ort::Session session(env, "your_model.onnx", so);
// 构造输入 CPU tensor → session.Run(...) → 读取输出
完整可运行版本见 Step2 示例包的 main.cc,其中包含从 session 自动查询输入输出名称与形状、构造 tensor、执行与读取输出的全过程。
注意:OrtMUSAProviderOptions musa{}; 的花括号不可省略。省略后各字段为未初始化值,行为不确定;带花括号时按下表的默认值初始化。
输入输出的适配方式(多输入、fp16、动态维度、多输出)与 Python 路线同理,对应的 C++ API 为:
| 情形 | 关键 API |
|---|---|
| 多输入 | 遍历 session.GetInputCount(),逐输入取 GetInputTypeInfo(i) 的 name、shape、dtype 各建一个 tensor,Run 传入名称数组与 tensor 数组 |
| fp16 输入输出 | 用 std::vector<Ort::Float16_t> 缓冲配合 CreateTensor<Ort::Float16_t>()。不要使用 CreateTensor<uint16_t>(),它创建的是 UINT16 tensor 而非 FLOAT16 |
| 动态维度 | 须按业务在构造输入 shape 时显式固定 batch、分辨率等维度 |
| 输出读取 | Run 返回的 Ort::Value 用 GetTensorTypeAndShapeInfo().GetShape() 取形状、GetTensorData<T>() 取数据指针,T 与输出 dtype 一致 |
性能特性开关
C++ 接口通过 OrtMUSAProviderOptions 的结构体字段设置,字段含义与 Python 接口一致,取值为 int 而非字符串:
| 字段 | 默认值 | 对应 Python option |
|---|---|---|
device_id | 0 | "device_id" |
prefer_nhwc | 0 | "prefer_nhwc" |
allow_tf32 | 1 | "allow_tf32" |
enable_musa_graph | 0 | "enable_musa_graph" |
各开关的作用、适用性与实测方式见性能特性开关。该章的结论对 C++ 路线同样适用:开关效果与模型结构强相关,上线前须在自有工程内实测确认,不建议未经实测即全部启用。
enable_musa_graph 不能在本章的写法下直接置 1。 该开关须配合 IOBinding 使用,要求输入输出预先分配在 MUSA 设备内存上、且跨次调用地址不变;本章示例使用的是普通 Run() 与 host 侧输入,置 1 后推理调用会返回错误。该开关仍在持续完善中,本版建议保持默认值 0;前提条件见图捕获(MUSA Graph)。
注意:allow_tf32 默认为 1,即带花括号初始化后该开关已处于开启状态。如需关闭须显式设置 musa.allow_tf32 = 0;。
精度验证
上线前须对自研模型执行精度验证。