张量并行支持现状与多 GPU 拆分实践:从 ik_llama.cpp Issue #627 谈起
【免费下载链接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance项目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp
本文围绕 ik_llama.cpp 仓库中一则典型的 Feature Request(github-data/issues/627)展开,梳理社区对“张量并行(Tensor Parallelism)”的诉求背景、ik_llama.cpp 当前提供的多 GPU 拆分方案(--split-mode各模式)、对应命令行参数与源码实现依据,并结合 issue 讨论中用户的实测数据,帮助读者理解在 ik_llama.cpp 中如何配置多 GPU 推理、当前的性能边界与已知限制。
一、Issue #627 的诉求:为什么需要张量并行
2025 年 7 月 18 日,用户rankaiyx在 ik_llama.cpp 仓库提交了编号 627 的 Feature Request(当前状态为 Open),核心诉求是:在 ik_llama.cpp 中实现张量并行(Tensor Parallelism)支持。
1.1 张量并行是什么
Issue 中对张量并行的定义是:一种用于大语言模型(LLM)推理的模型并行技术,将模型的张量计算(如矩阵乘法)分布到多个设备(GPU/TPU)上,使模型不同层的不同部分能够并行处理,从而提升推理速度与可扩展性。其关键特性包括:
- 模型拆分(Model Splitting):将模型层(尤其是大型权重矩阵)拆分到多个设备;
- 分布式计算(Distributed Computation):并行执行张量运算,减少计算时间;
- 通信开销(Communication Overhead):需要设备间通信(如 AllReduce)来同步中间结果;
- 高效扩展(Efficient Scaling):使超出单设备显存容量的大型模型也能完成推理。
典型使用场景是:模型尺寸超过单张 GPU 显存容量时的大规模 LLM 推理。
1.2 动机:--split-mode row的性能差距
提交者给出的动机非常具体:当前通过--split-mode row实现的多 GPU 推理性能远低于 vLLM 或 mlc-llm。其引用的实测数据如下(注意:以下均为 issue 提交者报告的个人环境数据,非项目官方基准):
- 平台:4×P100(Pascal 架构,较老的计算卡);
- 模型:Qwen2.5-72B-4bit;
- vLLM / mlc-llm:生成速度约20 tok/s;
- llama.cpp(
--split-mode row):生成速度约10 tok/s,约为前者的一半。
此外,提交者还补充了两个背景因素:mlc-llm 开发活跃度较低、支持模型较少;而 vLLM 的 1.0 版本将放弃大量 Turing 及更老的硬件。因此他希望在 ik_llama.cpp 中通过张量并行获得更好的老硬件多卡性能。
需要明确的是,issue 编号 627 在仓库记录中仍为 Open 状态,即该项目当时并未完整落地独立的张量并行实现。下文所述的
--split-mode各拆分模式,是该 issue 讨论时项目中实际存在的多 GPU 推理方案。
二、ik_llama.cpp 现有的多 GPU 拆分方案:split-mode 全景
虽然 issue 中提交者写的是--split-mode row,但当前仓库中-sm/--split-mode的合法取值已经演进为四个模式。在 include/llama.h 中定义了枚举:
enum llama_split_mode { LLAMA_SPLIT_MODE_NONE = 0, // single GPU LLAMA_SPLIT_MODE_LAYER = 1, // split layers and KV across GPUs LLAMA_SPLIT_MODE_ATTN = 2, // splits self-attention computations across GPUs LLAMA_SPLIT_MODE_GRAPH = 3, // splits computations across GPUs };命令行解析位于 common/common.cpp,对应关系如下:
| 命令行取值 | 枚举值 | 语义 |
|---|---|---|
none | LLAMA_SPLIT_MODE_NONE | 仅使用单张 GPU |
layer(默认) | LLAMA_SPLIT_MODE_LAYER | 按层与 KV 缓存拆分到多张 GPU |
attn | LLAMA_SPLIT_MODE_ATTN | 将 self-attention 计算拆分到多张 GPU |
graph | LLAMA_SPLIT_MODE_GRAPH | 将模型张量与计算图拆分到多张 GPU |
其中graph模式最接近 issue 中“张量并行”的诉求:它不再只是按层切分,而是把单个层的权重张量与计算图节点分布到多张 GPU 上执行,并配合 REDUCE 算子做跨设备归约。
2.1 从源码结构看各模式的实现差异
在 src/llama.cpp 的设备分配逻辑中,可以看到三种路径的分野:
LLAMA_SPLIT_MODE_LAYER:按default_layer_device[]把每个重复层整体分配到某一设备,使用llama_default_buffer_type_offload();输出层同理。这是最传统、通信开销最小的“层级流水”拆分。LLAMA_SPLIT_MODE_GRAPH/LLAMA_SPLIT_MODE_ATTN:当model.splits.size() > 1时,会构造一个llama_default_buffer_type_split()的split_buft,并让每个层持有{ split_buft, offload_buft }双 buffer 类型——即权重按“拆分 buffer”存放、随计算图在各 GPU 间调度执行。ATTN模式还会根据splits[]比例用std::upper_bound把每一层落在对应的 GPU 上(src/llama.cpp)。
这也解释了为什么仓库中大量架构实现会同时判断GRAPH与ATTN两种模式。例如 src/llama-load-tensors.cpp 中的use_split_ctx、src/graphs/build_deepseek2.cpp 中的tp_mode(张量并行模式)标志,均把GRAPH/ATTN视为“按张量拆分”的统一入口。
2.2 拆分模式下张量如何存放与归约
在GRAPH模式下,模型的重复层张量会按设备数量复制/切分。可以从 src/llama-model.h 看到一条关键逻辑:
if (split_mode == LLAMA_SPLIT_MODE_GRAPH && !devices.empty()) n_tensors *= devices.size();即拆分模式下张量数量会乘以设备数——这正是张量并行“每个设备持有权重的一个切片”的典型形态。而跨设备的结果同步,则对应 issue 中提到的 AllReduce 语义:项目以REDUCE 算子的形式在计算图中完成多设备归约,GGML_OP_ADD等节点在graph调度下跨设备执行并同步(src/llama.cpp 的注释明确提到“the GPU where the last REDUCE op is performed”)。
三、多 GPU 推理的命令行实战
结合 common/common.cpp 的帮助文本,实际使用多 GPU 时最常用的参数如下。
3.1 选择拆分模式:-sm, --split-mode
-split-mode SPLIT_MODEnone:只用一块 GPU;graph:把模型张量与计算图拆分到多张 GPU(最接近张量并行);layer(默认):按层与 KV 拆分;- 仓库帮助文本中未列出
attn,但解析器支持该取值(common/common.cpp)。
注意:-sm仅在编译启用了 CUDA/SYCL/Vulkan 后端时生效;否则会打印警告 “llama.cpp was compiled without CUDA/SYCL/Vulkan. Setting the split mode has no effect.”(common/common.cpp)。
3.2 控制张量在各 GPU 的分配比例:-ts, --tensor-split
-ts, --tensor-split SPLIT以逗号分隔的“每块 GPU 分担的模型比例”,例如3,1表示把约 3/4 权重给第一块 GPU、1/4 给第二块。解析代码位于 common/common.cpp:参数以,或/分割,逐项写入params.tensor_split[],未指定的设备权重置 0;同时要求split_arg.size() < llama_max_devices()。
3.3 指定主 GPU 与设备列表
-mg, --main-gpu i # split-mode=none 时模型所在 GPU;graph/row 场景下用于中间结果与 KV 的 GPU -dev, --device dev1,dev2 # 显式指定参与 offload 的设备,如 CUDA0,CUDA1,RPC[192.168.0.1:8080] --max-gpu i # split mode 'graph' 下同时使用的 GPU 数量上限其中-dev支持RPC[ip:port]形式的远端设备,说明多卡场景还可以跨机器扩展(见 examples/rpc)。
3.4 拆分模式专项开关
-smgs, --split-mode-graph-scheduling # 强制使用 Split Mode Graph Scheduling -smf16, --split-mode-f16 # GPU 间数据交换使用 f16(默认) -smf32, --split-mode-f32 # GPU 间数据交换使用 f32这三个开关在 common/common.cpp 中解析(-smf16/-smf32当前被注释,尚未激活),并写入上下文参数split_mode_graph_scheduling(common/common.cpp)。在 src/llama.cpp 中,当split_mode == LLAMA_SPLIT_MODE_GRAPH时(且无张量覆盖或用户强制-smgs),会调用:
ggml_backend_sched_set_split_mode_graph(ctx->sched, true, cparams.scheduler_async);该 API 声明于 ggml/include/ggml-backend.h,async参数表明拆分模式图的调度支持异步执行。若用户同时设置了张量覆盖(tensor overrides)又强制-smgs,日志会明确警告可能因组合不受支持而导致推理错误。
3.5 典型多卡启动示例
结合以上参数,一个在 2 张 GPU 上以 graph 模式运行的典型命令形如:
./build/bin/llama-cli -m Qwen2.5-72B-4bit.gguf \ -ngl 99 \ -sm graph \ -ts 1,1 \ -mg 0其中-ts 1,1表示两卡均分权重,-mg 0指定主 GPU。需要提醒的是,graph模式对架构支持有前置条件(详见下文),实际使用前应先在低负载模型上验证。
四、issue 讨论中的实测反馈与已知限制
issue 的对话部分保留了多位用户的实测观察,这些是理解该功能现状的一手素材(均为用户个人环境数据,非官方基准):
项目维护者的定位:ikawrakow(项目作者)回复表示“支持旧硬件并非本项目强项,而这恰恰是 mainline llama.cpp 的强项之一”,并建议将该 issue 提交给 llama.cpp 主线项目——这界定了该项目在多 GPU 能力上的优先级定位。
split-mode row 的实际表现:用户 Ph0rk0z 在 Command-A 模型上的对比测试显示:
- ik_llama.cpp 在 split-mode row 下生成约17 tok/s,与主线 prompt 处理速度相当,但输出出现不连贯文本(“looks like parts of the training data or random text”);关闭 split-mode 后输出连贯但速度降到约12 tok/s;
- 主线 llama.cpp 并行时约12 tok/s,关闭后约9 tok/s;且两边的prompt 处理速度在 row 模式下都约减半。
后续建议:用户 saood06 的结论是“这个仓库提供了最快的可用生成速度”,建议针对 row 模式的连贯性问题以及 PP 速度减半问题分别提交 issue 跟踪。
从这些反馈可以看出,多 GPU 拆分(尤其是 row 语义)在当时存在两类典型问题:输出质量退化(可能与跨设备归约的数值/同步路径有关)与prompt 处理吞吐下降。这也与第 2.2 节所述 REDUCE 跨设备同步的通信开销互相印证。
五、现状与展望
截至仓库记录的 issue 状态,编号 627 仍为Open,即张量并行作为一个“独立完整特性”尚未在本仓库中统一落地;但仓库已经在GRAPH/ATTN拆分模式上实现了大量与张量并行同构的机制:
- 张量级切分与多副本存放(src/llama-model.h);
- 拆分 buffer 类型
split_buft与计算图调度(src/llama.cpp); - 跨设备 REDUCE 归约与异步 graph 调度(ggml/include/ggml-backend.h、src/llama.cpp);
- 多架构的
tp_mode判定(如 src/graphs/build_deepseek2.cpp、src/graphs/build_minimaxm2.cpp)。
对于希望用老硬件(如 4×P100)跑超大模型的用户,务实路径是:先以-sm layer获得稳定的多卡可用性,再尝试-sm graph+-ts配置观察吞吐与输出质量,并注意对照 issue 讨论中已知的“row 模式输出不连贯 / PP 减半”风险。需要跟进张量并行完整实现进展的读者,可直接关注该 issue 的状态变化及-sm相关参数在 common/common.cpp 中的演进。
【免费下载链接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance项目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考