小区要办一场百家宴,四百户人家各做了一道拿手菜。菜做好后不能散着放,得拼成一桌完整的宴席,每个人才知道最终该按什么菜谱办事。分布式训练里,“每户人家”就是一张GPU显卡,“拿手菜”就是它根据自己看到的那批数据算出的梯度。问题是:几百张卡的菜,怎么拼最快? 有人提议围成一圈传菜,各家把菜切块递给邻居,边传边拌,最后人人手里都有一份完整配方——这是Ring All-Reduce;有人提议先四户凑一桌,再让代表把菜端到更大的桌,逐级汇总成金字塔,最后再逐级分下去——这是Tree All-Reduce;还有人干脆请一位总厨坐镇,各家把菜端进中央厨房,由总厨调配好再分发——这是参数服务器。 选错传菜方式,再快的厨师也要干等;选对了,几百张卡也能像一个人那样步调一致。这篇文章就用这场百家宴,把梯度聚合的原理、三种主流方案和通信提速的窍门一次讲明白。

岗位关联

理解梯度聚合,是看懂分布式训练通信开销、优化大模型训练吞吐的第一道门槛,也是AI工程师从“单卡调参”走向“集群训练”的必经之路。

目录
  1. 可视化演示
  2. 1. 梯度聚合的由来
  3. 2. 同步与异步训练
  4. 3. Ring环形接力算法
  5. 4. Tree树形归并算法
  6. 5. 参数服务器架构
  7. 6. 通信优化三板斧
  8. 7. 工程实践要点
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示Ring All-Reduce环形聚合、Tree All-Reduce树形聚合与参数服务器三种梯度聚合方式的拓扑结构与数据流。

本节配有交互动效(进入视口后自动加载,约 3KB)。

Ring All-Reduce环形聚合 GPU排成环形拓扑,梯度沿环传递 带宽最优利用,通信量与GPU数无关 Bandwidth = O(N/K) optimal NVIDIA NCCL库高效实现

1. 梯度聚合的由来

小区要办百家宴,四百户人家各自做了拿手菜。但每户做的不是一道完整的菜,而是这道菜的一个“侧面”——有人负责调味、有人负责火候、有人负责摆盘,只有把这些侧面拼起来,才凑得出真正的一桌宴席。分布式训练里的数据并行,就是这样分工的。

数据并行(Data Parallelism)的做法很直白:每张GPU上都复制一份完整的模型权重,但只喂给它整个训练数据的一个切片。GPU把切片跑一遍正向传播得到损失,再反向传播得到梯度 g_i。因为每个GPU看到的只有 1/N 的数据,它算出来的梯度相当于盲人摸象——只摸到一条腿,就以为大象是柱子。这个“局部梯度”只有和其他 N-1 份加起来取平均,才能还原出全局的方向。

这个“加起来取平均”的动作,就是梯度聚合。它发生在每一轮参数更新之前,是一个全集群的集体操作:N 张卡的梯度张量形状相同,逐元素相加、除以 N,得到平均梯度。用数学写出来就是:

回到百家宴:聚合这口大锅,把四百户的“侧面”精准地拼成完整宴席。没有这一步,每户都按自己那点片面的经验改菜谱,整桌菜早就乱了套。理解了这个“拼菜”动作,我们再来看怎么拼得又快又好——三套传菜方案正在候场。

gˉt=1N∑i=1Ngi(t)\bar{g}_t = \frac{1}{N}\sum_{i=1}^{N} g_i^{(t)}
这一步相当于把四百户人家的菜倒进同一口大锅,拌匀后再分成四百份,每户按同一份配方去改进自己的手艺。
  1. 局部梯度第 t 轮中第 i 张 GPU 反向传播得到的梯度,形状与模型参数一致——这是第 i 户端来的拿手菜。
    gi(t)g_i^{(t)}
  2. 全体求和把 N 张卡的梯度逐元素相加,混合成“总梯度”——四百户的菜都倒进同一口大锅。
    ∑i=1Ngi(t)\sum_{i=1}^{N} g_i^{(t)}
  3. 求平均总梯度除以 N,还原每个 GPU 本应看到的平均方向——一锅菜分给 N 户人家,大家各取一份。
    gˉt=1N∑i=1Ngi(t)\bar{g}_t = \frac{1}{N}\sum_{i=1}^{N} g_i^{(t)}

2. 同步与异步训练

宴席有两种开法:一种要等所有人家都到齐、所有菜都端上桌,才统一开席;另一种先到先吃,谁端来菜就先尝谁的手艺。分布式训练里的同步与异步,正是这两种开法的翻版。

同步训练(Synchronous SGD)要求每轮迭代中,所有 GPU 都完成自己的前反向计算,然后集体做一次梯度聚合,等聚合结果到手,大家再齐步更新参数。步子整齐,每一步都基于完整 batch 的统计信息,收敛路径稳定、结果可复现。代价是只要有一张卡掉队,全体都得等它——宴席上最慢的那位客人,决定了所有人动筷的时间。这一轮的参数更新可以写成:

异步训练则像自助餐:GPU 算完自己的梯度就立刻推给中心节点,参数马上更新,其他 GPU 随时拉取最新参数继续算,谁都不等谁。吞吐高,但“过时的梯度”和“正在改的参数”同时存在,像边吃饭边改菜单,味道容易跑偏。为此工业界常用半异步——限时等待,掉队超过一定时长就先用现有梯度继续。同步求稳、异步求快,选择取决于集群规模和训练阶段。

wt+1=wt−η⋅gˉtw_{t+1} = w_t - \eta \cdot \bar{g}_t
单个 GPU 只能基于自己那 1/N 的数据给参数提建议,平均梯度才是大家公认的修改方向。
  1. 当前参数第 t 轮开始时的模型权重——宴席当前的菜单。
    wtw_t
  2. 聚合梯度本轮所有 GPU 平均后的梯度——大家共同认可的改进方向。
    gˉt\bar{g}_t
  3. 学习率η 控制每次更新的步子大小,步子太大容易走出好味道,太小又迟迟学不到。
    η∈(0,1)\eta \in (0, 1)
  4. 参数更新让菜单沿梯度反方向挪一步,完成本轮学习。
    wt+1=wt−η⋅gˉtw_{t+1} = w_t - \eta \cdot \bar{g}_t

3. Ring环形接力算法

如果不想请总厨、也不愿让所有人去广场排队,宴席还有一种更聪明的传法:八户人家围着圆桌坐好,每人把自己那份菜切成八小份。第一轮,每户把自己的一小份菜递给右边邻居,同时接过左边邻居递来的菜倒进自己碗里。下一轮,再把刚收到的菜接着往右传。就这样转七圈,每个碗里都混进了所有人的配方。

这就是 Ring All-Reduce 的基本画面。梯度张量被切成 N 块(N 就是 GPU 数量),整个聚合成两个阶段:先做 scatter-reduce(分块归并)——N-1 轮传递中,每个节点每轮把第 (i-k) 块传给下一个节点,同时从上一个节点收到一块并累加;N-1 轮后,每个节点恰好持有“某一块”在所有 GPU 上的累加和。再做 all-gather(全量收集)——把这个归并好的块继续沿环传 N-1 轮,每轮覆盖而不是累加,最终每个节点都拥有一整套块的完整和。

每一步,每个节点收发 D/N 的字节,两个阶段共 2(N-1) 步,总时间近似为:

当 N 变大时,(N-1)/N 趋近于 1,总时间趋近于 2D/B——与 GPU 数量几乎无关!这才是 Ring 碾压“单点汇聚”的根本原因:所有节点同时收发,没有人闲着。这就是为什么 NCCL、Horovod 这些主流通信库,都把 Ring 作为 GPU 间 All-Reduce 的主力实现。

Tring=2(N−1)⋅DN⋅BT_{ring} = 2(N-1)\cdot\frac{D}{N\cdot B}
传菜总量不会因为户数变多而膨胀——这是环形接力的灵魂。
  1. 总数据量D 是梯度张量的总字节数,比如大模型的梯度可达几百 MB——整桌菜的总量。
    DD
  2. 分块把梯度切成 N 份,每份 D/N——每家每次只端一小份传菜,端起来不累。
    DN\frac{D}{N}
  3. 链路带宽B 是单条网络链路每秒能传的字节数——传菜通道的宽度。
    BB
  4. 总时间两个阶段共 2(N-1) 轮,每轮传 D/N 字节,得到总通信时间。
    Tring=2(N−1)⋅DN⋅BT_{ring} = 2(N-1)\cdot\frac{D}{N\cdot B}

4. Tree树形归并算法

另一种传菜思路是金字塔:四户人家先把菜凑成一小桌,小桌的代表端着一盆混合菜去上一级,和隔壁小桌的代表再凑一桌,如此逐级往上,最后宴席总厨手里有了一盆汇集四百户配方的浓汤。然后浓汤从塔尖逐级分下去,每一级都把配方复制给下一级,最终人人手里都拿到完整菜谱。

这就是 Tree All-Reduce:前半程叫 Reduce,叶子节点两两把梯度发给父节点,父节点逐元素相加后继续向上传,直到根节点拥有全量梯度总和;后半程叫 Broadcast,根节点把总和广播给所有子节点,逐级复制,直到每个叶子都拿到完整总和。树的层数等于 log₂N,所以传输次数是 O(log N) 级别。忽略不同层级的带宽差异,总时间约为:

与 Ring 相比,Tree 的并行度集中在树的每一层,延迟更低,但根节点要承载全量 D 的收发,很快成为带宽瓶颈;而 Ring 把负载摊到每个节点,带宽利用率更高。现代框架常把两种方案混合:机内用 Ring,机间再叠一棵 Tree,各取所长。

Ttree=log⁡2N⋅DBT_{tree} = \log_2 N \cdot \frac{D}{B}
树的层数只与户数取对数,但每一层都要完整传一大盆,树根的压力最大。
  1. 树高N 个节点两两归并,需要的层数——几层楼就能把菜汇总到塔尖。
    log⁡2N\log_2 N
  2. 单层传输树每层要传一整份梯度 D,耗时 D/B——每层端一大盆菜上楼。
    DB\frac{D}{B}
  3. 总时间层数乘以单层耗时,得到对数级的总通信时间。
    Ttree=log⁡2N⋅DBT_{tree} = \log_2 N \cdot \frac{D}{B}

5. 参数服务器架构

最省心的传菜法其实是请一位总厨坐镇中央厨房:各家的菜直接端进厨房,总厨把所有的菜混匀、定好最终的配方,再通知各家来领。所有决策都在这位总厨的掌握之中,简单直接。

参数服务器(Parameter Server,简称 PS)就是这个中央厨房。一组合计节点(PS 节点)负责保存模型参数、累加梯度、执行更新;一群计算节点(worker)只负责前向和反向计算。worker 把算出的梯度 push 推给 PS,PS 做聚合更新,worker 再 pull 拉取最新参数。扩展时可以把参数切分到多个 PS 节点上分担压力,这叫参数分片。PS 在下一次发给 worker 之前,把本轮所有 push 来的梯度做一次平均,更新量写成:

PS 最大的好处是天然支持异步:谁先推来梯度就先更新,不必等所有 worker 到齐,这对推荐系统里海量稀疏特征的在线学习特别友好。坏处也很明显:所有梯度都涌向中心节点,通信量随 worker 数线性增长,中央厨房的传菜通道早晚会堵。宴席规模一大,就得靠分片甚至改用环形流动来缓解。

wt+1=wt−η⋅1N∑i=1Npushi(t)w_{t+1} = w_t - \eta\cdot\frac{1}{N}\sum_{i=1}^{N}\text{push}_i(t)
push 是端菜进厨房,pull 是领新配方,总厨(PS)掌控全局。
  1. 推送梯度第 i 个 worker 在第 t 轮推送给 PS 的梯度——第 i 户端来的菜。
    pushi(t)\text{push}_i(t)
  2. 聚合平均PS 把所有 push 来的梯度相加再除以 N,得到本轮更新量——总厨把所有菜混匀分份。
    1N∑i=1Npushi(t)\frac{1}{N}\sum_{i=1}^{N}\text{push}_i(t)
  3. 更新参数PS 按学习率缩放后更新参数,等待 worker 下次 pull——总菜单更新完毕。
    wt+1=wt−η⋅1N∑i=1Npushi(t)w_{t+1} = w_t - \eta\cdot\frac{1}{N}\sum_{i=1}^{N}\text{push}_i(t)

6. 通信优化三板斧

菜做得再快,传菜通道只有那么宽,怎么办?老厨子有经验:把菜熬成浓汤再传,省地方;几道小菜攒成一罐再端,省趟数;锅还在炒着,手里的这盘已经递了出去——时间重叠,省等待。

第一招是梯度压缩。梯度占用的字节数可以直接缩水:FP32 换成 FP16 或 BF16,通信量减半;再激进一点用 INT8,减到四分之一。更聪明的 TopK 稀疏化,每轮只传绝对值最大的 k% 梯度元素,其余当零处理,配合把舍弃部分累积到下一轮的技巧,精度损失极小。压缩后的通信量写成:

第二招是梯度累积:与其算一步传一次,不如算好几个 micro-batch,把梯度先累加在本地,攒到 K 步再做一次 All-Reduce。通信频率降为原来的 1/K,但等效 batch 变大了,学习率也要配合调整。第三招是通信与计算重叠:反向传播本身按层计算,梯度一层一层冒出来,PyTorch 的做法是把梯度分桶,每凑满一桶就立刻启动这个桶的 All-Reduce,让通信藏在下一层计算的时间里。三招合起来,相当于既把菜熬浓、又攒盒装、还边走边端,往往能省下一半以上的训练时间。

D′=γ⋅DD' = \gamma \cdot D
压缩比越大,浓缩汤料越少占地方,但要注意别把关键味道也丢了。
  1. 原始流量D 是未压缩的梯度通信量——一大盆菜。
    DD
  2. 压缩比γ 表示压缩后体积占原始的比例,FP16 的 γ≈0.5——浓缩汤料的浓度。
    γ∈(0,1]\gamma \in (0, 1]
  3. 压缩后流量两者相乘得到实际的通信量。
    D′=γ⋅DD' = \gamma \cdot D

7. 工程实践要点

前面聊的都是“怎么传”,真到办一场几百桌的宴席,还要看场地怎么摆、人手怎么配、出了岔子怎么救。工程实践解决的就是这三个问题。

拓扑选型上,单机多卡走 NVLink 带宽极高,用 Ring 最合适;跨机走 InfiniBand 或以太网,延迟明显抬高,通常采用分层结构——机内先做一轮 Ring 归并,机间再用 Tree 或高层次 Ring,把慢速跨机链路上的数据压缩到最少。混合精度方面,BF16 梯度通信已成为大模型训练标配,配合损失缩放避免下溢;如果叠加 TopK 稀疏化,必须给丢弃的梯度配误差补偿,否则模型会悄悄漂移。

衡量集群协作效率有个直观指标:加速比 S(N)。假设单卡训练一个 batch 需要时间 T₁,N 卡训练相同总数据量时,理想情况下用时是 T₁/N。但真实世界里每轮都要聚合通信,所以 N 卡的实际用时 T_N 比理想值大。定义:

容错是真实集群的必修课:同步训练中一张慢卡能让全体降速一半,常见对策是超时剔除、弹性训练和通信重试;梯度出现 NaN 时要有熔断机制,避免毒化模型参数。百家宴办得成不成分,三分靠厨艺,七分靠统筹——分布式训练也是如此。

S(N)=T1N⋅TNS(N) = \frac{T_1}{N\cdot T_N}
S 越接近 1,说明 N 张卡的力气都花在了刀刃上,很少在等传菜。
  1. 单卡基准T₁ 是单卡训练一轮的时间——只有一户人家做饭的用时。
    T1T_1
  2. N卡实际T_N 是 N 卡协作训练一轮的实际用时,包含聚合通信的开销。
    TNT_N
  3. 加速比用理想总用时除以实际总用时,度量集群是否被充分利用。
    S(N)=T1N⋅TNS(N) = \frac{T_1}{N\cdot T_N}

AI 应用场景

千卡大模型训练

阶段:模型训练阶段

解决的问题:GPT 规模的大模型一次反向传播产生的梯度可达数百 MB,千卡同步时每轮都要 All-Reduce。若不优化,通信时间会反超计算时间。Ring All-Reduce 把通信量从随卡数线性增长压到几乎恒定,配合梯度分桶与计算重叠,让“传菜时间”藏进“炒菜时间”。

具体案例:某团队用 256 张 A100 训练 70B 模型时,将默认 All-Reduce 换成 Ring 并启用 BF16 梯度通信,每步迭代从 12 秒降至 8 秒,训练吞吐提升约 33%。

联邦学习安全聚合

阶段:隐私保护协作训练阶段

解决的问题:各参与方的数据不能出域,只能上传梯度。服务端用 FedAvg 算法把各端梯度加权聚合再平均下发,相当于“各家在本地做好菜,只把配方汇总到总厨手里”。

具体案例:某医疗联盟用联邦学习训练病理影像模型,12 家医院各自本地训练后仅上传梯度,服务端聚合平均,模型 AUC 比单院模型提升 9 个百分点。

推荐系统稀疏训练

阶段:在线学习与异步更新阶段

解决的问题:CTR 模型特征海量稀疏,样本实时到达。参数服务器天然支持异步 push/pull,配合梯度稀疏化只传非零特征梯度,让千亿参数模型也能分钟级更新。

具体案例:某电商广告平台用 PS 架构训练 CTR 模型,参数分片部署在 20 台机器上,日志特征梯度经 TopK 稀疏化后通信流量下降 80%。

Python 演示

python61 行
"""模拟 Ring All-Reduce 梯度聚合过程, 验证每个节点最终都得到全量梯度总和."""import numpy as np  class RingAllReduce:    def __init__(self, num_nodes=4, num_blocks=4, seed=42):        assert num_blocks == num_nodes, "Ring All-Reduce 要求分块数等于节点数"        self.num_nodes = num_nodes        self.num_blocks = num_blocks        rng = np.random.default_rng(seed)        # 每个节点的梯度矩阵: num_nodes x num_blocks        self.grads = rng.normal(size=(num_nodes, num_blocks))        # 期望的全局梯度(逐块求和)        self.expected = self.grads.sum(axis=0)     def scatter_reduce(self, g):        # 阶段一: 分块归并, 每轮节点i把第(i-k)块发给下一个节点并累加        for k in range(self.num_nodes - 1):            new = g.copy()            for i in range(self.num_nodes):                nxt = (i + 1) % self.num_nodes                block = (i - k) % self.num_blocks                new[nxt][block] = g[i][block] + g[nxt][block]            g = new        return g     def all_gather(self, g):        # 阶段二: 全量收集, 把归并好的块沿环继续传遍所有节点        for k in range(self.num_nodes - 1):            new = g.copy()            for i in range(self.num_nodes):                nxt = (i + 1) % self.num_nodes                block = (i - k + 1) % self.num_blocks                new[nxt][block] = g[i][block]            g = new        return g     def run(self):        g = self.scatter_reduce(self.grads.copy())        result = self.all_gather(g)        for i in range(self.num_nodes):            assert np.allclose(result[i], self.expected), \                f"节点 {i} 聚合结果错误"        return result  def main():    model = RingAllReduce(num_nodes=4, num_blocks=4, seed=42)    before = model.grads.copy()    after = model.run()    print("每个节点的初始梯度矩阵:")    print(before)    print("\n期望的全局梯度(每块在所有节点上的和):", model.expected)    print("\nRing All-Reduce 之后每个节点持有的梯度:")    print(after)    assert np.allclose(after, model.expected)    print("\n校验通过: 所有节点都拥有相同的全局梯度.")  if __name__ == "__main__":    main()
目的:用 NumPy 矩阵模拟 4 个 GPU 的 Ring All-Reduce 完整流程,直观展示“分块归并 + 全量收集”两阶段,并自动校验每个节点最终拿到全部梯度总和。
  1. self.grads = rng.normal(size=(num_nodes, num_blocks))随机生成每个节点的梯度矩阵,模拟各 GPU 算出的局部梯度。
  2. self.expected = self.grads.sum(axis=0)预先算出期望的全局梯度,也就是每个梯度块在所有节点上的和。
  3. new[nxt][block] = g[i][block] + g[nxt][block]阶段一:节点 i 把第 block 块传给下一个节点,下一个节点把收到的值累加到自己对应块上,“传菜即拌菜”。
  4. new[nxt][block] = g[i][block]阶段二:只传递不累加,把归并好的部分和覆盖给邻居,让完整总和传遍所有节点。
  5. assert np.allclose(result[i], self.expected)像验菜一样校验每个节点最终拿到的是同一份总梯度,否则算法就写错了。

常见误区

误区“梯度聚合不就是把每张卡算出的梯度都发给 0 号 GPU,0 号算完平均再广播回去吗?反正最终大家拿到的都一样。”

正解这是“单点汇聚再广播”的朴素做法,通信量 O(N·D) 随 GPU 数线性增长。Ring All-Reduce 没有中心节点,而是把梯度切块沿环接力,让每个节点同时收发。两者最终结果一致,但 Ring 的通信量几乎恒定,这正是它在百卡千卡集群中胜出的原因。好比百家宴的环形传菜比“每家都端菜到总厨那里”高效得多。

为何常见:很多教程先讲"reduce + broadcast"的抽象语义,让人误以为实现上也要先汇聚到某一点再分发。

误区“梯度聚合就是求和,把所有 GPU 的梯度加起来更新参数就行,不用管别的。”

正解求和后一定要除以 GPU 数量 N(或等价地缩放学习率)。每个 GPU 只看了 1/N 的数据,N 份梯度之和对应“N 倍 batch”的梯度方向,直接用它更新相当于学习率被放大了 N 倍,容易震荡甚至发散。百家宴的菜要分给 N 户人家,每家只吃 1/N,而不是一个人全吃掉。

为何常见:数学直觉里“汇总 = 求和”太自然,容易忽略数据并行中“平均”才是还原全局方向的正确语义。

误区“同步 SGD 每轮都等最慢的 GPU,肯定比异步慢,所以能用异步就尽量用异步。”

正解同步每轮只有一次参数版本,梯度统计完整,收敛稳定、可复现;异步虽然吞吐高,但过时梯度会带来噪声,严重时发散。实际系统中“同步 + Ring + 梯度累积”往往是最优解,Ring 等高效聚合算法已经大幅压缩了同步的通信成本。

为何常见:只看到同步在“等”,没看到异步在“乱”——训练快慢不能只看单轮吞吐,还要看收敛到目标精度所需的总时间。

误区“梯度是训练的核心信息,压缩或丢掉一部分梯度,模型精度肯定大幅下降。”

正解梯度本身噪声大,合理压缩几乎无损。FP32 换 BF16 减半流量已是标配;TopK 稀疏化在梯度幅度长尾分布时效果很好,配合误差累积机制损失极小。浓缩汤料不是偷工减料——决定整锅味道的往往是那几味主料。

为何常见:把梯度信息想象成不可压缩的精确数据,忽视了梯度在随机优化中本就是带噪声的统计估计。

误区“教材说 Ring 带宽最优,所以训练框架全都用 Ring,Tree 已经过时了。”

正解Ring 在带宽利用率上最优,但时延不是;Tree 的层数只有 log N,在延迟敏感、模型较小或节点数较少时更快。大规模跨机训练常用“机内 Ring + 机间 Tree/分层 Ring”的混合方案,而不是二选一。

为何常见:只看教科书结论不看适用条件,忽略了延迟、拓扑和模型规模的差异。

面试题

Q1. 数据并行中,梯度聚合的核心作用是什么?

单选题 · easy

  • A.汇总各GPU梯度求平均← 正确答案
  • B.加快单张GPU计算速度
  • C.减少模型参数总量
  • D.扩大单卡显存容量

答案:A。每个 GPU 只看部分数据,算出的梯度是局部估计,像只摸到大象一条腿。聚合平均后才是全局方向,所以 A 对;B、C、D 都与梯度聚合无关。

Q2. 梯度聚合时为什么要除以 GPU 数量 N?

单选题 · easy

  • A.因为每个GPU只看部分数据← 正确答案
  • B.让梯度数值变小便于存储
  • C.降低通信中的数据流量
  • D.避免模型参数过度膨胀

答案:A。每个 GPU 基于 1/N 的数据算梯度,N 份局部梯度相加后除以 N,才能还原真实 batch 大小的梯度方向。A 对;B、C、D 都不涉及“平均”的语义。

Q3. 以下哪种 All-Reduce 方式没有中心节点?

单选题 · easy

  • A.环形接力无中心← 正确答案
  • B.参数服务器中心化
  • C.树形逐级汇总
  • D.单机顺序计算

答案:A。Ring 把所有节点连成环,数据沿环接力,每个人只和邻居通信,没有中心。PS 和主从广播模式都有中心,树形根部也承担汇聚角色,所以选 A。

Q4. 同步 SGD 与异步 SGD 的关键区别是?

单选题 · mid

  • A.同步等全体梯度再更新← 正确答案
  • B.异步收敛速度更稳定
  • C.同步训练一定更快速
  • D.异步必须用参数服务器

答案:A。同步模式等所有 GPU 算完再统一聚合更新,稳定但可能被慢卡拖慢,A 对;异步快但噪声大,B 说反了;C 说反了;D 中异步不强制要求参数服务器。

Q5. Ring All-Reduce 为什么通信量几乎不随节点数增长?

单选题 · mid

  • A.每轮节点都同时收发分块← 正确答案
  • B.因为它做了数据压缩
  • C.因为它省去部分梯度
  • D.因为它使用中心缓存

答案:A。Ring 把梯度分成 N 块在环上并行传输,每个节点每轮收发 D/N,总通信量约 2D。节点越多分块越细,总量基本不变,A 对;它没有压缩、没有省梯度、也没有中心缓存。

Q6. 哪些属于梯度聚合的 All-Reduce 实现方式?

多选题 · mid

  • A.环形接力← 正确答案
  • B.树形归并← 正确答案
  • C.中心汇聚← 正确答案
  • D.本地不通信

答案:ABC。Ring、Tree、中心汇聚(类似参数服务器的单点聚合)都能完成 All-Reduce 效果,对应百家宴的“传菜、金字塔、中央厨房”三种方案;D 不通信就无法聚合。

Q7. 以下哪些属于通信优化手段?

多选题 · mid

  • A.梯度量化压缩← 正确答案
  • B.TopK稀疏化← 正确答案
  • C.梯度累积← 正确答案
  • D.增加GPU数量

答案:ABC。量化降低单次流量,TopK 只传大分量,累积降低通信频率,都是“浓缩、攒罐、重叠”的思路;增加 GPU 数量本身并不会优化通信。

Q8. Tree All-Reduce 通信时间的数量级是?

单选题 · hard

  • A.与树高成对数关系← 正确答案
  • B.随节点数线性增长
  • C.与节点数平方增长
  • D.与带宽大小完全无关

答案:A。Tree 每层传一份全量 D/B,树的层数是 log₂N,所以总时间 O(logN·D/B),A 对;它随节点数对数增长而非线性/平方,且与带宽直接相关。

Q9. 梯度累积为什么能减少通信开销?

单选题 · extreme

  • A.多次计算只通信一次← 正确答案
  • B.它压缩了梯度数据
  • C.它跳过了反向传播
  • D.它改用无梯度优化

答案:A。梯度累积把多个 micro-batch 的梯度先在本地累加,再发起一次 All-Reduce,通信频率降为原来的 1/K,相当于几道菜攒成一罐再端;它不压缩数据、不跳过反传。

Q10. 参数服务器架构的特点有哪些?

多选题 · hard

  • A.中心节点聚合更新← 正确答案
  • B.worker推拉参数← 正确答案
  • C.天然支持异步训练← 正确答案
  • D.无中心且人人平等

答案:ABC。PS 是中心化设计:PS 节点存参数并聚合更新,worker 通过 push/pull 交互,天然适配异步。D 恰好是 Ring 的特点,与 PS 矛盾。