数据—算法—机器分类体系

数据—算法—机器分类体系

运行缓慢的系统很少会直接揭示原因。加速器空闲,可能源于输入流水线供给不足(数据)、算法的算术强度过低(算法),或内存总线饱和(机器)。本附录对本书的单节点诊断分类体系作出形式化说明,将性能剖析中的症状和测量结果直接映射到实际限制执行的轴,以便在优化开始前明确约束所在。阅读本附录前,读者应已了解开篇各章介绍的三个轴,以及量化这些轴的机器学习系统铁律。

如何使用本附录

当系统未能达到性能、成本或质量目标,而原因尚不明确时,可使用数据—算法—机器分类体系。按以下四个步骤运用该框架:

  1. 明确症状和运行预算:记录未能达到的端到端目标、工作负载和部署环境。
  2. 定位候选轴或边界:使用 table 1 进行初步判断;当证据涉及多个轴时,使用 table 2。
  3. 检验假设:将证据映射到铁律和算术强度,再借助 table 6 和 table 7 收集用于验证的测量结果。
  4. 干预并重新测量:从 table 4 中选择优化手段,然后重复端到端测量。如果目标指标未改善,则修正假设。

症状决定最有用的切入点。加速器利用率低或批次交付缓慢时,应从 section 1.5 和 section 1.8 开始。未达到服务级别目标(SLO)时,应从 table 5 中的阶段耗时和队列深度入手,定位对应的铁律项。质量进入平台期时,应先检查数据/算法边界,并参考 section 1.11,再分配更多计算资源。在所有情况下,轴标签都只是假设,而非定论:各轴存在重叠,有用的诊断可能需要同时指出主导轴和边界效应。

诊断概览

该分类体系直接映射到 机器学习系统铁律 中建立的机器学习系统铁律。Table 1 汇总了各轴的作用、主要物理约束和核心优化路径。

Table 1: 数据—算法—机器各轴参考:每个轴都对应一类约束和一种优化策略。先提出假设,再通过测量确认,随后查阅所指向的章节。
轴 作用 物理约束 高收益优化
数据(D) 信息(燃料) 数据量、质量、到达速率 数据选择(数据选择)
算法(A) 逻辑(蓝图) 运算及依赖关系 模型压缩(模型压缩)
机器(M) 物理机制(引擎) 计算、内存、I/O 硬件加速(硬件加速)

这种初步划分很有用,但生产系统很少只受某个单一轴上的瓶颈影响。更常见的是,问题位于两个轴之间的边界——例如,某种数据格式的选择决定了 GPU 能否达到饱和,或某种剪枝策略改变了内存访问模式。处理这些情况需要梳理各轴的交叉关系。

交叉关系全景

开篇章节使用 数据—算法—机器交叉全景 建立概念全景。这里,figure 1 将该图景转化为诊断顺序。首先识别构成约束的轴,然后考察干预会如何改变另外两个轴。

\scalebox{0.85}{
\begin{tikzpicture}[line join=round,font=\sffamily\small]
\tikzset{
 Line/.style={line width=0.35pt,black!50,text=black},
 ALineA/.style={violet!80!black!50,line width=3pt,shorten <=2pt,shorten >=2pt,
  {Triangle[width=1.1*6pt,length=0.8*6pt]}-{Triangle[width=1.1*6pt,length=0.8*6pt]}},
LineD/.style={line width=0.75pt,black!50,text=black,dashed,dash pattern=on 5pt off 3pt},
Circle/.style={inner xsep=2pt,
  circle,
    draw=BrownLine,
    line width=0.75pt,
    fill=BrownL!40,
    minimum size=16mm
  },
 circles/.pic={
\pgfkeys{/channel/.cd, #1}
\node[circle,draw=\channelcolor,line width=\Linewidth,fill=\channelcolor!10,
minimum size=2.5mm](\picname){};
        }
}
\tikzset {
pics/cloud/.style = {
        code = {\colorlet{red}{RedLine}
\begin{scope}[local bounding box=CLO,scale=0.5, every node/.append style={transform shape}]
\draw[red,fill=white,line width=0.9pt](0.67,1.21)to[out=55,in=90,distance=13](1.5,0.96)
to[out=360,in=30,distance=9](1.68,0.42);
\draw[red,fill=white,line width=0.9pt](0,0)to[out=170,in=180,distance=11](0.1,0.61)
to[out=90,in=105,distance=17](1.07,0.71)
to[out=20,in=75,distance=7](1.48,0.36)
to[out=350,in=0,distance=7](1.48,0)--(0,0);
\draw[red,fill=white,line width=0.9pt](0.27,0.71)to[bend left=25](0.49,0.96);

\end{scope}
    }
  }
}
%streaming
\tikzset{%
 LineST/.style={-{Circle[\channelcolor,fill=RedLine,length=4pt]},draw=\channelcolor,line width=\Linewidth,rounded corners},
 ellipseST/.style={fill=\channelcolor,ellipse,minimum width = 2.5mm, inner sep=2pt, minimum height =1.5mm},
 BoxST/.style={line width=\Linewidth,fill=white,draw=\channelcolor,rectangle,minimum width=56,
 minimum height=16,rounded corners=1.2pt},
 pics/streaming/.style = {
        code = {\pgfkeys{/channel/.cd, #1}
\begin{scope}[local bounding box=STREAMING,scale=\scalefac, every node/.append style={transform shape}]
\node[BoxST,minimum width=44,minimum height=48](\picname-RE1){};
\foreach \i/\j in{1/north,2/center,3/south}{
\node[BoxST](\picname-GR\i)at(\picname-RE1.\j){};
\node[ellipseST]at($(\picname-GR\i.west)!0.2!(\picname-GR\i.east)$){};
\node[ellipseST]at($(\picname-GR\i.west)!0.4!(\picname-GR\i.east)$){};
}
\draw[LineST](\picname-GR3)--++(2,0)coordinate(\picname-C4);
\draw[LineST](\picname-GR3.320)--++(0,-0.7)--++(0.8,0)coordinate(\picname-C5);
\draw[LineST](\picname-GR3.220)--++(0,-0.7)--++(-0.8,0)coordinate(\picname-C6);
\draw[LineST](\picname-GR3)--++(-2,0)coordinate(\picname-C7);
 \end{scope}
     }
  }
}
%data
\tikzset{mycylinder/.style={cylinder, shape border rotate=90, aspect=1.3, draw, fill=white,
minimum width=25mm,minimum height=11mm,line width=\Linewidth,node distance=-0.15},
pics/data/.style = {
        code = {\pgfkeys{/channel/.cd, #1}
\begin{scope}[local bounding box=STREAMING,scale=\scalefac, every node/.append style={transform shape}]
\node[mycylinder,fill=\channelcolor!50] (A) {};
\node[mycylinder, above=of A,fill=\channelcolor!30] (B) {};
\node[mycylinder, above=of B,fill=\channelcolor!10] (C) {};
 \end{scope}
     }
  }
}
\pgfkeys{
  /channel/.cd,
  channelcolor/.store in=\channelcolor,
  drawchannelcolor/.store in=\drawchannelcolor,
  scalefac/.store in=\scalefac,
  Linewidth/.store in=\Linewidth,
  picname/.store in=\picname,
  channelcolor=BrownLine,
  drawchannelcolor=BrownLine,
  scalefac=1,
  Linewidth=0.5pt,
  picname=C
}
\node[Circle](MO){};
\node[Circle,below right=0.85 and 2.5 of MO,draw=GreenLine,fill=GreenL!40,](IN){};
\node[Circle,below left=0.85 and 2.5 of MO,draw=OrangeLine,fill=OrangeL!40,](DA){};
\draw[ALineA](MO)--(IN);
\draw[ALineA](MO)--(DA);
\draw[ALineA](DA)--(IN);
\node[below=2pt of MO]{算法};
\node[below=2pt of IN]{机器};
\node[below=2pt of DA]{数据};
%%
\begin{scope}[local bounding box=CIRCLE1,shift={($(MO)+(0.04,-0.24)$)},
scale=0.55, every node/.append style={transform shape}]
%1 column
\foreach \j in {1,2,3} {
  \pgfmathsetmacro{\y}{(1.5-\j)*0.43 + 0.7}
  \pic at (-0.8,\y) {circles={channelcolor=RedLine,picname=1CD\j}};
}
%2 column
\foreach \i in {1,...,4} {
  \pgfmathsetmacro{\y}{(2-\i)*0.43+0.7}
  \pic at (0,\y) {circles={channelcolor=RedLine, picname=2CD\i}};
}
%3 column
\foreach \j in {1,2} {
  \pgfmathsetmacro{\y}{(1-\j)*0.43 + 0.7}
  \pic at (0.8,\y) {circles={channelcolor=RedLine,picname=3CD\j}};
}
\foreach \i in {1,2,3}{
  \foreach \j in {1,2,3,4}{
\draw[Line](1CD\i)--(2CD\j);
}}
\foreach \i in {1,2,3,4}{
  \foreach \j in {1,2}{
\draw[Line](2CD\i)--(3CD\j);
}}
\end{scope}
%
\pic[shift={(-0.4,-0.08)}] at (IN) {cloud};
%
\pic[shift={(-0.05,-0.13)}] at  (IN){streaming={scalefac=0.25,picname=2,channelcolor=RedLine, Linewidth=0.65pt}};
%
\pic[shift={(0,-0.3)}] at  (DA){data={scalefac=0.3,picname=1,channelcolor=green!70!black, Linewidth=0.4pt}};
\end{tikzpicture}}
Figure 1: 数据—算法—机器三轴图:以紧凑的诊断视图,将数据、算法和机器呈现为三个相互依赖的轴。双向连接强调,对一个轴的干预会改变另外两个轴上的约束。

初步识别轴后,table 2 将两两交叉和三轴交叉展开为具体的工程技术及其在本书中的主要对应章节。

Table 2: 数据—算法—机器交叉关系参考:每个区域都将具体技术映射到其跨越的轴以及涵盖这些技术的章节。两两交叉需要同时对两个领域进行推理;中心区域则需要同时考虑全部三个领域。
区域 名称 关键技术 本书涵盖章节
数据 信息 存储格式、数据质量、分布 数据工程
算法 逻辑 损失函数、架构、梯度 神经计算, 网络架构
数据 \(\cap\) 算法 从什么中学习 数据选择、课程学习、计算最优缩放 数据选择, 模型训练
数据 \(\cap\) 机器 如何移动信息 I/O 带宽、预取、数据格式 数据工程, 硬件加速
算法 \(\cap\) 机器 如何高效执行 量化、剪枝、算子融合、混合精度 机器学习框架, 模型压缩
机器 物理机制 芯片、内存层次结构、峰值 FLOP/s 硬件加速
数据 \(\cap\) 算法 \(\cap\) 机器 机器学习系统工程 铁律、Roofline、训练循环、模型服务 模型训练, 模型服务, 基准测试

在 D·A·M 这一缩写中,数据(Data)、算法(Algorithm)和机器(Machine)是分类体系的三个轴。它们不是数学变量;形式化量仍遵循符号章节的约定,其中 \(D\) 表示数据集大小或训练词元数。

以单个轴为中心的区域包含主要归属于该轴的概念:存储格式和分布侧重数据,损失函数和梯度侧重算法,芯片物理机制和峰值 FLOP/s 侧重机器。单一领域的专业知识足以引入这些概念,但系统部署后的行为仍可能依赖其他轴。

两两交叉是系统思维的起点。\(\mathsf{Data} \cap \mathsf{Algorithm}\)(从什么中学习)涵盖数据选择、课程学习、主动学习,以及 Chinchilla 等缩放定律(在所研究的稠密自回归语言模型设定下,\(D \approx 20P\))(Hoffmann et al. 2022)——这些都需要综合考虑信息含量和算法容量。增加数据而不考虑模型能否从中学习,会浪费计算资源;选择架构而不考虑数据可用性,会浪费工程时间。\(\mathsf{Data} \cap \mathsf{Machine}\)(如何移动信息)涵盖 I/O 带宽、预取策略、数据格式和能量—数据移动不变量。数据引力正是在这一交叉区域显现:字节在内存层次结构中移动的物理成本,决定了能否以足够快的速度向机器供给数据。\(\mathsf{Algorithm} \cap \mathsf{Machine}\)(如何高效执行)涵盖量化、剪枝、算子融合、混合精度和计算图优化。一种减少 FLOPs 却破坏内存访问模式的剪枝策略,可能使实际硬件上的执行变慢。

中心区域——\(\mathsf{Data} \cap \mathsf{Algorithm} \cap \mathsf{Machine}\)——是三个轴的汇合之处。铁律、Roofline 模型、端到端训练循环、模型服务流水线和整体基准测试,都需要同时考量数据流、算法复杂度和硬件利用率。这个中心并非某一种技术,而是这门学科本身。

全景图用于划分技术作用的区域,而要确定究竟是哪个轴在实际限制工作负载,就需要将这些关系转化为实际执行时间——这正是铁律的作用。

铁律映射

对于串行执行的各阶段,铁律将数据—算法—机器各轴上的工作映射为执行时间。这里,\(T\) 和 \(L_{\text{lat}}\) 是以秒为单位的时间;\(D_{\text{vol}}\) 是移动的字节数,\(\text{BW}\) 的单位是字节每秒;\(O\) 是以 FLOPs 为单位的工作量,\(R_{\text{peak}}\) 的单位是 FLOP/s,\(\eta_{\text{hw}}\) 是无量纲的硬件效率。这些量与各轴的映射关系如下: \[ T = \underbrace{ \frac{D_{\text{vol}}}{\text{BW}} }_{\text{Data/Machine}} + \underbrace{ \frac{O}{R_{\text{peak}} \cdot \eta_{\text{hw}}} }_{\text{Algorithm/Machine}} + \underbrace{ L_{\text{lat}} }_{\text{Cross-axis overhead}} \]

算法和机器共同对应计算项,二者按工程师所控制的变量区分。减少总运算量(\(O\))属于算法侧的优化手段,而提高硬件峰值吞吐量(\(R_{\text{peak}}\))或利用率(\(\eta_{\text{hw}}\))属于机器侧的优化手段。

这个方程将性能调试从定性的猜测转化为定量的工程问题。测得的主导成本会体现在这些项中的某一项。系统缓慢,可能是因为移动的数据过多(\(D_{\text{vol}}\))、带宽不足(\(\text{BW}\))、执行的运算过多(\(O\))、未能发挥硬件的峰值能力(\(\eta_{\text{hw}}\)),或承担了跨轴开销(\(L_{\text{lat}}\))。以下优化手段将具体优化映射到其改善的变量。

各组成部分的优化手段

  • 数据侧优化手段:通过去重、选择或低精度表示减少移动的字节数(\(D_{\text{vol}}\)),或提高 I/O 带宽(\(\text{BW}\))。
  • 算法侧优化手段:通过剪枝或架构改进减少运算量(\(O\))。量化降低表示位宽,并可能提高硬件吞吐量;它通常不会减少运算次数。
  • 机器侧优化手段:通过提高峰值吞吐量(\(R_{\text{peak}}\)),或利用算子融合提高利用率因子(\(\eta_{\text{hw}}\)),增大计算项的分母。

数据—算法—机器协同:从求和到取最大值

加法形式的铁律表示顺序执行。令 \(T_{\text{sequential}}\) 表示无重叠时的时间,\(T_{\text{pipelined}}\) 表示存在重叠时测得的时间。重叠可使总耗时从各项之和趋近于最大项,但依赖关系、资源争用和不完全重叠会使测得的时间高于这一理想下界: \[ T_{\text{sequential}} = \frac{D_{\text{vol}}}{\text{BW}} + \frac{O}{R_{\text{peak}} \cdot \eta_{\text{hw}}} + L_{\text{lat}} \quad \xrightarrow{\text{overlap}} \quad T_{\text{pipelined}} \geq \max\left(\frac{D_{\text{vol}}}{\text{BW}}, \frac{O}{R_{\text{peak}} \cdot \eta_{\text{hw}}}\right) + L_{\text{lat}} \]

系统工程师的任务是让这些组成部分并行运行,而非串行运行。Table 3 汇总了使各轴上的工作重叠执行的关键数据—算法—机器协同技术:

Table 3: 数据—算法—机器重叠执行技术:每种技术都使跨轴工作重叠执行,使原本顺序相加的数据/机器时间和算法/机器时间趋近于其理想下界,即两项中的较大值。依赖关系和资源争用限制了实际实现的重叠程度。
技术 重叠的数据—算法—机器轴 实现方式
预取 D 与 M 重叠 使用 prefetch_factor、pin_memory=True 的 DataLoader
CUDA 流 D 与 M 重叠 使用独立的流分别执行 H2D 传输和计算
异步梯度同步 M(通信)与 A 重叠 使分桶 AllReduce 与剩余的反向传播计算重叠
双缓冲 D 与 M 重叠 在缓冲区 N 上计算的同时填充缓冲区 N+1

当数据—算法—机器各时间项较为均衡时,重叠执行带来的相对加速最大。如果某一项占主导地位(例如严重受内存限制),将较小项与较大项重叠所带来的收益微乎其微——最大值仍由同一个瓶颈主导。这种均衡出现在 \(D_{\text{vol}}/\text{BW} \approx O/(R_{\text{peak}} \cdot \eta_{\text{hw}})\) 附近。延迟项需要单独处理。

Systems Perspective 1.1: 无法隐藏的开销
未被隐藏的延迟项 \(L_{\text{lat}}\)(算子启动、同步屏障、Python 调度)包含无法完全重叠的串行化点。算子融合可以通过合并操作来减小这一项,但无法消除所有启动、调度或同步开销。

铁律量化了各阶段消耗的执行时间,而要确定当前性能上限究竟由数据移动还是算术吞吐量决定,则取决于二者的比值——这属于算术强度的范畴。

算术强度边界

数据/机器内存项与算法/机器计算项之间的边界并非任意划定,而是由工作负载的算术强度1(\(I\))在数学上定义的。

当数据流量和实际达到的速率采用一致口径测量时,Roofline 模型能够给出性能上界。在生产事故处理中,更快捷的筛查启发式方法可以指引下一步应收集哪些测量数据。

经验法则

生产系统发生故障时,通常没有时间求解完整的铁律方程。经验丰富的系统工程师会依靠定量启发式方法快速缩小排查范围;以下阈值属于筛查信号,应结合性能剖析轨迹和硬件计数器进行核实。

  • 加速器利用率低(\(<\) 80%):排查数据、CPU 或算子启动供给不足。通过输入流水线等待时间、主机 CPU 饱和情况、内存带宽计数器和执行轨迹中的空隙加以确认。
  • 加速器利用率高(\(>\) 95%):只有在计算单元繁忙且内存带宽未饱和时,才将其视为受机器限制。如果内存带宽已饱和,瓶颈仍位于数据/机器边界。
  • 如果批量大小为 1:将其视为延迟或启动开销可能产生影响的警示;在将算法本身判定为瓶颈之前,应先通过执行轨迹确认。
  • 算术强度低(低于硬件拐点):工作负载很可能受内存限制(位于数据/机器边界)。精确边界为 \(R_{\text{peak}}/\text{BW}\),取决于硬件和精度。
  • 如果系统在开发环境中正常,却在生产环境中失效:将数据漂移列为假设之一,同时考虑配置、负载、依赖项和运行时的差异。

行业中的常见标签往往跨越多个轴。受内存限制的执行位于数据/机器边界,因为移动的字节数和可用带宽都很重要。受计算限制的执行将算法工作量与机器吞吐量联系起来。受延迟限制的执行可能反映算法的串行深度、运行时调度、同步或排队的影响。

瓶颈诊断

一旦性能剖析识别出铁律中的主导项,优化就必须针对相应的轴。Table 4 对比了能够带来端到端加速的干预措施,以及针对非约束项、因而浪费工程精力的优化:

Table 4: 有效与徒劳的优化:优化非约束项,对端到端性能的改善很小,甚至毫无改善。受内存限制的大语言模型不会仅因峰值 FLOP/s 增加而获益,但内存带宽更高的加速器可能有所帮助。
如果工作负载…… 主导项 有效的优化 徒劳的优化
受内存限制 \(D_{\text{vol}}/\text{BW}\) 量化;结构化剪枝;通过批处理复用权重;消除中间数据流量的融合 更快的加速器(更高的 FLOP/s 无济于事)
受计算限制 \(O/(R_{\text{peak}} \cdot \eta_{\text{hw}})\) 更优的算子实现、Tensor Core、更快的加速器、更低的精度 更高的内存带宽(并非构成约束的项)
受延迟限制 \(L_{\text{lat}}\) 降低串行深度;融合或异步调度;在预算范围内进行批处理 更多计算资源或更高带宽,除非执行轨迹表明它们构成约束

了解哪些方法有效,也意味着要识别哪些方法无效。在实践中,面临交付期限压力的团队会反复落入相同的陷阱——信心十足地优化了错误的维度。这些失效模式十分常见,值得分别命名。

反模式

系统诊断往往是一个逐步排除的过程。在投入复杂的内核优化之前,应警惕以下浪费工程精力的常见陷阱。

  • 硬件拐杖:购买更快的加速器(机器),以解决 Python 数据加载器缓慢(数据)的问题。新硬件只会更快地进入空闲状态。
  • 模型微调折腾:实际瓶颈是网络带宽或磁盘 I/O,却不断更换神经网络架构(算法)。
  • 过早优化:尚未确认算法是否只是执行了过多不必要的操作,就开始编写自定义 CUDA 内核(机器)。

每种反模式都有相同的根源:未诊断就行动。以下案例展示了正确的诊断方式——从令人困惑的症状出发,系统地将范围缩小到起主导作用的数据—算法—机器维度。

数据—算法—机器案例研究

理论约束在生产环境中往往表现为令人困惑的症状。这些具有代表性的场景说明了如何应用这一分类体系。每个案例都遵循相同的三个诊断步骤:症状、诊断和修复。

案例 1:供给不足的加速器(数据)

某团队配置了大型 A100 GPU 实例以加速训练,但训练时间几乎没有改善,nvidia-smi 显示 GPU 利用率在 10% 到 40% 之间波动。这种模式提示加速器供给不足,但并不能确定其原因。如果跟踪记录显示存在等待输入的空档,同时存储或 CPU 解码已饱和,那么数据路径就是制约因素。此时,有效的干预应位于模型的上游。可以优化抽取、转换、加载(ETL)路径:将需要大量 CPU 解码的原始 JPEG 文件改为 TFRecords 或 WebDataset 等顺序格式,提高数据加载器的并行度,并将批次预取到加速器内存中。

案例 2:延迟悬崖(跨维度)

某实时推荐服务无法满足 20 ms 延迟的服务级别协议(SLA),与此同时,加速器利用率较低,批大小为 1。这种组合提示问题可能来自启动开销、内存流量或模型的串行深度,而非芯片饱和。如果跟踪记录确认顺序层执行路径占主导地位,增加硬件并不能消除该路径,因此可通过剪枝或知识蒸馏减少模型工作量。如果占主导地位的是权重传输,则可以在精度允许的情况下使用 INT8 量化,以减少搬运的字节数。应由测量结果决定解决方案。

案例 3:计算瓶颈(机器)

加速器利用率始终保持在 99%,内存带宽尚未饱和,训练过程稳定,但需要三周才能完成。如果性能分析器计数器还显示计算流水线占用率和模型 FLOPs 利用率(MFU)均较高,那么该工作负载受计算限制。数据路径能够持续满足加速器的供给需求,因此下一步必须改变机器学习系统铁律中的计算项。团队可以将 A100 升级为 H100 级加速器,通过数据并行进行横向扩展,或在数值安全的前提下将精度从 FP32/TF32 降为 BF16。在 NVIDIA Tensor Core 执行路径上,BF16 的峰值吞吐量通常约为 TF32 峰值的 2\(\times\),实际加速效果取决于内核和瓶颈 (Choquette 2023)。综合这三个案例可见,同一个利用率数值可能对应不同的后续措施,具体取决于损失变化、批大小和内存压力。

Choquette, Jack. 2023. “NVIDIA Hopper H100 GPU: Scaling Performance.” IEEE Micro 43 (3): 9–17. https://doi.org/10.1109/mm.2023.3256796.
Checkpoint 1.1: 数据—算法—机器诊断检查
  1. 某训练任务的加速器利用率为 95%,但损失已连续两个训练轮次停滞。哪些数据—算法—机器维度可能对此负责?为什么仅凭利用率不足以区分它们?
  2. 对于一个 nvidia-smi 显示 GPU 利用率为 98% 的任务,你的同事建议增加数据加载器工作进程。在判断这一措施是否有效之前,需要哪些跟踪证据?
  3. 某推理服务器在批大小为 1 时满足延迟 SLO,但在批大小为 16 时无法满足。机器学习系统铁律中的哪些项以及哪些排队效应可能发生了变化?哪些测量能够确定起制约作用的运行区间?

这三个案例展示了跨越多个维度的瓶颈。在实际生产事故中,症状经常相互重叠,主导瓶颈也可能随着优化落地而动态转移。系统化排除需要对照结构化诊断矩阵,筛查性能分析器信号。

生产环境故障排查

识别性能瓶颈的根本原因需要系统化排除。Table 5 提供了一个诊断矩阵,将常见生产故障模式映射到候选维度及用于验证的测量。

Table 5: 数据—算法—机器诊断矩阵:常见故障的初始假设及测量依据。干预之前,应先确认起制约作用的组件。
症状 假设 确认依据 确认后的措施
加速器利用率低 数据/主机供给不足 跟踪空档;加载器、CPU、存储、启动计数器 预取、并行化或减少启动次数。
延迟高(P99) 算法/运行时/队列 各阶段 p99 和队列深度 优化占主导地位的阶段。
训练成本高 有效工作效率低 MFU、通信、空闲时间 减少最大的效率损失,或调整资源规模。
GPU 间开销高 受通信限制 设备跟踪;集合通信空档 对 AllReduce 分桶;调优数据并行中的通信与计算重叠。
内存不足(OOM) 算法与机器的适配问题 权重、状态、激活值的峰值内存占用 使用激活检查点、分片、量化或缩小批大小。

工具映射

诊断假设需要具体的硬件和运行时计数器作为依据,之后才能采取纠正措施。Table 6 将理论上的数据—算法—机器组成部分与能够揭示其状态的具体 Linux 和 Python 性能分析工具联系起来。

Table 6: 数据—算法—机器工具映射:用于诊断各数据—算法—机器维度瓶颈的性能分析工具。首先使用主要工具进行快速排查;当主要工具的输出无法得出明确结论时,再使用辅助工具进行深入分析。
维度 关键指标 主要工具 辅助工具
数据 批次加载与等待时间 框架性能分析器跟踪 iostat、pidstat(I/O/CPU)
算法 FLOPs、模型深度 PyTorch Profiler DeepSpeed Flops Profiler
机器 加速器利用率、SM 占用率 Nsight Compute nvidia-smi、Nsight Systems

性能分析工具会生成利用率百分比、FLOP 计数和带宽测量值等原始指标,只有结合工作负载约束进行评估,这些指标才能指导行动。数据—算法—机器评分卡提供的是筛查信号,而非通用评级,用于识别哪些测量结果值得立即干预。

数据—算法—机器评分卡

为了超越定性猜测,table 7 中的效率指标可帮助确定下一步应调查什么。这种成绩单式视图有助于初步比较,但其中任何一行都不能给出通用评级。MFU2 对大模型训练尤其有用。

Table 7: 数据—算法—机器筛查指标:用于调查的信号依赖具体情境,并非通用评级。
维度 指标 定义 需要调查的信号 强信号
数据 I/O 开销 \(\dfrac{\text{Data Wait Time}}{\text{Total Step Time}}\) \(>\) 10%(筛查) \(<\) 1%(强信号)
算法 可避免的工作 性能分析或消融实验发现冗余操作 发现冗余工作 端到端工作量下降
机器 MFU \(\dfrac{\text{Achieved model FLOP/s}}{\text{Peak FLOP/s}}\) \(<\) 30%(大模型) \(>\) 50%(相同运行区间)

评分卡和 Roofline 模型都回答效率问题,但所处尺度不同。评分卡使用依赖具体情境的指标筛查当前系统。缩放定律和信息 Roofline 隐喻则探讨系统规模超出当前水平后可能发生什么。

缩放定律与 Roofline

系统工程需要区分增长轨迹与根本极限。

缩放定律(行进路径)

缩放定律3是经验幂律,用于预测在拟合适用区间内,留出集损失如何随资源增加而变化。两项里程碑式成果分别是 Kaplan 缩放定律 (Kaplan et al. 2020),它研究了损失与参数量(\(P\))、数据量(\(D\))和总运算量(\(O\))的关系;以及 Chinchilla 缩放定律 (Hoffmann et al. 2022),它针对所研究的稠密自回归语言模型区间估计了计算最优的平衡关系,通常概括为每个参数约对应 20 个训练词元(\(D \approx 20P\))。

作为资源投入的经济性指南,这些拟合关系估计了在观测区间内,留出集损失如何随计算量变化。它们既不保证任务错误率会下降,也不能不加改变地外推到不同架构和数据分布。

信息 Roofline(目的地)

这里将信息 Roofline用作诊断隐喻,而非标准定量定律。其目的地意象指向从现有数据中能够学到什么的极限。对于数据分布和损失函数固定的分类问题,贝叶斯错误率4是不可约的错误率下限,而非上限。噪声、标签歧义、覆盖缺口和分布偏移可能造成数据质量方面的限制,但它们并不定义一个通用的斜率或转折点。

由此得到的诊断启示更为有限。缩放定律描述拟合得到的改进轨迹,而信息 Roofline 隐喻促使我们寻找数据质量方面的限制。如果损失曲线相对于拟合趋势趋于平坦,应调查优化、容量、评估噪声和数据质量;仅凭曲线变平,无法确定哪种原因占主导地位。贝叶斯下限描述的是针对指定分布能够实现的最优分类器。只有在测量证实数据质量构成制约之后,增加加速器或参数才是徒劳的。无论是在调试训练步骤、评估硬件利用率,还是规划规模扩展,都应先测量哪个维度构成制约,再选择调整手段。

总结

这些工具构成了一套统一的诊断工作流。数据—算法—机器框架将候选原因定位到数据、算法和机器三个维度。机器学习系统铁律和算术强度将这些原因转化为时间、运算量和字节数,而案例研究、反模式、工具映射和评分卡则展示了如何在生产环境中检验它们。随后,缩放定律和信息 Roofline 将观测到的改进轨迹与数据质量限制区分开来。应将这一框架用作循环流程,而非标签。

要点回顾: 首先应检查什么
  • 从跨维度假设入手;症状很少能直接确定其原因。
  • 将每个假设转化为机器学习系统铁律中的相关项,以及能够证伪该假设的测量。
  • 使用算术强度和评分卡识别起制约作用的约束,而非给出通用评级。
  • 应用相应的调整手段,并重新进行端到端测量;如果局部收益未改变起制约作用的项,就不能算作系统改进。
Back to top

Footnotes

  1. 算术强度:本书使用该术语表示每传输一个字节所执行的浮点运算次数。Williams et al. (2009) 将 Roofline 模型中测得的 DRAM 对应量称为操作强度。将工作负载的这一比值与硬件的拐点(\(R_{\text{peak}}/\text{BW}\))比较,可以从性能上界的角度诊断执行是受内存限制还是受计算限制。↩︎

  2. MFU(模型 FLOPs 利用率):实际达到的模型 FLOP/s 与硬件理论峰值 FLOP/s 之比,由 PaLM 论文提出 (Chowdhery et al. 2022)。原始加速器利用率会计入加速器执行的任何工作,而 MFU 衡量的是模型计算速率相对于硬件峰值吞吐量的比例,因此非模型工作和系统开销不计入实际达到的模型 FLOPs。识别瓶颈 将详细阐述如何使用 MFU 诊断训练。↩︎

  3. 缩放定律:经验关系,通常是带有拟合负指数的幂律,用于根据数据集规模、参数量或计算预算预测模型损失。Kaplan et al. (2020) 在 OpenAI 的神经语言模型研究中考察了这些关系;Hoffmann et al. (2022) 随后针对其研究的稠密语言模型区间,估计了计算最优的训练权衡。计算最优前沿 将详细阐述计算最优前沿及其数据供给不足诊断方法。↩︎

  4. 贝叶斯错误率:在给定数据分布上,任何分类器在 0–1 损失下能够达到的最低错误率,由类别先验和类条件分布之间的重叠程度决定 (Goodfellow et al. 2016)。无论增加多少数据、参数或计算量,都无法将错误率降至这一理论下限以下。↩︎

Williams, Samuel, Andrew Waterman, and David Patterson. 2009. “Roofline: An Insightful Visual Performance Model for Multicore Architectures.” Communications of the ACM 52 (4): 65–76. https://doi.org/10.1145/1498765.1498785.
Chowdhery, Aakanksha, Sharan Narang, Jacob Devlin, Maarten Bosma, Gaurav Mishra, Adam Roberts, Paul Barham, et al. 2022. “PaLM: Scaling Language Modeling with Pathways.” arXiv Preprint arXiv:2204.02311.
Kaplan, J., S. McCandlish, T. Henighan, T. B. Brown, B. Chess, R. Child, S. Gray, A. Radford, J. Wu, and D. Amodei. 2020. “Scaling Laws for Neural Language Models.” ArXiv Preprint abs/2001.08361.
Hoffmann, Jordan, Sebastian Borgeaud, Arthur Mensch, Elena Buchatskaya, Trevor Cai, Eliza Rutherford, Diego de Las Casas, et al. 2022. “Training Compute-Optimal Large Language Models.” Advances in Neural Information Processing Systems (NeurIPS) 35: 30016–30. https://doi.org/10.52202/068431-2176.
Goodfellow, Ian, Yoshua Bengio, and Aaron Courville. 2016. Deep Learning. MIT Press.
← 中文书架