跳转到内容

AI 系统的分层

计算机科学解决复杂度只有一招:分层抽象。每层只依赖下一层的接口,不关心其实现。AI 系统也不例外——从晶体管到"用户提交了一个训练作业",中间隔着七层。

这一章给出全书使用的分层。它的用处不是背下来,而是:当性能不如预期时,你能说出问题在哪一层,以及为什么在别的层做优化没有用。

#层向上提供的承诺向下隐藏的细节时间尺度对应卷
7调度与平台"提交作业,它会跑完"排队、故障、资源竞争、多租户分钟–天八、十一
6训练 / 推理框架"定义模型,它会算"自动微分、算子调度、显存管理毫秒–秒四、六
5编译器与内核"这个算子会被高效执行"分块、融合、寄存器分配、指令选择微秒五
4分布式运行时"多卡像一张卡"分片、通信、同步、重叠微秒–毫秒四
3集群网络"任意两卡可通信"拓扑、路由、拥塞、重传微秒三
2节点内互连"同机八卡高带宽互通"链路差异、NUMA、点对点能力亚微秒二
1加速器与内存"这么多算力、这么多显存"核心调度、缓存、内存时序、功耗纳秒二

从下往上,每层的时间尺度大致放大一个数量级。这不是巧合:每一层都在用"多花一点时间"换"少操一份心"。

第 1 层 · 加速器与内存。 提供两个数字:峰值算力和显存容量。它隐藏了核心怎么调度、缓存怎么工作、显存怎么排队。泄漏点在于这两个数字都是"理想值"——实际能拿到多少取决于你的访问模式和功耗状态。下一章专门讲这些数字。

第 2 层 · 节点内互连。 让同一台机器里的几张卡能高速交换数据,通常比走主板总线快一个数量级。它是"八卡为一个单位"这个惯例的物理来源——很多并行策略的边界就画在这里。

第 3 层 · 集群网络。 让任意两张卡能通信。它隐藏了拓扑和路由,但隐藏得不彻底:两张卡的物理位置会让实际带宽差出好几倍,而框架看不到这一点。

第 4 层 · 分布式运行时。 最关键也最漏的一层。它承诺"多卡像一张卡",实际上你必须知道数据怎么切、通信量多大、能不能和计算重叠,否则加卡不加速。第六章和第十章讲这一层。

第 5 层 · 编译器与内核。 把"矩阵乘"这样的算子变成具体的机器指令,负责分块、融合、调度。它承诺"高效执行",但对没见过的算子形状、动态变化的张量尺寸,效率可能断崖式下降。

第 6 层 · 框架。 让你用几十行代码描述一个模型。它隐藏了求导、内存分配、算子调度。泄漏点是:同样的数学,不同的写法性能可以差几倍。

第 7 层 · 调度与平台。 承诺"提交就会跑完"。隐藏了排队、抢占、故障。泄漏点是:分到哪些机器会显著影响速度,而用户通常无法指定。

有两件事不属于任何一层,却贯穿所有层:

  • 数据(第七卷):从远端存储到加速器显存的一条独立管道。任何一段堵住,上面全部空转。它与七层正交,因为每一层都可能成为数据路径上的瓶颈。
  • 可观测性(第九卷):每层都要能被测量,否则无法定位瓶颈。一个测不出来的系统,等于没有系统。

分层之所以重要,是因为相邻层之间的性能差距是数量级的。下一章会给具体数字,这里先给结论性的直觉:

片上存储 ──10×──→ 显存 ──10×──→ 节点内互连 ──10×──→ 跨节点网络
──100×──→ 本地盘
──1000×──→ 远端存储

每跨一级,带宽降一档、延迟升一档。这些落差解释了几乎所有系统设计决策:

设计为什么
算子融合少往显存跑一趟
张量并行只在节点内跨节点带宽低一个数量级,通信会吃掉收益
训练数据缓存到本地盘远端存储的延迟高两三个数量级
检查点先写本地再异步上传同上,且不阻塞训练
增大批量摊薄每次数据搬运的固定开销

记住落差,比记住绝对数字更有用——绝对数字每代硬件都在变,落差的相对关系几十年没变过。

把一个训练步骤的墙钟时间拆开:

Tstep=Tcompute+Tmemory+Tcomm+Tdata+Tsync−ToverlapT_{\text{step}} = T_{\text{compute}} + T_{\text{memory}} + T_{\text{comm}} + T_{\text{data}} + T_{\text{sync}} - T_{\text{overlap}}

理想情况下后四项都能与计算重叠,T≈TcomputeT \approx T_{\text{compute}}。现实中总有一项没被藏住,它就是瓶颈。

在非瓶颈层做优化,端到端收益为零。 这听起来显然,但违反得极其频繁:花两周把某个算子优化了 30%,端到端毫无变化——因为作业本来卡在通信上。

用 Amdahl 定律量化:若某部分占总时间比例 pp,把它加速 ss 倍,端到端加速比为

Speedup=1(1−p)+p/s\text{Speedup} = \frac{1}{(1-p) + p/s}

代入几个数看看:

该部分占比加速 2×加速 10×加速 ∞
10%1.05×1.10×1.11×
30%1.18×1.37×1.43×
50%1.33×1.82×2.00×
80%1.67×3.57×5.00×

占比 30% 的部分即使优化到无穷快,端到端也只快 43%。所以第一步永远是测量——不测就动手,大概率在优化那 10%。

分层能成立的前提是"每层的承诺可靠"。但 AI 系统的抽象泄漏得比一般软件严重得多,原因很简单:性能本身就是需求。一个 Web 框架慢 30% 通常无所谓,一个训练框架慢 30% 意味着多烧几百万。

层的承诺泄漏形式后果
"定义模型即可"算子没被融合、写法不同显存爆炸;速度差数倍
"多卡像一张卡"不懂通信量、分片策略选错扩展性归零;显存不足
"算子会被高效执行"张量形状动态变化、图被打断反复重编译;优化失效
"任意两卡可通信"物理位置不佳、单条链路故障慢 30%;全局被拖累
"提交作业就会跑完"拓扑没对齐、被抢占通信绕远路;从头再来

这就是 AI Infra 这个岗位存在的直接原因:上层的人需要有人替他们管理泄漏的抽象。 也是本书不能只讲某一层的原因——真实问题总是跨层的。

用户报告"训练比上周慢了 20%"。按层排查,每层问一个可测量的问题:

层问什么怎么测常见原因
— 数据加速器在等数据吗?时间线上有无规律性空隙数据源变慢、预处理并发不足
7 调度换机器了吗?对比作业的节点列表拓扑变差、与人混部
6 框架配置变了吗?diff 配置与代码批量、重计算、并行度变化
5 编译器版本变了吗?检查镜像与库版本内核回退到慢路径
4 运行时通信占多少时间?通信计时、时间线重叠失效、并行度不当
3 网络带宽还是基线吗?跑标准通信基准测试链路误码、拥塞、路由不均
2 节点内卡间链路正常吗?查链路状态与速率降速、卡间不对称
1 加速器时钟被压了吗?采功耗、温度、时钟频率功耗封顶、散热问题

真实排查中最常见的答案是第 3 层(一条链路)和第 1 层(一张降频的卡),而不是代码。 顺序建议:先怀疑硬件与环境,再怀疑自己最近的改动,最后才怀疑框架。

理由是概率:硬件天天在坏,你的代码上周还是好的,框架被几十万人用过。

读完这一章,你应该能把任何一个问题映射到某一层,然后直接跳到对应的卷:

性能 / 成本问题
├─ 加速器在等数据 → 第七卷 存储与数据管道
├─ 加速器在等通信 → 第三卷 网络 / 第四卷 并行策略
├─ 加速器在算但算得慢 → 第五卷 编译器与内核 / 第二卷 硬件
├─ 显存不够 → 第四卷 分片与重计算 / 本卷第五章 精度
├─ 卡拿不到 / 排队太久 → 第八卷 调度与集群
├─ 时快时慢 / 经常挂 → 第九卷 可观测性与可靠性
├─ 能跑但太贵 → 第十卷 效率与成本
└─ 不知道卡在哪 → 本卷第四、七章(先学会测量)

最后一行最重要。如果你还不知道问题在哪一层,不要跳到任何一卷——先读完本卷第二部分,学会判断。

  • 七层:加速器 → 节点内互连 → 集群网络 → 分布式运行时 → 编译器与内核 → 框架 → 调度平台;外加数据与可观测性两条纵向关注点。
  • 相邻层之间是数量级的落差;记住落差比记住绝对数字有用。
  • 任一时刻只有一个瓶颈,非瓶颈层的优化端到端收益趋近于零——Amdahl 定律给出上界。
  • AI 系统的抽象泄漏严重,因为性能本身是需求;管理泄漏正是这个岗位的价值。
  • 排障顺序:先硬件与环境,再自己的改动,最后框架——按概率排的。