ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

大模型推理引擎vLLM(38):分布式集合通信 Broadcast、Gather、Reduce、ReduceScatter、AllGather、AllReduce、All-to-All 相关问题整理

大模型推理引擎vLLM(38):分布式集合通信 Broadcast、Gather、Reduce、ReduceScatter、AllGather、AllReduce、All-to-All 相关问题整理 目录1 Broadcast1.1 是什么1.2 有什么用1.3 在大模型推理 / vLLM 里主要用在哪1.3.1 Pipeline ParallelismPP把最后一阶段的结果广播给前面的 stage1.3.2 控制面 / RPC调度指令广播给各个 Workershm_broadcast2 Gather2.1 是什么2.2 有什么用2.2.1 Tensor ParallelismTP把分片 vocab 上的 logits 收集到 rank 02.2.2 和 AllGather 的取舍3 Reduce3.1 是什么3.2 有什么用3.3 在大模型推理 / vLLM 里主要用在哪3.3.1 先说结论纯 Reduce 用得不多热路径更常见 AllReduce3.3.2 「Reduce」这个词仍经常出现但多半是「规约运算」本身4 Scatter4.1 是什么4.2 有什么用4.3 在大模型推理 / vLLM 里主要用在哪4.3.1 先说结论单独的 Scatter 用得不多4.3.2 概念上会碰到的地方5 ReduceScatter5.1 是什么5.2 有什么用5.3 经典例子AllGather → 本地计算 → ReduceScatter① AllGather把输入拼齐② 本地计算例如 RowParallel 的局部 MatMul③ ReduceScatter求和并散回各人 token 段5.4 在大模型推理 / vLLM 里主要用在哪5.4.1 Sequence Parallel / TP 优化5.4.2 Context ParallelCP/ PCP5.4.3 算子融合MatMul ReduceScatter6 AllReduce6.1 是什么6.2 有什么用6.3 经典例子TP 下的 RowParallelLinear6.4 在大模型推理 / vLLM 里主要用在哪6.4.1 Tensor Parallelism最常见热路径6.4.2 其它并行组上的同步6.4.3 Custom AllReduce知道有优化即可7 AllGather7.1 是什么7.2 有什么用7.3 经典例子接上章的 Sequence Parallel7.4 在大模型推理 / vLLM 里主要用在哪7.4.1 Tensor Parallel / Sequence Parallel拼齐激活或中间结果7.4.2 和 Gather 的取舍logits 那条线7.4.3 Context Parallel / 多模态等8 All-to-All8.1 是什么8.2 All-to-All 和 All-to-Allv8.3 有什么用8.4 经典例子MoE 的 Dispatch / Combine8.5 在大模型推理 / vLLM 里主要用在哪8.5.1 Expert Parallelism绝对主角8.5.2 其它DCP 等布局重排abstract:broadcast(广播):其实就是广播把我一个人有的指令或者数据广播给其他人让其他人也知道最终结果就是大家的指令或者数据都相同了。gather(聚合):很多人有收集到一个人手里。很少单独用gatherreduce(规约):很多人有同形状数据按运算如 sum汇总成一份交到一个人手里。很少单独用。scatter(散射):一个人有完整份切开分给大家每人拿一段。很少单独用scatterReduceScatter先汇总再切开分给大家每人拿一段全局结果。allreduce:大家各自有一份汇总后每个人都拿到同一份完整结果。allgather:每人一小段内容不同拼成完整份并且每个人都有。和 AllReduce 的差别是拼 vs 加。all2all:个性化全交换每人给每人发可能不同的数据。其实记住每个单词的意思就记住这几个的意思了词字面概念Broad-cast广播出去一人复制给全员Gather收集收到一个人那里All-Gather全员收集收集完人人都有Reduce规约/归纳算成一份通常一人有All-Reduce全员规约算完人人都有Scatter散射/撒开切开分给不同人Reduce-Scatter先规约再散射先算再切开All-to-All全对全每人给每人发1 Broadcast1.1 是什么Broadcast广播 是一种一对多的集合通信组里指定一个 root / src 进程把它手里的那份数据发给组内所有其他进程结束后每个进程上都有同一份相同的数据。可以把它想成「一个人念通知全组人都抄一份」发送方只有 root 有有效数据接收方其他 rank 收到后本地内容与 root 一致结果组内数据完全相同不是拼接、不是求和1.2 有什么用典型场景某个 rank 算完了别的 rank 接下来也要用这份结果控制面信息配置、元数据、调度指令需要全员一致避免每个 rank 重复算同一件事或避免「只有一个地方有、别处却要用」的不一致它本身不做求和、不做拼接只做「复制分发」。1.3 在大模型推理 / vLLM 里主要用在哪1.3.1 Pipeline ParallelismPP把最后一阶段的结果广播给前面的 stagePP 时模型按层切开只有 最后一个 PP stage 能算出 logits / 采出 token。但前面的 stage 在下一步 decode 时往往也需要「上一步采出的 token」。vLLM 里常见做法是由 last PP rank 做broadcast把sampled_token_ids以及相关计数发给同组其他 PP rank。对应逻辑在pp_utils.py、gpu_model_runner.py的 PP broadcast 路径里。1.3.2 控制面 / RPC调度指令广播给各个 Workershm_broadcastvLLM 多进程执行时EngineCore / Executor 需要把同一套方法调用method、args、kwargs发给各个 Worker。这里用的是共享内存上的 MessageQueue broadcastshm_broadcast.py语义仍是 Broadcast一份调度消息多个 Worker 各收一份。2 Gather2.1 是什么Gather收集 是一种多对一的集合通信组里每个进程都有自己的一块数据指定一个 dst / root 进程把所有人的数据都收过来结束后只有 root 上拥有完整拼接结果其他 rank 通常没有这份完整数据在 vLLM 实现里非 dst rank 甚至可能拿到None。可以把它想成「全组交作业只交到班长手里」发送方每个 rank 都把自己那份发出去接收方只有 dst/root 收到并拼起来结果root 上是各 rank 数据的拼接不是求和也不是全员都有2.2 有什么用典型场景数据/结果本来分散在各个 rank但后续处理只想在一个进程上做采样、打印、写文件、返回给客户端和 Scatter 成对先 Scatter 分出去并行算再 Gather 收回来想节省通信如果只需要一个地方有完整结果用 Gather 比 AllGather 更省不必再分发给所有人它本身不做求和只做「收集 拼接」。2.2.1 Tensor ParallelismTP把分片 vocab 上的 logits 收集到 rank 0TP 下词表vocab常常被切到不同 GPU 上每个 TP rank 只算出自己那一段 vocab 对应的 logits。但采样sample通常需要完整词表上的分数。vLLM 里常见做法是调用tensor_model_parallel_gather把各 TP rank 的 logits Gather 到 dst0非 0 号 rank 可能返回None。对应逻辑在logits_processor.py的_gather_logits里。直观理解TP0: logits[*, vocab0] ──┐TP1: logits[*, vocab1] ──┼── gather ──► TP0 上拼成完整 logitsTP2: logits[*, vocab2] ──┘ TP1/TP2 不一定再保留完整份2.2.2 和 AllGather 的取舍同一处代码里也能看到有些设备如 TPU不方便用 Gather会改成 AllGather让每个设备都拿到完整 logits以保证各卡执行路径一致。3 Reduce3.1 是什么Reduce规约 是一种多对一的集合通信组里每个进程都有一份同形状的数据指定一个 dst / root 进程并指定一种运算常见是SUM、MAX、MIN、PROD结束后只有 root 上拿到规约后的结果其他 rank 一般不保留这份全局结果。可以把它想成「全组报数只汇总到班长本子上」发送方每个 rank 贡献自己那份数据运算按约定做加总 / 取最大 / 取最小等接收方只有 root 拿到最终结果结果一份「算过」的结果不是拼接也不是简单复制和相近原语的区别操作结果形态Reduce各份数据做运算只有 root 有结果AllReduce各份数据做运算每个进程 都有同一份结果Gather各份数据拼接只有 root 有完整份Broadcast不做运算只把 root 的数据复制给全员一句话很多人有汇总成一份交到一个人手里。3.2 有什么用典型场景需要全局统计但只想在一个进程上用结果全局 loss、计数、最大值、是否所有人 ready作为更复杂通信的「半边」AllReduce ≈ Reduce BroadcastReduceScatter ≈ Reduce Scatter训练里更常见梯度先 Reduce 到某卡推理里单独出现相对少它和 Gather 的关键差别Gather拼起来catReduce算出来sum / max / …3.3 在大模型推理 / vLLM 里主要用在哪3.3.1 先说结论纯 Reduce 用得不多热路径更常见 AllReduce和前面 Gather / AllGather 的关系很像Reduce结果只留在一个人那里AllReduce结果每个人都要有大模型推理里TP 下各卡算出局部结果后通常每个 rank 后面还要继续用同一份归约结果例如 RowParallel 后的 hidden states所以工程上几乎都直接走 AllReduce而不是先 Reduce 再 Broadcast。vLLM 里你更常看到的是tensor_model_parallel_all_reduce(...)tp_group.all_reduce(...)以及各种 fused / custom all_reduce单独的torch.distributed.reduce在推理热路径里很少当主角。3.3.2 「Reduce」这个词仍经常出现但多半是「规约运算」本身即使不单独调 Reduce API很多地方仍在做 reduce 语义例如TP 里对分片输出做 sum reduce通过 AllReduce 实现跨 rank 取 max / min同步 batch 规模、内存水位、是否可继续等vocab 并行时先本地 argmax再在多个 rank 的候选里做全局比较概念上是 reduce 到全局最优实现上可能用 AllGather 小张量再本地比所以读代码时要分清Reduce 原语通信 API结果只到 rootreduce 运算sum/max 这种数学操作常常包在 AllReduce / ReduceScatter 里4 Scatter4.1 是什么Scatter散射 是一种一对多的集合通信组里指定一个 src / root 进程它手里有一份完整数据按约定切成若干块每块发给一个进程。结束后每个 rank 只拿到属于自己的那一段不再人人都有完整份。可以把它想成「班长把讲义撕成几份每人发一页」发送方只有 root 有完整数据分发方式按块切开一人一块通常等分接收方每个 rank 只收到自己那份结果数据被分散开不是复制同一份也不是求和和相近原语的区别操作结果形态Scatterroot 的完整数据切开每人拿不同一块Broadcastroot 的数据原样复制每人拿同一份GatherScatter 的反操作每人一块收集回 root 拼完整ReduceScatter先对各人数据做规约再把结果切开分给每人一句话一个人有完整份切开分给大家每人拿一段。4.2 有什么用典型场景数据只在一个进程上需要分给大家并行处理和 Gather 成对Scatter 分出去算 → Gather 收回来作为更复杂通信的组成部分ReduceScatter ≈ Reduce Scatter它和 Broadcast 的关键差别Broadcast每人拿到一样的完整数据Scatter每人拿到不一样的一段数据4.3 在大模型推理 / vLLM 里主要用在哪4.3.1 先说结论单独的 Scatter 用得不多和 Gather、Reduce 类似概念重要但在 vLLM 推理热路径里很少单独调用scatter。更常见的是数据一开始就按 TP / DP / EP 切好放在各卡上不一定先集中再 Scatter真正高频出现的是 ReduceScatter、AllGather而不是纯 Scatter4.3.2 概念上会碰到的地方即使不直接调 Scatter API下面这些场景语义接近「切开分给各人」数据并行 / 输入准备一份 batch 按样本维切到不同 DP rank实现上未必走 NCCL Scatter词表 / 权重并行加载完整参数按列/行切到各 TP rank更多是加载与分片策略不一定是运行时 collective ScatterKV / 缓存类辅助路径个别 connector / 存储路径里会有 gather/scatter 风格的数据搬移例如按 block 分散写入语义是「整块拆开放到各处」但和训练课里的经典MPI_Scatter不完全同一层对读 vLLM 源码来说搜到大量torch.scatter时要注意——那经常是 Tensor 按 index 写入不是集合通信 Scatter。5 ReduceScatter5.1 是什么ReduceScatter规约散射 是一种多对多集合通信组里每个进程都有一份数据先按某种运算通常是SUM做全局规约再把规约结果切开每个进程只拿走其中一段。可以把它理解成两步合成一步ReduceScatter ≈ Reduce Scatter更直白一点先把大家的数据**加总或 max 等**成一份全局结果再把这份结果切成 N 块每人拿一块结束后不是只有 root 有完整结果那是 Reduce也不是每人手里都有完整结果那是 AllReduce而是每人手里有全局结果的一段和相近原语的区别操作结果形态Reduce规约后只有 root 有完整结果AllReduce规约后每人都有完整结果Scatter不做规约root 完整数据切开分发ReduceScatter先规约再切开每人一段AllGather每人一段 → 拼成完整份给每个人一句话先汇总再切开分给大家每人拿一段全局结果。5.2 有什么用典型价值省通信、省显存。如果后面每个 rank 本来就只需要用结果的一部分就没必要先 AllReduce 出完整份再自己chunkReduceScatter 直接让每人落到「自己那一段」通常更划算5.3 经典例子AllGather → 本地计算 → ReduceScatter用 Sequence Parallel TP 线性层Megatron 那套最直观。假设 2 卡序列长度 4按 token 切开GPU0 持有 token: [t0, t1]GPU1 持有 token: [t2, t3]① AllGather把输入拼齐后面计算需要完整序列输入时AllGather 后:GPU0: [t0, t1, t2, t3]GPU1: [t0, t1, t2, t3]这时输入齐了两边相同。② 本地计算例如 RowParallel 的局部 MatMul每张卡只用自己的权重分片去乘。输入虽完整权重却是 TP 切过的所以得到的是「完整 token 长度上的局部贡献」GPU0 算出: [y0_partial, y1_partial, y2_partial, y3_partial]GPU1 算出: [y0_other, y1_other, y2_other, y3_other]两边都是长度 4但不是同一份结果真正输出应是相加。一句话记AllGather 让输入变完整权重仍是分片的所以输出还要跨卡 reduce。③ ReduceScatter求和并散回各人 token 段归约后完整结果本应是:[y0_py0_o, y1_py1_o, y2_py2_o, y3_py3_o]ReduceScatter 后:GPU0 拿到: [y0, y1]GPU1 拿到: [y2, y3]5.4 在大模型推理 / vLLM 里主要用在哪5.4.1 Sequence Parallel / TP 优化就是上一节的模式用 ReduceScatter 替代「AllReduce 后再切」。vLLM 里例如部分 DeepSeek / sequence parallel MoE 路径会对hidden_states调用tensor_model_parallel_reduce_scatter(...)按 token 维散开后再进后续计算。5.4.2 Context ParallelCP/ PCPCP/PCP 也会用到reduce_scatter但比上面的线性层例子多一层细节attention 的局部输出往往不能直接当普通 sum常要先 AllGatherlse做校正再对校正后的贡献做 AllReduce / ReduceScatter。PCP 下 MoE combine 后也有get_pcp_group().reduce_scatter(hidden_states, dim0)这类用法语义仍是规约后只保留自己那段。5.4.3 算子融合MatMul ReduceScatter更进一步会把矩阵乘和 ReduceScatter 融合减少中间完整 tensor 的物化。vLLM / 编译路径里可见fused_matmul_reduce_scatter、fused_scaled_matmul_reduce_scatter6 AllReduce6.1 是什么AllReduce全规约 是一种多对多集合通信组里每个进程都有一份同形状数据按约定运算通常是SUM做全局规约结束后每个进程都拿到同一份完整的规约结果。可以记成AllReduce ≈ Reduce Broadcast或者AllReduce ≈ ReduceScatter AllGather更直白一点把大家的数据加总或 max 等成一份全局结果这份完整结果每人一份不是只给 root也不是每人只留一段6.2 有什么用典型场景就一个后面每个 rank 都要用这份全局结果继续算。TP 里各卡算出局部输出需要加总后每张卡都拿完整 hidden states 往下走需要全局一致的统计量计数、最大值、同步标记等训练里更出名的是梯度 AllReduce推理里同样高频只是对象变成激活/输出而不是梯度6.3 经典例子TP 下的 RowParallelLinear假设 2 卡做 Tensor Parallel某层输出要跨卡相加。GPU0 用权重分片算出: y_partial0 形状完整数值是半成品GPU1 用权重分片算出: y_partial1 形状完整数值是半成品真正结果: y y_partial0 y_partial1如果下一层每个 rank 都需要完整的 yAllReduce(SUM) 后:GPU0: yGPU1: y ← 两边相同、完整如果下一层其实只要 token 维上自己那一段Sequence Parallel更常见是ReduceScatter → 每人只留自己那段而不是AllReduce后再chunk。一句话权重分片导致输出是半成品 → 要 sum后面是否人人都要完整结果 → 决定用 AllReduce 还是 ReduceScatter。6.4 在大模型推理 / vLLM 里主要用在哪6.4.1 Tensor Parallelism最常见热路径vLLM 里大量调用tensor_model_parallel_all_reduce(...)典型位置包括RowParallelLinear等线性层局部 matmul 后 AllReduceVocabParallel embedding / 某些输出路径MoE 里 shared experts / 部分状态的跨 TP 归约个别 Norm / Mamba 等需要跨 TP 汇总统计量的地方这是推理里 AllReduce 出场最多 的原因TP 太常用且很多层算完后每张卡都要完整激活继续往下走。6.4.2 其它并行组上的同步除了 TP groupDP / CP 等组上也可能 AllReduce例如同步某种全局标量、内存水位、batch 相关信息CP 某些路径在校正后用 AllReduce 汇总 attention 贡献与上一章 RS 路径二选一语义仍是全员贡献 → 全员拿到同一份结果。6.4.3 Custom AllReduce知道有优化即可vLLM 还有custom_all_reduce、以及 ROCm 上的 aiter custom allreduce 等路径目标是在特定拓扑/消息大小下把 AllReduce 做得更快。7 AllGather7.1 是什么AllGather全收集 是一种多对多集合通信组里每个进程都有自己的一小段数据结束后每个进程都拿到所有人片段拼接而成的完整数据。可以把它想成「全组交作业而且每人手里都留一份完整合订本」发送方每个 rank 贡献自己那一段操作按约定维度拼接concatenate不是求和接收方所有人都有完整拼接结果7.2 有什么用典型场景当前各人只有分片但下一步计算需要看完整数据。输入/激活按 token 切开了Sequence Parallel某层需要完整序列特征/词表维被切开了后面要拼齐再算只想把分散片段收齐不做 sum7.3 经典例子接上章的 Sequence Parallel还是 2 卡、序列长度 4GPU0 持有: [t0, t1]GPU1 持有: [t2, t3]若下一层需要完整序列输入AllGather 后:GPU0: [t0, t1, t2, t3]GPU1: [t0, t1, t2, t3]注意这里只是把不同 token 拼齐没有把[t0,t1]和[t2,t3]加起来。和上一章串起来就是你已经熟悉的流水分片输入→ AllGather # 拼成完整输入此时相同→ 本地 MatMul # 用分片权重得到半成品→ ReduceScatter # sum 后只留自己那段或 AllReduce # sum 后每人保留完整结果一句话AllGather 解决「输入缺段、先拼齐」AllReduce / ReduceScatter 解决「输出是半成品、要跨卡求和」。7.4 在大模型推理 / vLLM 里主要用在哪7.4.1 Tensor Parallel / Sequence Parallel拼齐激活或中间结果vLLM 里常见tensor_model_parallel_all_gather(...)/tp_group.all_gather(...)各 TP rank 只有一部分激活下一计算需要完整维Sequence Parallel 下先 AllGather再进入需要完整 token 的层某些模型实现里对 Q/K、视觉 embedding、MoE 输出等做 all_gather相对 Gather推理热路径更常 AllGather因为通常每张卡后面都还要继续算。7.4.2 和 Gather 的取舍logits 那条线前面 Gather 章提过vocab 并行时可以把分片 logits Gather 到 rank0 采样。有些设备/路径会改成 AllGather让每张卡都有完整 logits以保证执行路径一致。只要 rank0 采样 → Gather 更合适每张卡都要完整 logits → AllGather7.4.3 Context Parallel / 多模态等CP/DCP 里可能 AllGather 较小的中间量如 LSE供后续校正多模态里视觉 embedding 在 TP 间 all_gather 后再送进语言模型这些都是同一语义本地只有一块先拼成全员可用的完整份。8 All-to-All8.1 是什么All-to-All全交换 是一种多对多集合通信组里每个进程都要给每个其他进程发一份通常不同的数据同时也从每个其他进程收一份。结束后每个人手里的数据都是「别人专门寄给自己的那些块」重新排好的结果。可以把它想成「全组互相寄快递而且寄给每个人的包裹内容可以不一样」不是 Broadcast不是把同一份通知复印给所有人不是 AllGather不是简单把各人片段拼成同一本合订本而是一对一、个性化交换——A→B 的内容和 A→C 的内容可以不同示意3 个 rank发送前每人本地按「寄给谁」排好块:Rank0: [给0, 给1, 给2]Rank1: [给0, 给1, 给2]Rank2: [给0, 给1, 给2]All-to-All 后每人拿到「别人寄给自己的」:Rank0: [来自0, 来自1, 来自2]Rank1: [来自0, 来自1, 来自2]Rank2: [来自0, 来自1, 来自2]一句话每个人给每个人寄不同的东西同时人人都在收。8.2 All-to-All 和 All-to-Allv基准表里常见两个名字名称含义alltoall发给每个对端的块大小通常整齐、一致或按固定规则等分alltoallvv varying发给/收到各对端的长度可以不同MoE 场景里不同 expert 收到的 token 数往往不一样所以工程上更常碰到 alltoallv 或等价的可变长 dispatch 实现。概念上仍属 All-to-All 家族不必单独再开一章。8.3 有什么用All-to-All 适合数据要按「目的地」重新洗牌而不是「大家对齐同一份」。最典型Expert ParallelismEP/ MoEtoken 根据路由结果发到持有对应 expert 的 rank某些并行布局变换按 head / 序列维做重排例如部分 DCP 路径用 all_to_all 做 combine一般的「个性化全交换」需求8.4 经典例子MoE 的 Dispatch / Combine假设 2 个 EP rank每卡负责一部分 expertRank0 负责 Expert 0,1Rank1 负责 Expert 2,3某步路由后Rank0 上的 token:tA → Expert2 应寄给 Rank1tB → Expert0 留在 Rank0Rank1 上的 token:tC → Expert1 应寄给 Rank0tD → Expert3 留在 Rank1Dispatch常用 All-to-All / alltoallv按「目标 expert 所在 rank」把 token 寄出去Rank0 最终本地要算的: [tB, tC, ...] ← 属于 Expert0/1 的 tokenRank1 最终本地要算的: [tA, tD, ...] ← 属于 Expert2/3 的 token各 expert 算完后再 Combine把结果按原 token 归属寄回同样是一轮交换/归约式回传具体实现可能是 alltoall、combine 内核等。一句话AllGather/AllReduce 是「对齐同一份结果」All-to-All 是「按目的地重新投递」。MoE 路由天然是后者。8.5 在大模型推理 / vLLM 里主要用在哪8.5.1 Expert Parallelism绝对主角vLLM 的 MoE 路径里EP 通信常被统一叫 all2all backend例如DeepEPhigh throughput / low latencyflashinfer / nixl 等其它 alltoallv 实现以及更朴素的 naive dispatch/combine代码里常见的是dispatch/combine先把 token和 routing 信息发到对应 expert 所在 rank算完再收回。你在日志、配置里看到的--all2all-backend ...deepep_high_throughputEP all2all timeout / fault说的基本都是这一层不是 TP 里的 AllReduce。8.5.2 其它DCP 等布局重排例如 Decode Context Parallel 的某些 backend会用all_to_all做 attention 部分结果的交换与合并作为 AllGatherReduceScatter 路线的替代实现。对博客主线记住一句即可All-to-All 不只服务 MoE但在大模型推理里MoE EP 是它最高频、最值得优先理解的场景。
返回列表