llama.cpp IBM zDNN 后端实战:在 IBM z17 主机上通过 NNPA 加速 LLM 矩阵乘

📅 发布时间:2026/9/7 3:15:04
llama.cpp IBM zDNN 后端实战:在 IBM z17 主机上通过 NNPA 加速 LLM 矩阵乘 llama.cpp IBM zDNN 后端实战在 IBM z17 主机上通过 NNPA 加速 LLM 矩阵乘【免费下载链接】llama.cppLLM inference in C/C项目地址: https://gitcode.com/GitHub_Trending/ll/llama.cpp本文以 llama.cpp 仓库中的 zDNN 后端文档为主线完整讲解 IBM zDNN 加速库的硬件前提、CMake 配置项、库安装与 llama.cpp 编译流程并结合ggml/src/ggml-zdnn目录下的后端源码剖析 zDNN 设备是如何被注册、如何探测 NNPA 硬件、又为何只对MUL_MAT矩阵乘算子进行硬件卸载。读完后你将能够在一台 IBM z17 / LinuxONE 5 主机上从零搭建可运行的 zDNN 加速版 llama.cpp并理解该后端的能力边界与回退机制。什么是 zDNN先厘清两个易混淆的名字llama.cpp 官方文档在开篇就用醒目的警告区分了两个拼写相近但完全不同的库zDNN本文主题IBM 的 Deep Neural Network 加速库专门运行在 IBM Z 与 LinuxONE 主机的 IBM Telum I / Telum II 处理器上底层依托处理器内置的NNPANeural Network Processing Assist神经网络处理辅助协处理器ZenDNNAMD 面向 EPYC CPU 的深度学习库与 IBM 主机没有任何关系见 ZenDNN 后端文档。zDNN 通过把神经网络推理中的密集矩阵运算交给 NNPA 硬件执行为主机环境下的 LLM 推理提供显著的性能提升。llama.cpp 的 zDNN 后端正是为此设计它让 llama.cpp 能够运行在 IBM z17 及后续系统上并通过 zDNN 库调用 NNPA 加速。硬件与数据类型支持矩阵官方文档给出的支持矩阵非常明确硬件级别状态已验证环境IBM z17 / LinuxONE 5SupportedRHEL 9.6, IBM z17, 40 IFLsIBM z16 / LinuxONE 4Not Supported—值得注意z16Telum I目前不在支持范围内只有 z17Telum II及以上才可用。这一点在后端源码中也有对应实现——ggml-zdnn.cpp 中设备上下文会分别探测两种 NNPA 参数块格式的安装状态ctx-has_parmblkformat_0 zdnn_is_nnpa_parmblk_fmt_installed(1, NNPA_PARMBLKFORMAT_0); ctx-has_parmblkformat_1 zdnn_is_nnpa_parmblk_fmt_installed(1, NNPA_PARMBLKFORMAT_1);其中has_parmblkformat_1在 common.hpp 的注释中明确标注为 checks for z17——即格式 1PARMBLKFORMAT_1是 z17 的标识能力这解释了为什么文档把支持门槛划在 z17。数据类型方面zDNN 后端支持三种浮点格式数据类型状态F32SupportedF16SupportedBF16Supported从源码结构看当前实现不支持任何量化权重类型q4_0、q8_0、IQ 系列等均不在列这在ggml/src/ggml-zdnn/ggml-zdnn.cpp的矩阵乘实现中留有明确的 TODO 注释ggml-zdnn.cpp// TODO: implement support for quantized types // we currently only support f32, f16, and bf16 ggml_zdnn_mul_mat_f(ctx, src0, src1, dst);CMake 配置选项zDNN 后端由两个 CMake 选项控制CMake 选项默认值说明GGML_ZDNNOFF是否编译带 zDNN 支持的 llama.cppZDNN_ROOT覆盖 zDNN 库的查找路径GGML_ZDNN选项定义在 ggml/CMakeLists.txtoption(GGML_ZDNN ggml: use zDNN OFF)打开该选项后构建会进入 ggml/src/ggml-zdnn/CMakeLists.txt其查找逻辑值得细看if (DEFINED ZDNN_ROOT) message(STATUS zdnn: using ZDNN_ROOT override: ${ZDNN_ROOT}) set(ZDNN_HINT ${ZDNN_ROOT}) else() set(ZDNN_HINT ) endif() find_path(ZDNN_INCLUDE NAMES zdnn.h HINTS ${ZDNN_HINT} /usr /usr/local PATH_SUFFIXES include) find_library(ZDNN_LIB NAMES zdnn HINTS ${ZDNN_HINT} /usr /usr/local PATH_SUFFIXES lib lib64)即ZDNN_ROOT作为HINTS优先搜索之后回退到系统标准目录/usr与/usr/local头文件查找zdnn.h、库文件查找libzdnnlib/lib64两种子目录任一头文件或库文件找不到都会触发FATAL_ERROR并提示please set ZDNN_ROOT to the proper path——因此只要 zDNN 不是装在标准系统目录下务必显式指定ZDNN_ROOT找到后构建系统把ggml/src/ggml-zdnn/下的 C/C 源码通过ggml_add_backend_library(ggml-zdnn ...)编译为独立的 ggml 后端动态库链接libzdnn并定义GGML_USE_ZDNN宏。第一步从源码安装 zDNN 库官方文档特别提示通过apt或yum安装的 zDNN 包可能无法正常工作此问题已在社区 issue #15772 中被报告因此推荐从源码编译安装。完整流程如下git clone --recurse-submodules https://github.com/IBM/zDNN cd zDNN autoreconf . ./configure --prefix/opt/zdnn-libs make build sudo make install各步骤说明git clone --recurse-submodules https://github.com/IBM/zDNN拉取 IBM 官方 zDNN 源码注意必须带--recurse-submodules获取依赖子模块autoreconf .重新生成 autotools 构建脚本./configure --prefix/opt/zdnn-libs把安装前缀固定为/opt/zdnn-libs这个路径就是下一步要传给 llama.cpp 的ZDNN_ROOTmake build与sudo make install构建并安装头文件与libzdnn到该前缀下。第二步编译带 zDNN 后端的 llama.cppgit clone https://github.com/ggml-org/llama.cpp cd llama.cpp cmake -S . -G Ninja -B build \ -DCMAKE_BUILD_TYPERelease \ -DGGML_ZDNNON \ -DZDNN_ROOT/opt/zdnn-libs cmake --build build --config Release -j$(nproc)要点回顾-DGGML_ZDNNON打开后端编译默认是OFF不打开则整个ggml-zdnn目标不会参与构建-DZDNN_ROOT/opt/zdnn-libs必须与上一步./configure --prefix的路径一致这样 CMake 查找逻辑 才能命中include/zdnn.h与lib/libzdnn.*使用 Ninja 生成器并以-j$(nproc)并行编译构建完成后即可在 z17 机器上运行 llama.cpp 的各工具llama-cli、llama-server、llama-bench 等由运行时自动发现 NNPA 设备并卸载支持的算子。源码级剖析zDNN 后端是如何接入 ggml 的zDNN 后端位于 ggml/src/ggml-zdnn 目录核心文件包括后端主实现 ggml-zdnn.cpp、设备/缓冲结构定义 common.hpp、矩阵乘实现 mmf.cpp 与张量工具 utils.cpp。理解以下四个环节就能看懂这个后端的完整工作链路。1. 后端注册与设备发现后端通过标准的 ggml backend registry 接口注册入口为 ggml_zdnn_reg / ggml_backend_zdnn_reg并以 GUID 字符串IBM-ZDNN-ACCELER标识自身static ggml_guid_t ggml_backend_zdnn_guid(void) { static const char * guid_str IBM-ZDNN-ACCELER; return reinterpret_castggml_guid_t((void *)guid_str); }设备数量的关键判定在 ggml_backend_zdnn_reg_device_countstatic size_t ggml_backend_zdnn_reg_device_count(ggml_backend_reg_t reg) { if (!zdnn_is_nnpa_installed()) { return 0; } return 1; }也就是说如果系统里没有安装/暴露 NNPA注册器会报告 0 个设备ggml 的调度层自然不会把任何算子分给它——这正是 z16 或其他非 NNPA 机器上该后端静默缺席的原因。后端还通过get_features接口对外暴露NNPA、NNPA_PARMBLKFORMAT_0、NNPA_PARMBLKFORMAT_1三个特性开关ggml-zdnn.cpp可以用llama-bench等工具观察当前环境是否真的启用了硬件加速。2. 设备上下文能力探测首次获取设备时ggml_backend_zdnn_device_acq 会一次性缓存三项关键信息结构体定义见 common.hpphas_parmblkformat_0 / has_parmblkformat_1两种 NNPA 参数块格式是否可用前者为通用 NNPA 能力后者用于识别 z17max_size zdnn_get_nnpa_max_dim_idx_size()NNPA 允许的最大张量维度索引后续所有张量形状都要受此上限约束设备类型为GGML_BACKEND_DEVICE_TYPE_ACCEL加速器描述字符串为 IBM Z Neural Network Processing Assist (NNPA)设备特性ggml-zdnn.cpp为不支持异步、不支持 host buffer、不支持 events但支持 mmap。3. 算子支持面只卸载 MUL_MATggml_zdnn_supports_op 精确界定了哪些算子可以放到 zDNN 设备上执行GGML_OP_NONE / RESHAPE / VIEW / TRANSPOSE / PERMUTE零成本元算子直接放行GGML_OP_MUL_MAT需要同时满足——权重与输入都是规整矩阵ggml_is_matrix、内存连续ggml_is_contiguous、不是视图张量、ne0 / ne1 / ne10均不超过max_size且权重类型只能是 F32、F16 或 BF16其余所有算子RMS_NORM、SOFT_MAX、MUL、ADD 等逐元素与规约类一律返回false。图执行函数 ggml_zdnn_graph_compute 同样只对GGML_OP_MUL_MAT分发给 ggml_zdnn_mul_mat_f内部调用 zDNN 的矩阵乘 API 完成 NNPA 上的硬件计算遇到不支持的算子会打印 unsupported op 错误日志。这也与 docs/ops/zDNN.csv 中自动生成的算子支持表相互印证该表枚举了 zDNN 后端在各算子、各类型组合下的支持情况MUL_MAT 的浮点组合是可加速的核心路径。由于 llama.cpp 的图分区graph split机制会按各后端的supports_op结果把算子切分到不同设备执行未卸载的算子会回落到 CPU 等后端因此混合执行是常态矩阵乘走 NNPA其余逐元素运算留在 CPU。4. 张量缓冲与 bias 附加缓冲zDNN 的张量需要转换到 NNPA 内部的 ztensor 表示。后端为每个张量维护一个 ggml_backend_zdnn_buffer 结构内含转换前后的描述符pre_tfm_desc/tfm_desc与zdnn_ztensor数据装载通过 utils.cpp 中的ggml_zdnn_load_tensor完成缓冲区按 256 字节对齐分配ggml-zdnn.cpp。一个值得注意的细节初始化GGML_OP_MUL_MAT输出张量时后端还会额外分配一块与ne[0]等长、按 1D 布局转换的零值 bias 缓冲ggml-zdnn.cpp以适配 zDNN 矩阵乘接口对偏置参数的要求case GGML_OP_MUL_MAT: { std::unique_ptrggml_backend_zdnn_buffer zdnn_bias_buffer std::make_uniqueggml_backend_zdnn_buffer(); zdnn_bias_buffer-data (void *)calloc(tensor-ne[0], ggml_element_size(tensor)); ... const int64_t bias_dim[GGML_MAX_DIMS] { 1, 1, 1, tensor-ne[0] }; ggml_zdnn_create_tensor(zdnn_bias_buffer-pre_tfm_desc, zdnn_bias_buffer-tfm_desc, zdnn_bias_buffer-ztensor, tensor, bias_dim, ZDNN_1D); ggml_zdnn_load_tensor(zdnn_bias_buffer-ztensor, zdnn_bias_buffer-data); zdnn_buffer-extra zdnn_bias_buffer.get(); } break;此外ggml_backend_zdnn_buffer_set_tensor 中还专门处理了LLAMA_SET_ROWS场景下的 ztensor 重置逻辑以修复 ztensor 已处于 transformed 状态时重新灌入数据导致的错误代码注释中引用了 issue #15414。使用建议与当前限制结合文档与源码实际部署时需要注意平台门槛必须是 IBM z17 / LinuxONE 5或更新的且 NNPA 可用例如文档验证过的 RHEL 9.6 环境在 z16 或无 NNPA 的机器上注册器会返回 0 设备后端不生效权重精度模型权重张量需要是 F32/F16/BF16 才能被 NNPA 加速量化模型中的量化权重矩阵当前无法卸载到 zDNN源码中留有量化支持 TODO相应算子会回落到 CPU 后端执行维度上限MUL_MAT的各维度受zdnn_get_nnpa_max_dim_idx_size()返回值约束超出的层会自动回退到其他后端库来源优先从源码编译安装 zDNN 并固定--prefix然后用ZDNN_ROOT指向它发行版软件包里的 zDNN 存在已知兼容性问题验证手段编译完成后可以运行llama-bench通过后端特性输出NNPA、NNPA_PARMBLKFORMAT_1均为 1确认硬件路径已启用。延伸阅读zDNN 后端官方文档docs/backend/zDNN.md易混淆的 AMD ZenDNN 后端docs/backend/ZenDNN.mdzDNN 算子支持矩阵docs/ops/zDNN.csv后端实现ggml/src/ggml-zdnn/ggml-zdnn.cpp、ggml/src/ggml-zdnn/mmf.cpp、ggml/src/ggml-zdnn/utils.cpp构建配置ggml/src/ggml-zdnn/CMakeLists.txt、ggml/CMakeLists.txt【免费下载链接】llama.cppLLM inference in C/C项目地址: https://gitcode.com/GitHub_Trending/ll/llama.cpp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考