想象一家五星级酒店的后厨,突然接到一张夸张的订单:做一整个 1024 层的千层蛋糕。主厨把蛋糕切成八份,分给八位厨师同时制作。问题来了——蛋糕每一层的奶油量、水果量、坚果量都不同,有的层厚实难做,有的层薄如纸张;再加上厨师手速有快有慢,烤箱功率也有高有低。结果快手早早收工,只能叉腰看着慢手加班,整张蛋糕要等最慢的那位做完才能组装上桌。这就是“负载不均”。 大模型训练里的张量并行,和这个后厨故事几乎一模一样:GPU 就是厨师,模型的大矩阵就是巨型千层蛋糕。把矩阵切分到多张 GPU 上并行计算,如果切分和调度不合理,就会出现“有的卡忙着算、有的卡闲着等”的尴尬局面,白花花的算力被浪费。本文会用这个千层蛋糕厨房贯穿始终,把负载不均的原因、计算均衡分配、通信均衡策略、切分调优、并行度选择、工程实践以及常见误区一次讲透。
对 AI 从业者而言,掌握负载均衡策略,意味着你负责的多卡训练能从“总有人摸鱼”变成“全员同步收工”,GPU 利用率提升 20%-50%,省下的都是预算和生命。
可视化演示
动态演示张量并行负载均衡策略的核心机制,通过入门/进阶/实战/优化四种模式展示关键概念与交互流程。
本节配有交互动效(进入视口后自动加载,约 3KB)。
张量并行负载均衡策略:负载不均 负载不均的根源与分类 计算量均衡分配方法 核心机制可视化 张量并行负载均衡策略整体架构与关键组件
负载不均成因
厨房里,八位厨师领到了同样大小的蛋糕块。乍一看很公平,但每一块内部奶油、水果和坚果的分布天差地别。有的层夹着厚厚的水果,要一颗颗摆整齐;有的层只有薄薄一层奶油,抹两下就完事。于是工作量大的厨师忙得满头大汗,工作量小的厨师早早站在一边喝咖啡。整个蛋糕上桌的时间,永远由最慢的那位决定——这就是后厨的“木桶效应”。
把镜头切到 GPU 集群,道理完全相同。张量并行把大矩阵切成若干子块分给多张卡。矩阵不同区域的非零元素密度、算子复杂度都不一样,天然就有“厚层”和“薄层”;再加上集群里可能混着 A100、A800、4090 等不同算力的卡,快卡等慢卡的现象被进一步放大。通信也会掺和一脚:如果某张卡总是转发别人的数据,它就成了新的瓶颈,形成长尾延迟。
为了量化这种忙闲不均,我们引入 GPU 利用率的概念:让 N 张卡并行工作,每张卡实际有效计算时间为 \(T_i\),真正能跑完一轮的总耗时却是最慢卡的完成时间 \(T_{\max}\)。那么利用率可以写成:
主厨要救场,第一步不是急着调整蛋糕配方,而是先盯住监控屏找出“谁最晚放下锅铲”。GPU 也是一样,定位到瓶颈卡,才能谈如何均衡。
- 分子的总和把 N 张 GPU 各自真正用于计算的时间累加,代表团队实际产出的总工作量。
- 分母的乘积N 张卡乘以最慢卡的完成时间,等于整个团队在最慢节奏下消耗的总墙钟时间。
- 两者相除有效工作时间占比就是利用率,也是负载是否均衡的第一观察指标。
计算量均衡
发现平均分不公平后,主厨换了思路:给手速快、工具好的厨师多分几层奶油厚的,给动作慢的厨师少分几层薄的。任务单不再追求“每个人拿一样多”,而是“每个人都在差不多的时间收工”。这个朴素的逻辑,正是负载均衡的核心。
在张量并行中,对应动作是“按算力加权分配工作量”。每张 GPU 有自己实测出来的算力,比如相对速度 \(P_i\)。总工作量 \(W_{\text{total}}\) 不该被 N 整除,而应该按每张卡算力占全体算力的比例来分:
主厨每周都会重新测一次厨师们的工作速度,再更新任务单。训练集群也一样,每次跑大任务前做一次微基准测试,算力分配表就能常保持新鲜,这一步是所有后续调优的地基。
- 算力求和先统计所有 GPU 算力的总和,作为分配比例的基准。
- 能力占比用某张卡的算力除以总算力,得到它在团队中应该承担的工作比例。
- 乘以总量用这个比例乘上总工作量,就得到该卡应分配的计算子块大小。
- 动态校准算力最好通过实际 benchmark 获得,因为理论峰值和真实能达到的算力往往两回事。
通信均衡策略
蛋糕块分得再均匀,最后总要把各块拼成一个整体。拼的时候需要传递奶油、水果、托盘,如果所有厨师都挤同一个窗口,传菜口瞬间堵死。你可能会想:那多开几个窗口不就好了?但每多一个窗口,就要多派人手,而且高峰期依然有人闲着等料。后厨的瓶颈,有时候不在做蛋糕,而在传蛋糕。
张量并行里也有一模一样的“传菜口”:每步计算完,各 GPU 要执行 AllReduce 等集合通信,把各自的中间结果汇总再分发。通信开销由三部分决定:要传的数据量 \(V\)、网络带宽 \(B\)、以及发送次数 \(r\)。每次通信都有固定的启动延迟 \(L\),于是通信耗时可以写成:
主厨后来发现,只要让不同厨师错峰去传菜窗口,别一窝蜂挤在同一个时间段,传菜口的拥堵就消失了。通信均衡的本质,不是“不传菜”,而是“大家都有菜可传、又都不堵车”。
- 数据量除以带宽把要传的蛋糕原料总量除以传输通道的速度,得到纯搬运时间。
- 延迟乘轮数每次启动通信都有固定握手延迟,轮数越多,额外耗时越多。
- 两者相加通信总耗时等于搬运时间加上启动开销,任何一项过大都会拖慢整体。
- 分桶优化把大块数据拆成多个小桶排成流水线发送,能掩盖部分启动延迟,让各卡通信量更均衡。
切分策略调优
蛋糕应该横切成大块,还是竖切成细条?横切的话块数少,厨师之间要传递的切面也少,但每块依旧很大,并行度有限;竖切的话能分给更多人,可每一条都要和其他条交换奶油和水果,传菜次数急剧增加。主厨揉着太阳穴感叹:切法没有绝对好坏,全看这块蛋糕“耐不耐烦等传菜”。
张量并行中的行切分与列切分就是这个选择。权重矩阵可以按行切(类似横切层)也可以按列切(类似竖切条),切分粒度决定了并行度与通信量的比值。为了科学决策,我们定义一个计算通信比:
主厨的经验是:先尝一口蛋糕,判断它是“耐放型”还是“易化型”。耐放型可以大卸八块慢慢做;易化型必须少切快拼。你的模型是哪种类型,跑一次 profile 就能心中有数。
- 计算时间\(T_{\text{calc}}\) 是单张卡执行本地矩阵乘等计算所花的时间。
- 通信时间\(T_{\text{comm}}\) 是同一张卡等待和参与 AllReduce 所花的时间。
- 计算比值两者相除得到 \(\Gamma\),大于 1 表示计算主导,小于 1 表示通信主导。
- 拓扑匹配机内 NVLink 带宽高、延迟低,允许更细切分;跨机网络慢,则应减少切分。
并行度权衡
主厨后来又犯过愁:是不是厨师越多越好?他把厨房从 4 人加到 10 人,结果发现效率反而下降了——灶台只有四个,新来的厨师挤来挤去,传菜通道也乱了,互相绊手,出餐比之前还慢。厨房的空间和传菜通道是有限的,这就是协作的代价。
张量并行同样有“最佳人数”。增加并行度 N,每张卡分到的计算量确实变少了,但通信开销会随着 N 增大而上升;负载不均造成的空闲等待通常也会更明显。因此总训练时间可以建模成三个部分之和:
真正的主厨会综合考虑灶台数量、人手和传菜口,而不是盲目堆人。工程上,张量并行度也常与数据并行度、流水并行度搭配,例如 64 卡下选 TP=4、PP=4、DP=4 的组合,而不是 64 卡全做张量并行。
- 计算项卡数越多,每卡要算的矩阵块越小,这一项单调下降。
- 通信项卡数越多,AllReduce 环越长、交换次数越多,这一项单调上升。
- 空闲项切分不均时快的卡等慢的卡,这一项随 N 增大往往加剧。
- 取最小值对 N 做扫描,找到 \(T_{\text{total}}\) 最小的那个值。
工程实践要点
开业之后主厨依然不轻松,因为每位厨师的效率会波动:今天有人手快,明天有人状态差;奶油用完要补货,传菜口偶尔还会堵。所以他装了摄像头,盯着后厨的实时画面:谁在玩手机、谁在拼命赶工,发现问题立刻临时调拨人手。
真实的训练集群也需要这样一双眼睛。模型不同层的计算密度不同、序列长度动态变化、特殊算子只在某张卡上出现,这些都会让负载漂移。因此工程实践的第一步是定义负载均衡度指标,用最快卡与最慢卡的完成时间比来衡量忙闲差距:
主厨每晚收工后都要看“谁最晚放下锅铲”的复盘记录,然后修改第二天的任务单。训练工程师也应在每个训练阶段后检查 profiler 报告,把负载均衡度纳入常规迭代节奏,而不是出了问题才想起它。
- 最快卡耗时记录本轮最早完成的那张卡的耗时。
- 最慢卡耗时记录本轮最后完成的那张卡的耗时。
- 两者比值LB 越接近 1,说明忙闲程度越同步。
- 阈值判断LB < 0.8 时启动排查流程,检查切分比例、通信分桶、拓扑布局等参数。
常见误区辨析
后厨来了一批新厨师,他们有三个常见误解:第一,“每人分一样多就是公平”;第二,“人多一定更快”;第三,“只要把传菜速度提上去,菜就不会等”。结果每次考核都栽跟头。这些误区在 GPU 世界里也同样遍布。
理解这些误区,最好用一个同时惩罚“计算不均、通信开销、扩展损耗”的并行效率公式。假设单卡完成一轮耗时 \(T_1\),N 卡理想并行时每卡应耗时 \(T_1/N\),而实际由最慢卡决定的总耗时为 \(T_{\max}\),那么:
这组公式就像后厨的“总出餐效率”:不看每人分到多少盘子,只看最后一桌菜几点上齐。平均分配、盲目加人、无视通信,这些直觉的坑,都要靠数据指标来填平。
- 单卡基准耗时先得到单张 GPU 完成一轮完整计算的耗时。
- 理想并行耗时假设 N 卡完美切分且无通信开销,每卡应耗时。
- 实际最慢耗时真实训练中由最慢的卡决定本轮结束时间。
- 效率比值E 越小,说明负载不均或通信开销越大,调优空间也越大。
AI 应用场景
大模型训练中的 Megatron 张量并行
阶段:模型训练(分布式并行计算)
解决的问题:用 8 卡训练 70B 模型时,权重矩阵被切成 8 份。如果机械地按层平均切,某些卡总是先算完,GPU 利用率只有 40% 左右。负载均衡策略按各卡实测算力分配切分比例,并把 AllReduce 数据分桶错峰发送,让每张卡几乎同时完成每一层的计算。
具体案例:某团队用 16 卡训练 13B 模型,发现第 5 卡永远是瓶颈。排查发现某些算子只在特定卡上执行,于是将张量并行度从 8 调整为 2×4,并开启通信与计算重叠,训练吞吐提升约 30%。
LLM 推理服务动态调度
阶段:模型推理部署
解决的问题:推理时请求长度长短不一,有的请求几百 token,有的几千 token,负载像后厨高峰期的点单一样抖动。如果不加控制,短请求卡在慢卡后面,P99 延迟飙升。利用负载均衡度指标将长请求路由到算力强的卡、短请求发给算力弱的卡,并动态调整批处理窗口。
具体案例:一个 8 卡 vLLM 推理服务,prompt 长度从 128 到 4096 混合。采用按算力加权调度 + 连续批处理后,P99 延迟降低 28%,GPU 平均利用率提升约 20%。
混合并行资源规划
阶段:训练集群资源配置
解决的问题:面对 64 卡集群,要决定每张卡扮演什么角色:张量并行、流水并行还是数据并行。就像主厨决定谁切蛋糕、谁做奶油、谁负责传菜。如果全做张量并行,通信会成为灾难;全做数据并行,单卡显存放不下大模型。
具体案例:训练 175B 模型时对比 TP=8/PP=8/DP=1 与 TP=4/PP=4/DP=4 两组配置。后者因张量并行通信开销更小、各卡负载更均衡,有效算力提升约 18%。
Python 演示
# -*- coding: utf-8 -*-def calc_work(W_total, capacities): total = sum(capacities) return [W_total * c / total for c in capacities] def sim_time(work_loads, speeds): return [w / s for w, s in zip(work_loads, speeds)] def lb_ratio(times): return min(times) / max(times) def report(name, times): print(name, "各卡耗时:", [round(t, 2) for t in times]) print(name, "负载均衡度:", round(lb_ratio(times), 3)) print(name, "总耗时:", round(max(times), 2)) def main(): W_total = 1000.0 capacities = [1.0, 0.8, 1.2, 1.0] n = len(capacities) even_work = [W_total / n] * n weighted_work = calc_work(W_total, capacities) report("平均分配", sim_time(even_work, capacities)) report("按算力分配", sim_time(weighted_work, capacities)) if __name__ == "__main__": main()
def calc_work(W_total, capacities):实现按算力比例分配工作量的核心函数,对应正文中的加权公式。total = sum(capacities)先求出所有 GPU 的算力总和,作为分配基准。return [W_total * c / total for c in capacities]每张卡的算力占比乘以总工作量,得到各自的任务量。def sim_time(work_loads, speeds):计算每张卡完成自己任务所需的时间,即工作量除以算力。def lb_ratio(times):用最快卡与最慢卡耗时之比计算负载均衡度 LB,越接近 1 越好。even_work = [W_total / n] * n构造一个“平均分配”的对照组,用来凸显差异。if __name__ == "__main__":标准入口,保证代码可直接运行,也可以作为模块被导入。
常见误区
误区我以为只要把矩阵平均切成 N 块,每卡拿一样多数据,就是均衡了。可为什么我 4 卡跑训练,还是有一张卡一直在等?
正解平均分配只保证“数据量”相等,不保证“完成时间”相等。张量并行的目标不是分得一样多,而是全体 GPU 在同一时刻收工。好比千层蛋糕,快手和慢手拿同样厚度的层,快手早就干完等别人。正确做法是按算力加权分配,再结合通信开销微调,让各卡完成时间趋于一致。
为何常见:初学分布式时,直觉上“公平 = 平分”;且训练框架默认切分往往就是均匀的,容易让人误以为这就是均衡。
误区卡越多越好,从 4 卡加到 8 卡不是应该快一倍吗?为什么我实测反而更慢了?
正解总耗时 = 计算 + 通信 + 空闲等待。增加并行度 N 时,每卡计算量下降,但 AllReduce 等通信开销和负载不均造成的等待也会上升。N 超过某个点后,通信成为主导,训练反而变慢。就像厨房 3 平米里再加 5 个人,转个身都难。要用效率公式判断是否划算。
为何常见:“人多力量大”的日常经验忽略了协作成本;分布式系统的扩展损耗在直观上反直觉。
误区只要把计算和通信重叠起来,通信就不耗时了,负载均衡问题就解决了。
正解重叠只是把通信的时间“藏”进计算里,并没有减少通信本身占用的带宽和处理资源。当通信量超过网络能力,依然会排队。更准确的目标是“通信均衡 + 尽量重叠”:减少通信轮数、分桶发送、让不同卡在不同时段通信,避免同时挤占带宽。就像后厨错峰传菜,不代表不用传菜。
为何常见:很多教程强调“通信与计算重叠”是高级优化手段,学习者容易把它神化成万能解药。
误区每卡计算时间都一样了,负载应该均衡了吧?为什么监控图里还有某张卡明显在等?
正解负载均衡必须同时看计算和通信。如果通信数据总要从 0 号卡转发,0 号卡就会成为热点,整体随之变慢。计算均衡 + 通信热点的双重瓶颈,LB 指标只能发现“不均衡”,还需要 profiler 定位是计算不均还是通信热点,再针对性优化。好比蛋糕分得再均匀,所有厨师都从同一个窗口取水果,窗口照样堵。
为何常见:初学并行时关注计算切分,通信被认为是“框架自动处理”的黑盒,直到踩坑才意识到通信也有瓶颈。
误区把切分方案定好,训练过程中就不用管了,负载自然会一直均衡。
正解模型不同层的计算特征、序列长度、batch 大小都会让负载漂移;某些特殊算子只在特定卡上出现。需要监控工具持续观测,必要时动态调整切分比例或调度策略。就像主厨不能只在开业前定好任务单,高峰期要随时调拨人手。工程上常用 profiler 定期采样 + 自动化调参。
为何常见:框架的静态策略是默认主流,且调优成本高,让人误以为“设置一次就万事大吉”。
面试题
Q1. 张量并行中最常见的负载不均原因是?
- A.各卡显存速度不一致
- B.各卡分到的计算量不同← 正确答案
- C.各卡型号完全一样
- D.各卡驱动版本落后
答案:B。负载不均的根本原因是各卡拿到的计算任务量不同,加上算力差异,导致完成时间错开。显存速度、驱动版本虽有影响,但不是最常见的主因。就像千层蛋糕切块一样,分到厚层和薄层的厨师完成时间自然不同。
Q2. 负载均衡度 LB=T_min/T_max 越接近 1 说明?
- A.最慢卡与最快卡耗时越接近← 正确答案
- B.各卡显存占用越平均
- C.通信带宽利用率越高
- D.训练损失下降越快
答案:A。LB 是最快卡耗时除以最慢卡耗时,比值越接近 1,说明快慢差距越小,负载越均衡。它反映的是完成时间的一致性,与显存、带宽、损失收敛无关。
Q3. 四卡算力分别 1、2、3、4,总工作量 100,按算力加权的分配方式是第 3 张卡应分到?
- A.约 30← 正确答案
- B.约 20
- C.约 40
- D.约 25
答案:A。算力总和为 10,第 3 张卡算力为 3,占比 3/10,乘以总工作量 100 得到 30。按算力加权会让快卡多干活,慢卡少干活,从而拉齐完成时间。
Q4. 通信时间公式 T_comm = V/B + L×r 中,r 直接代表?
- A.通信轮数← 正确答案
- B.数据总量
- C.网络带宽
- D.并行卡数量
答案:A。r 是通信往返的次数,即通信轮数。V/B 表示纯搬运时间,L×r 表示固定启动延迟的总和。想要降低 r,可以增大单次通信的数据块,减少拆分次数。
Q5. 四卡负载均衡度为 0.5 表示?
- A.最慢卡耗时是最快卡的两倍← 正确答案
- B.最快卡耗时是最慢卡的两倍
- C.每张卡均有一半时间空闲
- D.通信时间超过总时长的一半
答案:A。LB=T_min/T_max=0.5,说明最快卡耗时只有最慢卡的一半,即最慢卡耗时是最快卡的两倍。这是负载不均的典型表现,会造成约一半的算力空转。
Q6. 导致张量并行负载不均的因素有哪些?
- A.矩阵切分粒度不均匀← 正确答案
- B.异构GPU算力差异← 正确答案
- C.通信热点集中在某卡← 正确答案
- D.训练集类别比例失调
答案:ABC。切分粒度不匀导致各卡计算量不同,异构 GPU 导致同样工作耗时不同,通信热点会让某卡额外等待。训练集类别比例是数据层面的问题,与张量并行切分负载无关。
Q7. 以下哪些做法能改善通信均衡?
- A.AllReduce分桶发送← 正确答案
- B.通信与计算重叠← 正确答案
- C.简单增大学习率
- D.调整并行卡拓扑← 正确答案
答案:ABD。分桶发送可缓解启动延迟,通信与计算重叠让通信不再独占时间线,调整拓扑可让带宽分布更均匀。增大学习率不改变通信模式,无法改善通信均衡。
Q8. 某卡计算通信比 Γ=T_calc/T_comm=0.2,最合适的策略是?
- A.再细切分增大并行卡数
- B.减少切分或优先优化通信← 正确答案
- C.加大batch size训练
- D.忽略通信只算计算
答案:B。Γ 远小于 1,说明通信时间远超计算时间,通信是主要瓶颈。此时再细切分只会增加通信量,正确做法是减少切分、增大块粒度,或优先优化通信链路。
Q9. 确定最优张量并行度 N 时需权衡?
- A.每卡计算量随N下降← 正确答案
- B.通信开销随N上升← 正确答案
- C.负载不均随N加剧← 正确答案
- D.显存总量随N下降
答案:ABC。N 增大,每卡分到的计算量变小,但通信链路变长、交换次数变多,切分粒度变细也可能加剧不均。显存总量随卡数增加而增加,并不会下降。
Q10. 并行效率 E = (T_1/N)/T_max 中,影响 E 的关键因素是?
- A.最慢卡实际耗时与理想耗时差距← 正确答案
- B.训练数据总大小的变化
- C.模型参数量的规模大小
- D.学习率初始值的设定
答案:A。E 的分子是理想并行下的每卡耗时,分母是最慢卡实际耗时。两者差距越大,E 越低,说明负载不均和通信开销越严重。数据大小、模型规模和学习率都直接改变 T_1,但不会直接决定理想与实际之间的差距。