Skip to content

张量并行(Tensor Parallelism, TP)——两台机器在同一个 token 上同时工作,把每一层里最重的矩阵运算切给两边,在图的同步门处交换部分和。与按层切片的流水线并行不同,它降低的是单 token 延迟,而非"塞下更大的模型"。

两种并行,一个根本区别 ​

ds4 有两套"把模型拆到多块芯片上"的方案,先分清它们:

流水线并行(Pipeline)张量并行(本文)
切什么按层切片,A 跑层 0–30,B 跑层 31–output按层内工作量切,A、B 同跑每一层
同一时刻A 处理 chunk N,B 处理 chunk N(流水线错位)A、B 处理同一个 token(lockstep)
交换什么整段隐藏状态激活(MiB 级)每层的部分和(16–24 KB)
主要收益塞下超出单机的模型 + 加速长 prefill降低单 token 延迟
decode更慢(每 token 至少一次跨机跳)更快(两人合力算一个 token)

一句话:流水线并行是"装配线",张量并行是"两人抬一件货"。

ds4 的张量并行有两种部署形态,共用同一套 lockstep 协议:

形态一:Mac-to-Mac 张量并行(RDMA) ​

两台 MacBook 用一根 Thunderbolt 5 线直连,把单个 decode 拆给两张 GPU。实现见 ds4_tp.c / ds4_tp.h(~3K 行,2026-09 延迟工程战役后)。

切分规则:每台机器常驻连续的一半路由专家;dense 权重、注意力、共享专家、embedding、output 在两边复制。这样路由专家内核永远不会碰对方那一半——容量翻倍而无跨专家读取。

lockstep 协议:Leader 是一个普通的前端 session,它把每一次 ds4_session_sync() / ds4_session_eval() 调用原样镜像给 Worker,于是两个引擎执行完全相同的图序列。在一个 token 内部,部分和在图的同步门(每层一个 ATTN 门、一个 FFN 门)处交换:

c
// ds4_tp.h — 门类型
enum {
    DS4_TP_GATE_ATTN = 0,
    DS4_TP_GATE_FFN  = 1,
    DS4_TP_GATES_PER_LAYER = 2,
    DS4_TP_BATCH_MAX_ROWS = 8,   // 推测验证块最多 5 行
};

// 在每个门处:把本机 partial 发给对方,等对方的 partial 到位
int ds4_tp_gate_exchange(ds4_tp *tp, uint32_t layer, uint32_t gate, uint64_t seq);

部分和是 f32,从不在网络上量化(vec_bytes = n_embd * 4)。DeepSeek 的 gate 向量 16 KB,一条 RDMA 消息发完;GLM 的 6144 宽、24 KB 向量拆成两条有序 RDMA 消息。

传输:优先 RDMA over Thunderbolt(two-sided SEND/RECV),否则回退到全双工 TCP(--transport tcp)。一个 GPU 可见的共享内存 slab 充当收发缓冲,NIC 用 RDMA 注册它并交换 remote key。

部署要点(详见上游 docs/DISTRIBUTED.md):

sh
rdma_ctl status && ibv_devinfo -v      # 先确认 verbs 设备与 IPv4-mapped GID

# 两台都要:放宽 GPU wired 上限(默认约 RAM 的 75%)
sudo sysctl iogpu.wired_limit_mb=120000

# 两台都要:给 Thunderbolt 成员接口配 IPv4(网桥 IP 不算)
sudo ifconfig en1 inet 10.99.0.2/30 alias   # 机器 A
sudo ifconfig en6 inet 10.99.0.1/30 alias   # 机器 B

# 先启 worker,它会重试直到 coordinator 加载完
./ds4 --tensor-parallel --role worker \
  --coordinator 10.99.0.2 9911 --transport rdma --ctx 8192

./ds4 --tensor-parallel --role coordinator \
  --listen 10.99.0.2 9911 --transport rdma --ctx 8192

歧义时用 --rdma-device / --rdma-gid-index 指定;RDMA 不可用就两边 --transport tcp。不要 curl/nc 探测等待中的 coordinator——探测连接会被当成 worker 握手,直接搞挂它。coordinator 可以是 ds4、ds4-agent、ds4-server、ds4-bench。GLM MTP 两端都加 --mtp;DeepSeek DSpark 两端都要支持模型与选项。

实测(两台 M5 Max 128 GB、Thunderbolt 5、MXFP4 配方,2026-09 延迟工程之后):

双 Mac TP单 Mac SSD streaming
decode @128 ctx~47-48 t/s~11 t/s
decode @2048 ctx~48 t/s—
prefill~250 t/s @128 token、~850 t/s @2048~10 t/s
启动~10 s/台(钉住分片)—
DSpark30-40 t/s(比纯 decode 慢:每个验证行重流它的专家)—

对比 2026-08 的同一设置(GLM 5.2 IQ2_XXS):decode 16.8 t/s、prefill ~94 t/s——一轮延迟工程把 decode 提了近 3 倍、prefill 一个数量级。代价仍是确定性但不逐字节相同——浮点归约顺序变了。

身份校验:握手时交换 ds4_tp_identity(GGUF 字节数、model_id、层数、embd、词表、量化位、上下文、解码门调度)。门调度决定 RDMA recv 落在 slab 的哪个槽:DeepSeek 每层先 ATTN 后 FFN;GLM 只在稀疏层发一个 FFN 门,所以它的调度跳过 dense 前缀和 ATTN 槽。两边必须一致,否则在跑任何推理前就 abort。协议已升至 version 10(2026-09:RDMA 预热、预投递窗口、GLM MTP 帧)——两端必须同版本。

不兼容组合:TP 要求 Metal 后端,不能和 SSD streaming、分布式模式、层切片同时启用(ds4_tp_validate_engine_options())。DSpark 推测已于 2026-09 解禁——验证块经 DS4_TP_FRAME_VERIFY 镜像给 worker(旧单阶段 MTP 在 TP 下退回逐 token decode);但实测 TP 下开 DSpark 更慢(上表),纯 decode 是当前推荐。

延迟工程战役(2026-09) ​

macm5us/mac-tp-1-sep-2026(4886c56 合入)把两 Mac TP 从"能跑"推到"快得值得跑"。两个 rank 每 token 在每层门上碰面,任何一侧的微秒抖动都进单 token 延迟——一周 ~25 个提交全在磨这件事(完整机制表格见 Part 6 §4j):

  • 轮询门 + 校验和 flag:CPU→GPU 事件唤醒要 27-43 µs,改 16 区 flag 环轮询;flag 行可能比 partial 的 store 早 ~35 µs 落地,整数校验和防读到半成品(kernel_dsv4_tp_flag_set_checked)
  • flag 折叠:把"发 flag"折进产出 partial 的载荷内核(ds4_gpu_tp_flag_fold_request),省一次 dispatch
  • RDMA 预热与 QP 重建:Apple UC verbs 上向无 posted receive 的 QP 发送会永久杀死该方向——tp_rdma_warm_up 先握手,失败则 tp_rdma_recreate_qp(新 PSN,至多 4 次)
  • 分级大门:prefill 每层 32 MB big gate 改 256×16 KB 窗口 + 链式 posted receive(~26 ms → 4-6 ms)
  • 队列保活:M5 Max 空闲 ~3 s 后提交的命令缓冲晚 600-800 ms 启动——每秒一个 1 KB 内核保温(ds4_gpu_warm_command_queue)
  • GPU 决定的负载均衡:由本 rank 选中的专家 id 在 GPU 上算共享专家车道互补切分(ds4_gpu_parallel_ffn_start_split,shift_q16);多领一个路由专家就让学生出一半共享专家
  • 推测验证预投递 + 三态提交:验证块 RDMA 窗口提前投递;ds4_tp_verify_commit_mode {ROLLBACK_REPLAY, COMMIT_FULL, COMMIT_PREFIX} 取代布尔 full_accept——TP 的 partial accept 也能直接提交前缀快照

计时驱动的车道偏置 DS4_TP_LANE_BIAS 因让输出依赖时序而默认关闭——"更快但不确定"不做默认。bbec200 之后混合 2/4/6-session TP 批的 logits 与串行完全一致。

形态二:CUDA 张量并行(单机多卡) ​

在单台 CUDA 服务器上,--cuda-tensor-parallel 把 DeepSeek V4 Flash 的张量和路由专家工作切到偶数块 GPU。它和上面的 Mac-to-Mac 模式互相独立:不用 --role、不用 RDMA、不走分布式层流水线。设备放置用普通的 --gpu-devices / --gpu-vram。

设备顺序很关键。N 块卡时,前 N/2 个逻辑层是连续的"流水线层之家",后 N/2 个是它们的张量并行搭档。先列所有 home,再列所有 partner,且配对位置上是最亲近的 P2P 对。例如 8×L40S 用物理对 (0,1)(2,3)(4,5)(6,7),写成 0,2,4,6,1,3,5,7。每对存 50/50 的路由专家,词表头按行分片给参与输出的层(这些大张量不复制);dense 注意力、router、共享专家在每对内复制。

sh
./ds4-server --cuda --cuda-tensor-parallel \
  --gpu-vram auto \
  --gpu-devices 0,2,4,6,1,3,5,7 \
  --model "$MODEL" --ctx 100000 \
  --batched-session 16 --host 0.0.0.0

该模式目前要求 DeepSeek V4 Flash + 偶数多卡放置;GLM 5.2 在 CUDA 上改走普通的层放置(路由专家 Q4 等 TP 不兼容布局会在评估前被拒绝);DGX Spark 是单卡目标,不能用 --cuda-tensor-parallel。

V4.1 Flash 双 Mac TP(2026-09):Q2 工件每 rank 常驻 ~81 GiB 主权重,两台机器都要完整 341 GiB GGUF——189 GiB 的 engram 表永远在盘上,两 rank 各自 pread 自己的行。与 V4 Flash 的两个结构差异:输出头复制而非词表切分(tp.vocab_split 仅保留给 V4);注意力分片方式按模型而定("attention partitioning depends on the model")。协议版本升到 12:新增同步检查点帧(取消由两 rank 协商一致,不在 GPU 门内单方决定)、RDMA 全发送 IBV_SEND_SIGNALED + 窗口屏障修 UC 竞态。续 prefill 批处理下限 32 token。

双 Spark TP(2026-09 中旬,a04f46f,协议 → 14):V4.1 Q2 文本推理扩展到两台 DGX Spark——Linux 侧 RoCEv2 + RC 队列对(libibverbs 运行时 dlopen,直连地址自动选 GID),TCP 兜底。与 Mac 路径的本质差异:CUDA 结果经 pinned host 内存中转(RoCE,非 GPUDirect),交换模型是"等本地流后同步调用"而非 Metal 的服务线程异步门。每台 ~81 GiB(专家 50/50),≥5 个就绪会话才跨双 Spark 批处理 decode;实测单会话 21.9 t/s、8 会话聚合 ~28 t/s、32K prefill ~400 t/s。协议 14 要求所有 peer(含 Metal)一起升级。

托管重启:run-nvidia-tp-server.sh 包一层 --cuda-tensor-parallel server,进程崩溃后自动重启。配合小 Q4 批次的 TP 加速内核,单机多卡服务部署更稳。

相关概念 ​

  • distributed-inference — 流水线并行(按层切片),与本文互补
  • session-batching — 张量并行常和会话批处理一起用于多用户服务
  • moe — 路由专家是切分的主要对象(占模型大部分空间)
  • ssd-streaming — 另一种突破单机内存的方式,与 TP 互斥

详见 Part 6 — 张量并行。