想象你是一家五星级酒店后厨的总厨宋大厨,手下四位工作站厨师(GPU 节点)要协作完成一场千人国宴(训练大模型):有人切菜、有人颠勺、有人摆盘,食材通过传菜电梯(NCCL)在工位间流动。突然,传菜电梯卡在二层不动了,所有厨师端着盘子傻等;某位师傅手速明显跟不上,案板上的菜堆成了山;甚至有位厨师直接熄火撂挑子。这正是分布式训练里最经典的四大故障:卡死、显存溢出、节点崩溃、指标异常。 其实分布式训练就是一场“多人协作的流水线烹饪”——每个 GPU 本身运转正常,问题往往出在“人和人的交接”上:数据分片不均、梯度同步超时、通信链路拥堵、日志错位难对齐。因此,分布式训练调试的核心不是调参,而是用一套系统方法快速回答四个问题:哪位厨师掉队了?哪条传菜通道堵了?哪个环节在空转?改完有没有真的修好? 本文就带你以宋大厨的视角,把分布式训练调试这门“后厨管理学”彻底讲透。
掌握分布式训练调试技巧,意味着你在大模型时代从“只会调参”升级为“能止血、能定位、能优化”的工程高手——这是大模型训练岗位最稀缺的能力之一。
可视化演示
展示系统处理流水线、实时性能指标曲线及多方案对比分析,包含数据流转、吞吐延迟监控与方案评估。
本节配有交互动效(进入视口后自动加载,约 3KB)。
系统可视化 处理流程:输入→处理→模型→输出 性能监控:实时指标 P=L×T
训练协作模式
宴会开席前,宋大厨站在后厨中央,目光扫过四个工位。切配组的小王领走了半筐土豆各切各的,负责炒制的老李守着自己的铁锅按工序分工,传菜口的小赵把半成品递向下一个工位——这是后厨最常见的三种协作:各切各的汇总(数据并行)、按工序分工(模型并行)、沿着流水线传递(流水线并行)。大场面国宴,三种协作常常混着用,这就是混合并行。
分布式训练的逻辑与此如出一辙。数据并行,就是每个 GPU 都保存一份完整的模型副本,把训练数据切成多份分给各节点,各自算梯度后做一次全局平均;模型并行,则是把一个大模型按层或按张量拆开分别放在不同 GPU 上,单卡装不下时尤其管用;流水线并行负责把前一层的结果顺着链条传给下一层,就像切好的菜顺着传菜口送到炒锅前。
工程里常把数据并行(DP)、流水线并行(PP)、张量并行(TP)合称“3D 并行”。上百台机器、上千张卡协同训练千亿参数模型时,三种并行会叠加使用。但并行并不是免费午餐:节点间同步梯度、传递激活值都会消耗时间。节点数翻倍,训练速度却不会翻倍。我们用一个简洁的指标衡量并行收益——加速效率:
宋大厨心里清楚:雇四个帮工并不能让备菜快四倍——工位之间的传菜、核对、等待都是隐性成本。效率低于 70% 时,他就该去查查哪个环节在“磨洋工”了,这恰好是下一节要面对的四种典型故障。
- 分子 S(加速比)$S = \frac{T_{1}}{T_{N}}$ — 单机训练耗时除以 N 机训练耗时,代表真实提速了多少倍。
- 分母 N(节点数)$N$ — 参与训练的机器或 GPU 数量,是理想情况下理论提速的倍数。
- 整体含义 — 4 台机器加速 3.6 倍,效率是 0.9,接近完美;若只加速 1.5 倍,效率不到 40%,说明并行收益被通信与同步严重稀释。
常见故障类型
国宴当天上午十点,后厨警报四起。传菜电梯卡在二层一动不动,所有厨师端着盘子傻等——这是“卡死”;老王案板上的土豆丝堆成了小山,灶台都快被淹没——这是“显存溢出”;三号灶台突然熄了火,厨师直接撂挑子走人——这是“节点崩溃”;宋大厨盯着出菜记录,发现某道菜的量忽多忽少毫无规律——这是“指标异常”。四类故障,几乎覆盖了分布式训练九成以上的事故现场。
技术世界里,卡死最常见也最隐蔽:集合通信中某个 rank 提前退出或数据不齐,导致其他 rank 永远在等待同步信号;显存溢出源于激活值过多、梯度累积或碎片化;节点崩溃通常由网络断连、硬件故障或 CUDA 错误引发;指标异常的典型表现是 loss 变成 NaN,背后往往是梯度爆炸或学习率过大。
排查显存溢出时,要算清显存账本。大模型训练时显存主要被四样东西占据:
账算明白了,就知道该砍哪一样:用梯度检查点砍激活值,用混合精度砍优化器状态。宋大厨对着这份清单,就像对着食材清单下采购单——哪一样占地方,就先优化哪一样。
- M参数(模型体重)$M_{参数}$ — 模型本身的权重参数量,70B 模型仅半精度参数就要约 140GB。
- M梯度(练习册)$M_{梯度}$ — 反向传播时每个参数对应一份梯度,大小和参数相当。
- M优化器状态(备忘本)$M_{优化器状态}$ — Adam 优化器要额外保存动量和方差,动辄是参数的 2-3 倍。
- 整体含义 — 账算清楚了才知道为什么 80GB 显卡放不下 70B 模型:参数只是冰山一角,配套状态才是大头。
日志分析技巧
宋大厨处理事故有个习惯:先翻工作笔记。每位师傅的围裙口袋里都别着一本日志本,每页开头写着编号——“RANK 3 10:02:15 切丝完成”。宋大厨自己的笔记永远是第 0 本。出问题时,他先看自己的笔记,再按时间戳把四本笔记对齐,看哪一页出现断层或异常。
分布式训练中,每个进程输出的日志都带自己的 rank 标识。rank 0 通常是主进程,负责汇总全局状态、打印训练指标、协调启动和退出;其他 rank 的日志记录局部异常。排查第一原则:先看 rank 0 有没有全局性错误,再看非零 rank 有没有各自的崩溃堆栈。系统崩溃时,错误栈从栈顶往栈底看,就像顺着烧糊的锅往上游找火源——每一步调用都写在报错里。
日志的另一大用途是时间线重建。多卡训练中,各 rank 在同一时刻应处于相近的进度。如果 rank 2 的迭代时间戳比别的节点晚了数秒,说明它在等待或做多余的计算。这个时间差用简单减法就能度量:
日志就像厨师的笔记:单看一本看不出问题,四本对齐才看得出谁在偷懒。宋大厨常说:“笔记不撒谎,但对不齐的笔记才是线索。”
- t0(基准时间戳)$t_{0}$ — 取 rank 0 在某个阶段(如每轮迭代结束)打点的时间。
- t1(待查时间戳)$t_{1}$ — 同一轮迭代其他 rank 打点的时间。
- 整体含义 — 若偏差持续为正且越来越大,说明该节点在累计掉队,是负载不均或通信等待的线索。
性能瓶颈定位
午市高峰,宋大厨掏出秒表站在后厨中央。他先看每位师傅的颠勺节奏——灶台火苗旺不旺(GPU 利用率);再看传菜口排队的人数(通信开销);又绕到洗菜间看备菜流水线是否断货(数据加载);最后瞥一眼四个工位的忙闲程度(负载均衡)。一圈下来,瓶颈无处遁形。
判断性能瓶颈,最直接的数据是 GPU 利用率。用 nvidia-smi 或训练框架自带的 profiler 观察:如果利用率长期低于 60%,说明 GPU 在空转等待——要么等数据从磁盘或网络加载,要么等别的节点完成梯度同步。此时别急着加卡,先分清瓶颈在计算侧、数据侧还是通信侧,否则加再多卡也只是让更多 GPU 一起空转。
一个朴素而有效的分解模型是:把单次迭代时间拆成“干活的时间”和“等人、等数据的时间”。通信开销占比越高,并行效率越低:
宋大厨把秒表一收,心里有了数:“火苗再旺,传菜口堵着也是白搭。”瓶颈定位的精髓在于先分清是灶的问题、菜的问题还是通道的问题——诊断方向错了,优化动作全是徒劳。
- T计算(切菜时间)$T_{计算}$ — GPU 真正做前向和反向计算的时间。
- T通信(等传菜时间)$T_{通信}$ — 梯度同步、参数广播、数据拉取等花在互等上的时间。
- 整体含义 — 若利用率只有 40%,说明一半以上的时间浪费在等待上,要优先优化通信和数据管线。
同步一致性
国宴的招牌菜是一道秘制酱汁,四位师傅各调一锅,最后汇进大锅里。问题来了:每锅酱汁是按“一人份配方”调的还是按“四人份配方”调的?如果每锅都按全席配方调,四锅汇一起就咸死人——这就是分布式训练里最常见的同步一致性陷阱:学习率没有随节点数放大。
数据并行下,每个节点用各自的 batch 算梯度,然后做 AllReduce 把所有梯度平均,再用平均梯度更新参数。关键点:平均梯度约等于“单机 batch 的梯度”,但全局更新一次用的数据量是原来的 N 倍。如果维持原学习率,等效于 batch 变大而步长没变,模型收敛会变慢甚至发散。线性缩放法则给出了修正:学习率随节点数线性放大。
除了学习率,全局 batch 也要同步确认:global_batch = per_gpu_batch × N。随机性管理同样重要——数据增强的随机种子应让各节点采样到不同数据,但模型参数初始化的种子必须一致,否则各节点开始了“不同的人生”,梯度平均就没有意义。这类问题从日志和指标上很难一眼看出,loss 高、收敛慢,背后可能只是少乘了一个 N。
- η单(单机学习率)$\eta_{单}$ — 单卡训练时调好的学习率基线,是配方基准。
- N(并行节点数)$N$ — 数据并行的 GPU 数量,决定配方要放大几倍。
- 整体含义 — 4 卡训练就把学习率乘 4,同时配合 warmup 策略,避免开局步长过大震荡。
集合通信排查
宴席最忙的环节是传菜。宋大厨装了一套自动传菜电梯系统(NCCL),四个工作站呈环形布局:三号师傅切完的菜传给四号,四号传给一号,一号传给二号,绕一圈后每个人手里都有一份完整的“汇总调料包”。可偏偏这套电梯三天两头卡顿——电梯超时报警,所有工作站停下手里活干等着。
集合通信是分布式训练的血管。最常用的原语是 AllReduce,它把各节点的梯度规约为一个平均值再广播回去。常用实现是 Ring AllReduce:数据拆成一个环,每个节点只和相邻节点通信,收一份、合并一份、再传一份。它非常省带宽——总通信量与节点数几乎无关:
排查通信问题三板斧:第一,调大 NCCL_TIMEOUT 只是给电梯换了个更长的容忍时间,根本问题往往是网卡降速或交换机丢包,要配合 NCCL_DEBUG=INFO 看连接是否稳定;第二,用 nccl-tests 实测节点间带宽,吞吐只有理论值几成时再查网络拓扑;第三,确认通信走的物理链路和 GPU 插槽匹配(如 GPU Direct RDMA 是否生效),避免数据在 CPU 内存里中转。宋大厨的态度很鲜明:“电梯报警不能只按复位键,要查是钢丝绳还是电机的问题。”
- D(数据总量)$D$ — 需要规约的梯度总字节数,即“要传的所有食材量”。
- B(链路带宽)$B$ — 节点间网络链路的有效带宽,即“传菜电梯每秒能送多少盘”。
- 系数 2(N-1)/N — 环形归约分“归约 + 广播”两步,每步传 (N-1)/N 份数据;N 很大时系数趋近 2,说明瓶颈不在节点数而在带宽本身。
调试工具方法
后厨的质检工具箱里,宋大厨备着三样法宝:全厨房的监控探头(性能剖析器),能把每位师傅每分钟的动作拆成“切菜 40 秒、递菜 15 秒、发愣 5 秒”;对讲机系统(分布式调试器),能在任意时刻叫停整个后厨逐站检查;试菜小灶——用小锅按同样配方先烧一遍验证思路。
分布式调试的核心手段有三个。性能剖析器(PyTorch Profiler + TensorBoard)输出每个算子的耗时、GPU 利用率和通信等待的瀑布图,一眼看出 GPU 在“干活”还是“发呆”。分布式调试器(torchrun + debugpy)可以让所有 rank 在断点同时停下,检查各节点变量是否一致;或用 barrier debug 模式定位是哪个 rank 没到齐。小规模复现则把数据量、模型规模、节点数同时缩小,在单机多卡甚至单卡上复现问题,复现时间与数据量近似成正比:
环境变量也是好帮手:CUDA_LAUNCH_BLOCKING=1 让 CUDA 内核同步执行,报错栈精确到具体算子;NCCL_DEBUG=INFO 输出通信连接细节;PYTHONFAULTHANDLER=1 捕获段错误。宋大厨的哲学是:“大锅饭烧坏了,先用小灶试出正确配方。”调试工具要形成“探针 + 小灶 + 断点”的组合拳,把黑盒变成白盒。
- S小 / S全(数据比例) — 用小数据集(如 1%)与全量数据集的规模比例。
- T全量(原始训练时长)$T_{全量}$ — 全量数据训练一轮的时间。
- 整体含义 — 数据缩到 1%,复现成本也接近 1%,几十分钟就能验证一个假设。
实战排查流程
晚上九点,后厨复盘会。宋大厨在黑板上写下四行字:发生了什么(现象描述)→ 换个灶重做一遍(单机复现)→ 一道菜一道菜排查(逐层隔离)→ 改完再验一遍(验证修复)。这是他用十几年事故换来的排查 SOP,每一步都不许跳。
实战中分布式训练问题排查分四步。现象描述:是卡死、变慢、崩溃还是指标异常?在什么配置(节点数、batch、模型规模)下触发?卡死在启动阶段还是训练中途?单机复现:先缩到单机单卡或单机多卡跑同样的脚本——单机正常而多机故障,问题大概率在网络或通信层;单机也挂,问题在代码、数据或环境本身。逐层隔离:按“网络 → 数据管线 → 模型计算 → 优化器 → 指标监控”逐层打点,缩小嫌疑范围。验证修复:一次只改一个变量,改完用相同配置回归验证。
这个流程背后的理论依据是阿姆达尔定律——并行系统的加速上限取决于不可并行部分的比例:
“单机复现”这个动作,本质上是把不可并行部分彻底暴露出来。宋大厨在复盘会结尾敲敲黑板:“排查不是玄学,是控制变量。每一步只动一个变量,答案自己会浮出来。”
- p(可并行比例)$p$ — 训练中可并行部分占整体耗时的比例。
- (1-p)(不可并行部分) — 数据准备、启动同步、通信握手等串行开销。
- 整体含义 — 即使加到无穷多卡,加速上限也是 1/(1-p)。排查要先消灭串行瓶颈,否则加再多卡都白搭。
AI 应用场景
千卡集群训练卡死急救
阶段:训练运维 / 线上故障诊断
解决的问题:某企业 512 卡大模型训练凌晨突然 hang,日志停在某个同步点。传统做法是整集群重启碰运气,损失数小时算力。基于“日志分析 + 集合通信排查”的方法:先看 rank 0 日志确认没有全局异常,再用时间戳对齐发现 rank 137 的 checkpoint 时间落后 40 秒,打开 NCCL_DEBUG=INFO 发现该节点网卡链路降速到百兆,用 nccl-tests 实测确认,最终锁定交换机坏端口并迁移任务。
具体案例:某互联网公司多模态大模型训练平台,故障从“重启赌运气”变为“按流程定位”,平均恢复时间从 2 小时降到 20 分钟。
自动驾驶感知模型的性能调优
阶段:性能优化
解决的问题:8 卡训练 GPU 利用率长期 45%,加卡无效。用 PyTorch Profiler 看到迭代时间中通信占比 38%,GPU 大量时间在等待 DataLoader。按“性能瓶颈定位”的方法,通过多进程数据预取、开启 num_workers 与 pinned memory、把日志与 checkpoint 写盘改为异步,并让通信与计算重叠,利用率提升到 90%。
具体案例:某自动驾驶团队 BEV 感知模型训练,吞吐从 1200 samples/s 提升到 2400 samples/s,训练周期缩短一半。
大语言模型微调的学习率修正
阶段:超参数调整 / 收敛性诊断
解决的问题:32 卡 LoRA 微调 loss 震荡不收敛,排查模型代码无果。套用“同步一致性”一节的线性缩放法则检查,发现学习率仍是单卡基线 2e-5,未随节点数放大。修正为 6.4e-4 并配合 warmup 后 loss 平滑下降,收敛时间缩短 3 倍。
具体案例:某大模型应用团队 70B 模型微调,修正后评测分数提升 2 个百分点,稳定复现。
Python 演示
import randomimport threadingimport timefrom collections import defaultdict def worker(latency, results, rank): """单个 Worker 模拟: 在随机波动后上报耗时""" cost = latency * random.uniform(0.8, 1.2) time.sleep(cost) results[rank] = cost def run_one_round(latencies, results): """模拟一轮同步: 所有 Worker 并发执行并等待全部完成""" threads = [threading.Thread(target=worker, args=(lat, results, i)) for i, lat in enumerate(latencies)] for t in threads: t.start() for t in threads: t.join() def collect_rounds(worker_latencies, rounds=4): """多轮采集每个 Worker 的通信耗时""" records = defaultdict(list) for _ in range(rounds): results = {} run_one_round(worker_latencies, results) for rank, cost in results.items(): records[rank].append(cost) return records def find_stragglers(records, threshold=1.3): """将平均耗时超过全局均值 threshold 倍的节点判为掉队者""" averages = {} for rank, costs in records.items(): averages[rank] = sum(costs) / len(costs) baseline = sum(averages.values()) / len(averages) result = {} for rank, avg in averages.items(): if avg > baseline * threshold: result[rank] = round(avg, 3) return result def main(): random.seed(2024) latencies = [0.4, 0.4, 0.4, 1.6] # 4 个节点, 3 号明显偏慢 print("节点基线耗时(秒):", latencies) records = collect_rounds(latencies, rounds=4) for rank in sorted(records): costs = ["%.2f" % cost for cost in records[rank]] print("Worker %d: %s" % (rank, costs)) stragglers = find_stragglers(records) if stragglers: print("排查结果: 掉队节点 =", stragglers) else: print("排查结果: 所有节点健康") if __name__ == "__main__": main()
records = defaultdict(list)以节点编号为键存储多轮耗时,形成后续统计所需的时间序列。threads = [threading.Thread(target=worker, args=(lat, results, i)) for i, lat in enumerate(latencies)]为每个节点启动独立线程,模拟多卡并行地“同时跑一轮”。t.join()主线程等待所有 Worker 完成,等价于训练中的全局同步屏障。run_one_round(worker_latencies, results)执行一轮完整的通信模拟,每个 Worker 把耗时写入共享字典。averages[rank] = sum(costs) / len(costs)对每个节点求多轮平均耗时,消除单轮的随机抖动。baseline = sum(averages.values()) / len(averages)以全局平均耗时作为健康基准。if avg > baseline * threshold:超过基准 1.3 倍即判为掉队节点,对应正文负载不均衡的排查方法。
常见误区
误区“训练一卡住,我直接把 NCCL_TIMEOUT 从 600 秒改成 3600 秒,延长后训练果真继续跑下去了,问题这不就解决了?”
正解超时时间只是系统对故障的“忍耐上限”,并非病因。卡死往往是某个 rank 提前退出、网络闪断或数据不一致,导致集合通信永远等不到信号——延长超时只是把炸弹引信拉长。正确做法是开 NCCL_DEBUG=INFO 看连接日志,用各 rank 时间戳对齐查谁没到场,再用 nccl-tests 验证带宽。
为何常见:改超时零成本、见效快,能看到“继续跑”的表象,让人误以为已根治,实际上故障仍在反复。
误区“nvidia-smi 显示 GPU 利用率 95%,我的集群一定非常健康,不需要优化。”
正解利用率只说明 GPU 没闲着,不代表在算有效计算。通信自旋、同步忙等、kernel 启动开销都会造成虚假的高利用率。应结合 profiler 的 compute 与 memory 活动、以及“有效计算时间占比”综合判断;利用率高且通信占比低、带宽跑满,才算真的健康。
为何常见:nvidia-smi 最容易获取,人天生倾向用一个“看起来很满”的数字安慰自己,忽略了它只反映忙不忙、不反映效率。
误区“rank 0 是主进程,错误都会汇总到它那里,我只看它的日志就行,其他 rank 的日志都不用管。”
正解rank 0 负责协调与全局打印,但各 rank 的 CUDA 错误、OOM 堆栈往往只出现在对应 rank 的本地日志里。如果 rank 0 已进入 barrier 等待,它甚至不会打印任何错误。正确做法是:先扫 rank 0 抓全局线索,再按时间戳对齐各 rank 日志,重点看落后节点。
为何常见:“主进程”这个名称容易造成“唯一真相源”的错觉,而且分布式日志量大,人本能地想少看几份。
误区“我把数据缩到 1%、卡数缩到 2 张,问题复现不出来,那线上应该也不会再出现,可以不管了。”
正解复现不出来本身就是线索:它强烈暗示问题与规模相关,比如网络拓扑竞争、数据分片边界、显存碎片,或更多节点引发的通信拥塞。此时应反过来想“规模放大后什么发生了变化”,针对性地增加通信打点和资源监控,而不是放弃排查。
为何常见:人们把“复现失败”等同于“问题不存在”,但分布式系统中规模效应恰恰是最容易出 bug 的地方。
面试题
Q1. 排查分布式训练卡死时,最先应该查看哪种日志?
- A.随机选择某个工作节点日志
- B.所有节点日志一起滚动查看
- C.优先查看主进程 Rank0 日志← 正确答案
- D.从最高编号节点开始排查
答案:C。主进程 rank 0 负责全局协调、指标打印和错误汇总,是排查的第一现场;但它不包含其他节点的局部崩溃细节,所以先看 rank 0 建立全局视图,再按需深入具体 rank 日志。随机看、全量滚动看或从最大编号开始看都缺乏依据,容易淹没关键信息。
Q2. 数据并行中每卡 batch 为 8、共 4 卡时,全局批大小是多少?
- A.保持为每卡 8 不变
- B.与 batch 大小无关
- C.缩小到原来的 2
- D.扩大到总和的 32← 正确答案
答案:D。数据并行下全局批大小 = 每卡 batch × 卡数 = 8 × 4 = 32。保持 8 意味着全局更新用的数据量仍只是单卡规模;缩小以及“与 batch 无关”都违背数据并行同步语义。全局 batch 是评估收敛行为和调整学习率的基础。
Q3. 线性缩放法则要求全局学习率如何设置?
- A.随节点数线性放大学习率← 正确答案
- B.保持单机基线学习率不变
- C.每轮训练后清零重新搜索
- D.随节点数平方倍缩小学习率
答案:A。线性缩放法则指出:全局学习率 = 单机学习率 × 节点数,以补偿梯度平均后每步更新数据量的放大。保持基线会导致收敛变慢,清零重搜和平方倍缩小都无理论依据,且会破坏既有调参结果。这与正文“酱汁配方随人数放大”的原理一致。
Q4. Ring AllReduce 的通信时间与节点数 N 的关系?
- A.随 N 增大近似线性增长
- B.随 N 增大呈平方增长
- C.近似与 N 无关保持不变← 正确答案
- D.随 N 增大指数级爆炸
答案:C。环形归约时间为 2(N-1)/N × D/B,N 增大时 (N-1)/N 趋近 1,总通信量与节点数近似无关,这正是环形归约的优势。线性、平方、指数增长都是对“数据量随节点复制”的错误想象——环形归约避免了中心节点带宽瓶颈。
Q5. GPU 利用率长期低于 60%,最优先检查哪个方向?
- A.排查数据加载与通信等待← 正确答案
- B.降低模型参数量减少计算
- C.增加节点数量提升并行度
- D.增大学习率加速模型收敛
答案:A。利用率低意味着 GPU 在空等,等待主要来自两块:数据加载(磁盘/解码/预处理)和通信同步(梯度 AllReduce)。优先排查这两者才能对症下药。减少参数、加大学习率、增加节点数都不能解决“空转等数据/等通信”这类根因。
Q6. 使用 PyTorch Profiler 发现通信占迭代时间 45% 时,首选优化策略是?
- A.调大 NCCL 超时容忍等待
- B.重叠通信与计算并检查带宽← 正确答案
- C.关闭梯度同步直接异步更新
- D.把模型缩小一倍降低负载
答案:B。通信占比 45% 说明近一半迭代时间在等梯度同步。首选让通信与计算重叠(如梯度桶 + 异步通信后端),同时用 nccl-tests 检查真实带宽。调大超时只掩盖症状;关闭梯度同步破坏数据并行一致性;缩小模型属于牺牲精度的下策。
Q7. 以下哪些是分布式训练常见故障现象?
- A.多卡训练进程集体卡死← 正确答案
- B.单卡显存溢出 OOM 报错← 正确答案
- C.训练日志正常且指标稳定
- D.loss 突变为 NaN 且发散← 正确答案
答案:ABD。卡死、OOM、loss 出现 NaN 分别是“常见故障类型”一节中的训练卡死、显存溢出、指标异常三类典型信号。“日志正常且指标稳定”恰恰是健康状态,不属于故障。D 选项对应梯度爆炸或学习率过大,是典型指标异常。
Q8. 排查问题做“单机复现”的核心目的是什么?
- A.节省全部训练所用的电费
- B.降低模型的最终推理延迟
- C.提高模型的最终精度指标
- D.区分问题在单机还是分布式← 正确答案
答案:D。单机复现的目的是控制变量——单机正常而多机故障,问题大概率在网络或通信层;单机也异常,问题在代码、数据或环境本身。省电费、降延迟、提精度都不是复现实验的目的,它是“实战排查流程”里的隔离手段。
Q9. 定位负载不均衡问题时,哪些手段有效?
- A.对比各 rank 迭代耗时曲线← 正确答案
- B.核对各节点的数据采样量← 正确答案
- C.观察各卡 GPU 利用率分布← 正确答案
- D.只统计主机的显存总量
答案:ABC。负载不均衡的显著特征是各节点耗时曲线错位、采样量不均、GPU 利用率差异大。对比耗时与利用率能直接量化“谁在拖后腿”,核对采样量能找到数据分区的偏心。只统计主机显存总量与负载均衡无关,不能帮助定位。
Q10. 关于分布式训练随机一致性,正确做法包括?
- A.各节点模型初始化种子一致← 正确答案
- B.数据扩增采样各节点不同← 正确答案
- C.梯度全部异步无需统一规约
- D.每卡独立固定自己的数据加载← 正确答案
答案:ABD。随机性管理要区分对象:模型初始化种子必须各节点一致,保证从同一参数状态出发;数据增强或采样的随机种子应各不相同,确保全局数据多样性;每卡数据加载顺序固定有助于可复现调试。梯度异步且不统一规约违背数据并行同步更新语义,通常会导致模型参数不一致。