设想你是一名登山爱好者,为了清晨在山顶看日出,背着一只 10 升的小包出发。山路上有 24 个观景台,每个台子的风景都值得拍照。可向导叮嘱:下山时每到一处岔路口,都要翻看对应的照片才能辨清方向。于是你每过一个观景台就拍一张高清大图,一张张塞进背包。拍到第 6 个台子,背包已经鼓得拉不上拉链——而山路才走了四分之一。 这就是深度神经网络训练时的真实困境:模型把前向传播每一层算出的“中间激活值”都留在显存里,留给反向传播算梯度时当“路标”使用。层数越多、序列越长、batch 越大,显存就越吃紧,许多大模型甚至还没开始训练,就弹出了"out of memory"。 梯度检查点(Gradient Checkpointing)提供的,正是老登山客的智慧:不必每个观景台都拍照,只在少数几个关键位置留影;遇到岔路发现没照片时,就退回最近的有照片的台子,重走那段路,现场补拍。虽然多花了一些脚程(计算),但背包(显存)一下子轻了一大半。

岗位关联

对 AI 从业者而言,梯度检查点是突破“显存墙”的必备技能。掌握它,你就能在有限的 GPU 上训练更大的模型,读懂大模型训练框架中那些隐形设计,从容应对训练 OOM 与效率权衡。

目录
  1. 可视化演示
  2. 显存瓶颈:背包爆满
  3. 核心原理:隔站拍照
  4. 检查点策略:补给站选址
  5. 时间开销:来回折返的代价
  6. 工程实践:PyTorch 落地
  7. 高级优化:老驴友的省力心得
  8. 应用边界:雪山与险峰
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示梯度检查点三维度:前向保存与反向重计算流程(仅checkpoint层保存激活其余反向时重计算内存从O(n)降至O(√n))、显存对比(标准训练激活占55%检查点降至12%总显存减少约50%LLaMA 65B batch从1提升至4-5)、选择性检查点策略(按计算-内存比决策高计算低成本层设为checkpoint低计算高内存层重算),三模式切换理解用计算换内存的核心机制。

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

'+C1+'

显存瓶颈:背包爆满

设想你背着一只 10 升的小包去登山,目标是清晨在山顶看日出。向导反复叮嘱:下山时每到一个岔路口,都要翻看对应的风景照才能找对路。你生怕漏掉任何信息,于是经过 24 个观景台时都拍一张高清大图,一张张往包里塞。第 6 个台子还没到,背包就鼓得再也装不下一瓶水。

神经网络训练也有类似的下山之路。前向传播从输入层一路计算到输出层,每一层都会产生“中间激活值”——它是反向传播计算梯度时必不可少的“路标”。深度学习框架为了避免重复计算,默认把这些激活值全部保留在显存里,相当于把每张照片都背在身上。模型越深、序列越长、批量越大,显存压力就越大,训练常常还没开始就报"out of memory"。

若网络有 N 层、每层激活占用 m_layer 字节,激活占用的显存为:

24 层网络每层激活 2MB,一次前向就要在显存里堆 48MB 的“照片”;真实的大模型动辄上百层、每层激活数百 MB,背包自然瞬间爆满。所以,想轻装上山,只能选择少带照片。

Mfull=N×mlayer\displaystyle M_{\text{full}} = N \times m_{\text{layer}}
显存随层数线性增长,这就是“照片全塞进背包”的总重量:层数乘以单层激活体积。
  1. 层数 N神经网络中需要保存激活值的层数。N 越大,显存中需要常驻的激活值“份数”越多。
    N\displaystyle N
  2. 单层激活体积 m_layer每一层前向传播产生的中间结果大小,与隐藏维度、序列长度直接相关。
    mlayer\displaystyle m_{\text{layer}}
  3. 总激活显存 M_fullN 与 m_layer 相乘,得到全部中间激活占用的显存总量,相当于“每层一张照片”的总重量。
    Mfull=N×mlayer\displaystyle M_{\text{full}} = N \times m_{\text{layer}}

核心原理:隔站拍照

老登山客的办法很简单:不在每个观景台都拍照,只在每隔几个台子选一个“补给兼摄影点”。比如 24 站只拍第 4、8、12、16、20、24 站的风景。遇到岔路,就回到最近的照片点,重走那一段,到岔路时再看一眼路况——虽然多走几步,但背包一下子轻了 75%。

梯度检查点正是这个思路。前向传播时只保存少数几层的激活值,这些位置叫作“检查点”(Checkpoint),其余中间激活直接丢弃。反向传播需要某一层的激活时,从最近的检查点重新执行这一段前向计算,现场“补拍”一张。这样既保留了“路标”,又不必把全部照片背在身上。

设网络共 N 层,均匀分成 k 段,只存 k 个检查点;反向时每段临时重算,激活峰值不超过一段的长度:

当 k = √N 时取最小值:M_ckpt ≈ 2√N × m_layer。显存占用从 O(N) 降到了 O(√N)。

以 24 层、每层 2MB 为例:全部保存需要 48MB,而取 k≈5 时,检查点方案只需约 20MB。隔站拍照,让一只 10 升的小背包也能装下 24 站的“路书”。

Mckpt=k×mlayer+Nk×mlayer\displaystyle M_{\text{ckpt}} = k \times m_{\text{layer}} + \frac{N}{k} \times m_{\text{layer}}
公式左边是检查点照片占用的空间,右边是“现场补拍”时手里最多同时拿着的照片数,两者相加就是背包的新重量。
  1. 检查点总数 k我们总共保存 k 份激活,每份大小为 m_layer,这部分是“已拍好的照片”。
    k×mlayer\displaystyle k \times m_{\text{layer}}
  2. 段内重算临时激活N/k 是每段包含的层数,反向重算段内激活时,缓存里最多出现一段的激活量。
    Nk×mlayer\displaystyle \frac{N}{k} \times m_{\text{layer}}
  3. 最优分段数 k = √N对 k 求极值可知,当 k 等于 √N 时两者之和最小。
    k=N\displaystyle k = \sqrt{N}
  4. 最小显存 2√N × m_layer代入 k = √N,得到检查点方案的最优显存规模。
    Mckpt=2N×mlayer\displaystyle M_{\text{ckpt}} = 2\sqrt{N} \times m_{\text{layer}}

检查点策略:补给站选址

隔几站拍一次?拍得太密,背包依然很重;拍得太疏,来回折返的腿脚受不了。有经验的向导会先看地形:陡坡、岔路多的地方多拍几张,平直大道少拍甚至不拍。检查点的位置,本质上是一个“补给站选址”问题。

朴素做法是均匀分段,把 N 层等分成 k 段,每段长度 S = N/k,简单且容易实现。进阶做法是考虑每层的计算密度与激活体积:激活特别大的层(比如注意力层、大分辨率特征图)优先设为检查点,因为“省下”的显存最多;而重算成本低的层(如激活函数、归一化)也适合作为检查点,因为补拍代价小。

工程上常用动态规划或贪心搜索来求解最优分段。假设各段长度为 L₁, L₂, ……, L_k,重算子层数越多代价越高,优化目标可写为:

好的选址策略,是均匀打底、关键层优先、搜索兜底。就像老向导知道每条山路的脾气,优秀的调度器能把“少拍照、多跑腿”的平衡点拿捏得恰到好处。

min⁡L1,…,Lk∑i=1kLi22,s.t.∑i=1kLi=N\displaystyle \min_{L_1,\dots,L_k} \sum_{i=1}^{k} \frac{L_i^2}{2}, \quad \text{s.t.} \quad \sum_{i=1}^{k} L_i = N
段长平方表示“补拍一段前向”的工作量:段越长,折返爬山的脚程越长。均匀分段时每段 L_i = N/k,总代价为 N²/(2k),随 k 增大而下降。
  1. 段长 L_i第 i 段包含的层数,段长决定了一次重算需要跑多远。
    Li\displaystyle L_i
  2. 平方项 L_i²/2重算子层数的代价不能简单叠加,它随段长近似平方增长,体现出“越长的回头路越累”。
    Li22\displaystyle \frac{L_i^2}{2}
  3. 求和符号把所有段的折返代价加总,得到整个网络的反向重算总成本。
    ∑i=1kLi22\displaystyle \sum_{i=1}^{k} \frac{L_i^2}{2}
  4. 约束条件所有段长加起来必须等于总层数 N,选址不能凭空多出或漏掉楼层。
    ∑i=1kLi=N\displaystyle \sum_{i=1}^{k} L_i = N

时间开销:来回折返的代价

隔站拍照不是免费的午餐。每退回一个摄影点重走一段路,都要额外花时间。如果照片拍得太少,你可能会在同一个坡上来回爬三趟,日出都过了还没到山顶。梯度检查点同样要付出“重计算”的时间成本。

原本一次训练迭代包含一次前向传播和一次反向传播。前向计算量记为 F,反向传播大约是前向的两倍(经验值 2F),那么基准迭代成本是 3F。启用检查点后,反向传播每遇到一段没有照片的路,都要从最近检查点补跑一次该段前向;近似来看,整网前向被“重跑”了一半到一遍,额外增加约 F 的计算量:

在显存受限的 GPU 上,这 33% 的时间开销往往远比“模型根本无法训练”更划算。也是为什么大模型训练普遍愿意接受这份学费。

Tbase=F+2F=3F\displaystyle T_{\text{base}} = F + 2F = 3F
Tckpt=F+2F+F=4F\displaystyle T_{\text{ckpt}} = F + 2F + F = 4F
TckptTbase=4F3F≈1.33\displaystyle \frac{T_{\text{ckpt}}}{T_{\text{base}}} = \frac{4F}{3F} \approx 1.33
用 33% 的额外时间,换来接近 √N/N 的显存缩减——这是“时间换空间”最典型的交易。
  1. 前向量 F一次前向传播的浮点计算总量,是模型的“单程爬山”成本。
    F\displaystyle F
  2. 反向量 2F反向传播要计算梯度,通常约为前向的两倍,相当于下山的体力消耗。
    2F\displaystyle 2F
  3. 额外前向 +F检查点方案在反向期间至少补跑一次前向,所以总成本多出一个 F。
    Tckpt=4F\displaystyle T_{\text{ckpt}} = 4F
  4. 比值 4/3 ≈ 1.33总时间约为原来的 1.33 倍,即训练时间增加约 33%。
    43≈1.33\displaystyle \frac{4}{3} \approx 1.33

工程实践:PyTorch 落地

有了策略,还得有趁手的工具。就像买好了登山杖和摄影绳,照着步骤操作就能上路。PyTorch 把梯度检查点做成了开箱即用的接口,不需要自己发明轮子。

核心接口是 torch.utils.checkpoint.checkpoint。它接受一个网络模块和输入,在前向传播时只保留输入,不保存中间激活;反向传播时,它会在内部自动重新执行一次该模块的前向,把激活“补拍”出来,再用于梯度计算。

启用检查点后,理论上节省的显存为:

实际使用时,把模型中每个 Transformer Block 整体包进 checkpoint 即可,例如 output = checkpoint(block, x)。框架还提供了 torch.utils.checkpoint.checkpoint_sequential,适合顺序模型直接按段划分。需要注意的是,启用后显存变量明显下降,但训练日志里的耗时也会相应上升——这正是前几节反复强调的取舍。

Msaved=Mfull−Mckpt=(N−2N)×mlayer\displaystyle M_{\text{saved}} = M_{\text{full}} - M_{\text{ckpt}} = \left(N - 2\sqrt{N}\right) \times m_{\text{layer}}
对 24 层网络,约能省下 28MB(以每层 2MB 计),节省幅度超过一半。层数越多,这个优势越明显。
  1. 省下的层数份数 N − 2√N全存需要 N 份激活,检查点方案只需约 2√N 份,差额就是省下的显存“份数”。
    N−2N\displaystyle N - 2\sqrt{N}
  2. 单层激活 m_layer每份激活的体积,把“份数”换算成实际字节数,就是能省下的显存。
    (N−2N)×mlayer\displaystyle \left(N - 2\sqrt{N}\right) \times m_{\text{layer}}

高级优化:老驴友的省力心得

资深向导登山时从不蛮干:下坡不走回头路、把器材捆在一起背、天快亮时集中赶路。梯度检查点同样有一整套“省力组合拳”,让省出来的显存进一步放大。

其一是算子融合。把相邻的重算子(如卷积+激活、注意力+归一化)合并成一个算子,前向时不必把中间结果显式写出,重算时的临时显存也会变小。其二是混合检查点:显存大头通常集中在少数大激活层(如注意力矩阵、高分辨率特征图),只对约三分之一的大层设置检查点,其他小激活层照常保留,往往能得到 70% 以上的显存节省,而重算开销远低于均匀分段。

混合策略的显存模型为:

其中 𝒞 是设置了检查点的层集合,S_max 是未设置检查点的连续段中的最大段长。

配合内存调度(把参数或优化器状态暂存到 CPU,用时再取回),这套组合拳让现代大模型训练几乎把梯度检查点当作默认标配。LLaMA、GPT 等大规模预训练,无一不在用它把单位 GPU 的吞吐压榨到极限。

Mmixed=∑i∈Cmi+Smax⁡×mlayer\displaystyle M_{\text{mixed}} = \sum_{i \in \mathcal{C}} m_i + S_{\max} \times m_{\text{layer}}
第一项是所有检查点占用的空间,第二项是反向重算时峰值不超过最长的未检查点段。合理挑选 𝒞,可以让两个加数都尽量小。
  1. 集合 𝒞被选中做检查点的层集合,通常优先放激活体积大的层。
    C\displaystyle \mathcal{C}
  2. 检查点占用之和对集合中每一层 m_i 求和,得到所有检查点照片的总空间。
    ∑i∈Cmi\displaystyle \sum_{i \in \mathcal{C}} m_i
  3. 最大未检查点段 S_max没有设置检查点的连续段里,最长的一段长度,它决定了重算时的临时显存峰值。
    Smax⁡×mlayer\displaystyle S_{\max} \times m_{\text{layer}}

应用边界:雪山与险峰

隔站拍照不是万能钥匙。雪山上步距大、掉头难,如果折返距离太长,不如多带几张照片。梯度检查点也有明确的适用边界:当计算极度紧张、训练时长成为首要矛盾时,33% 的额外开销就变得难以接受;当模型本身不大、显存绰绰有余时,它更是多此一举。

一个实用的判据是:检查点启用后,激活显存、参数显存、梯度显存三者之和必须不超过设备显存:

梯度检查点是显存应急预案,而非银弹。理解它的边界,才能在大模型训练中做出清醒的权衡:何时用它救命,何时配合其他并行手段,何时干脆放弃。把这套“隔站拍照”的智慧用在正确的地方,你就能在显存的悬崖边,稳稳地走向更大的模型。

Mckpt+Mparam+Mgrad≤Mlimit\displaystyle M_{\text{ckpt}} + M_{\text{param}} + M_{\text{grad}} \le M_{\text{limit}}
只有当不等式成立,梯度检查点才是有效解药;否则还要叠加序列并行、张量并行或卸载等手段。
  1. 激活显存 M_ckpt启用检查点后中间激活占用的峰值显存。
    Mckpt\displaystyle M_{\text{ckpt}}
  2. 参数显存 M_param模型权重本身占用的空间,与是否检查点无关。
    Mparam\displaystyle M_{\text{param}}
  3. 梯度显存 M_grad反向传播累积的梯度所占空间,同样不可省略。
    Mgrad\displaystyle M_{\text{grad}}
  4. 设备显存上限 M_limitGPU 的总显存容量。三者和超过上限,模型依然装不下。
    Mlimit\displaystyle M_{\text{limit}}

AI 应用场景

大语言模型预训练

阶段:模型训练 / 显存优化

解决的问题:GPT、LLaMA 等大模型训练时,激活值动辄占用数十甚至上百 GB 显存,传统方式下单卡根本放不下。梯度检查点把激活显存从 O(N) 降到 O(√N),让数百亿参数模型可以在有限的 A100/H100 集群上启动训练。

具体案例:某团队预训练 130 亿参数的 LLaMA 规模模型,原本每个 Transformer 层激活需要 4.2GB,启用 torch.utils.checkpoint 后单层激活降到 1.1GB,配合混合精度,总算力不变的情况下把 batch size 提升了 2 倍,训练吞吐反而更优。

长序列视觉 Transformer

阶段:模型推理 / 微调适配

解决的问题:视频理解、高分辨率遥感影像等任务,输入序列极长,注意力矩阵的激活值呈平方级爆炸。传统方法要么切短序列损失信息,要么爆显存。梯度检查点让长序列微调成为可能。

具体案例:某安防团队微调 ViT-Large 处理 4096 帧视频,激活显存超 80GB;将每 4 层设一个检查点后,显存降至 26GB,单张 A100 即可完成微调,代价仅是训练时间增加约 35%。

云上多卡训练成本优化

阶段:训练基础设施 / 成本控制

解决的问题:云 GPU 按小时计费,模型太大导致必须租用更高配实例或更多卡。梯度检查点能以 33% 的时间换 50% 以上的显存,帮助团队用更少的卡跑同一个模型,总成本反而下降。

具体案例:某创业公司在 4×A10 上训练 7B 对话模型,启用混合检查点 + 梯度累积后,从 8 卡降为 4 卡,训练时长仅增加 28%,月度 GPU 账单减少约 45%。

Python 演示

python28 行
# 梯度检查点:前向激活显存模拟器def simulate_full(num_layers, act_size_mb):    total = 0    for i in range(num_layers):        total += act_size_mb    return total def simulate_checkpoint(num_layers, act_size_mb, num_segments):    seg_len = num_layers / num_segments    checkpoints = num_segments * act_size_mb    temp_acts = seg_len * act_size_mb    return checkpoints + temp_acts def main():    L = 24    m = 2.0    full_mem = simulate_full(L, m)    print("[模拟] 24 层网络,每层激活 2MB")    print("不启用梯度检查点: 显存 = %.1f MB" % full_mem)    print("启用梯度检查点:")    for k in [1, 2, 4, 5, 6, 8, 12, 24]:        mem = simulate_checkpoint(L, m, k)        ratio = mem / full_mem * 100        print("  分段 %2d: 显存 = %5.1f MB  为原来的 %4.1f%%"              % (k, mem, ratio)) if __name__ == "__main__":    main()
目的:用简单的累加公式模拟神经网络前向激活的显存占用,直观对比“全部保存”与“梯度检查点”两种策略在不同分段数下的显存差异。
  1. for i in range(num_layers)模拟框架逐层把激活值留在显存里,一层累加一层。
  2. total += act_size_mb每层的激活体积累加进总显存,体现线性增长。
  3. seg_len = num_layers / num_segments平均每段包含的层数,决定反向重算的临时显存峰值。
  4. checkpoints = num_segments * act_size_mb检查点照片本身占用的空间,分段越多照片越多。
  5. temp_acts = seg_len * act_size_mb反向补拍一段时临时占用的激活空间,段越长临时显存越大。
  6. ratio = mem / full_mem * 100算出检查点方案相当于原始显存的百分比,一眼看出最优分段在中间。

常见误区

误区我以为梯度检查点像是“压缩照片”,省了显存,拍出来的“路标”变模糊了,所以模型精度应该会下降。

正解梯度检查点并不会丢弃任何信息,只是把中间激活“推迟”到反向传播时重新计算。重算出来的激活值与原来完全一致(数值上可能有浮点级微小差异,但不影响训练结果)。它改变的是显存与时间的分配,而不是数据精度。

为何常见:人们容易把“省显存”和“省精度”混为一谈,看到名字里有“检查点”就联想到模型压缩或量化。

误区既然分段能省显存,那我就把每层都设成检查点,分 24 段,显存应该省到极限吧?

正解分段数 k 有一个最优值。从公式 M_ckpt = k·m + (N/k)·m 可以看出,k 太大时检查点本身占用的显存会上升;k 太小则重算临时显存增加。最优在 k ≈ √N 附近。比如 24 层时 k=5 最省,k=24 时显存反而接近全保存的水平。

为何常见:只看到“间隔保存”的直觉,忽略了检查点本身也要占空间,重算段也有临时开销,于是滑向极端取值。

误区都是省显存的手段,梯度检查点和梯度累积(Gradient Accumulation)应该是同一种东西吧?

正解两者解决的问题完全不同。梯度累积是把大 batch 拆成小 batch,先攒梯度再更新,省的是“一次前向的临时激活峰值”;梯度检查点则通过“不存中间激活、反向重算”来省显存。两者可以叠加使用,但原理和收益各有侧重。

为何常见:二者都出现在“内存优化”教程里,名字里都有“梯度”,初学者容易混为一谈。

误区既然能省这么多显存,为什么不全开?感觉它是零成本的优化技巧。

正解梯度检查点不是零成本,它每次反向都要补跑一段前向,整体训练时间约增加 33%~40%。它是一笔“用时间换空间”的买卖,在显存紧张时物超所值,但在计算极度紧张或显存充裕的场景下并不划算。

为何常见:教程往往重点讲显存收益,对时间开销一笔带过,让初学者误以为它没有任何代价。

面试题

Q1. 梯度检查点主要靠哪种方式节省显存?

单选题 · easy

  • A.减少模型参数数量
  • B.不保存全部中间激活← 正确答案
  • C.降低训练计算精度
  • D.缩小训练数据集规模

答案:B。梯度检查点只保存少数检查点层的激活值,其余中间激活在反向时重算,本质是“少存照片、需要时补拍”。它不改变参数量、精度或数据规模,所以 B 正确,A、C、D 均与机制无关。

Q2. 启用梯度检查点后,训练时间大约会额外增加多少?

单选题 · mid

  • A.约增加 10%
  • B.约增加 33%← 正确答案
  • C.约增加 100%
  • D.约增加 3%

答案:B。前向计算量记为 F,反向约为 2F,基准总成本 3F。检查点方案反向时补跑一次前向,总成本变为 4F,因此时间开销约为 (4F-3F)/3F ≈ 33%。选 B。

Q3. 24 层网络、每层激活 2MB,采用均匀分段的最优检查点策略时,激活显存约为多少?

单选题 · mid

  • A.大约 20MB← 正确答案
  • B.大约 48MB
  • C.大约 24MB
  • D.大约 96MB

答案:A。最优分段数 k = √24 ≈ 5,代入公式 M_ckpt ≈ 2√N × m = 2×4.9×2 ≈ 19.6MB,约 20MB。48MB 是不启用检查点的值,C、D 均不是正确代入结果。

Q4. 以下哪些场景适合使用梯度检查点?

多选题 · mid

  • A.大模型预训练显存紧张← 正确答案
  • B.长序列 Transformer 训练← 正确答案
  • C.计算极紧张且不可让步
  • D.追求极致训练速度不考虑显存

答案:AB。大模型预训练和长序列训练都是激活显存爆炸的典型场景,检查点能以 33% 时间换大量显存,A、B 正确。C 和 D 场景下时间成本是主要矛盾,不适合用时间换空间。

Q5. 反向传播时,梯度检查点如何获得被丢弃的中间激活?

单选题 · hard

  • A.从根节点重算整个网络
  • B.从最近检查点前向重算← 正确答案
  • C.从目标层反向到检查点
  • D.从随机权重重新初始化

答案:B。需要某层激活时,框架会从距离该层最近的检查点开始,重新执行这一段的前向传播,“现场补拍”出所需的中间激活。从根节点重算整个网络太浪费,反向重算方向也错了,随机初始化更是毫无意义。

Q6. PyTorch 中实现梯度检查点的原生接口是?

单选题 · easy

  • A.优化器 Adam 接口
  • B.官方 checkpoint 接口← 正确答案
  • C.全连接 Linear 层
  • D.随机种子 seed 接口

答案:B。torch.utils.checkpoint.checkpoint 是 PyTorch 提供的梯度检查点接口,传入模块和输入即可自动完成“少存激活、反向重算”。Adam 是优化器、Linear 是网络层、seed 是随机控制,均与检查点无关。

Q7. 设计混合检查点策略时,哪些层更适合设为检查点?

多选题 · hard

  • A.激活体积大的层优先级高← 正确答案
  • B.必须所有层都设置检查点
  • C.重算成本低的层优先设置← 正确答案
  • D.算子融合无法与之配合使用

答案:AC。大激活层省显存收益最大,重算成本低的层(如轻量激活层)补拍代价小,二者都适合设为检查点,A、C 正确。混合策略正是“选择性设置”,不是所有层都设,B 错;算子融合常与检查点搭配以进一步降低重算开销,D 错。

Q8. 梯度检查点与梯度累积的关系是?

单选题 · mid

  • A.两者本质完全相同
  • B.梯度累积节省的是优化器侧显存← 正确答案
  • C.梯度累积节省的是激活显存
  • D.检查点会改变梯度值

答案:B。梯度累积把小 batch 的梯度累加后再更新,主要降低优化器更新频率与梯度缓冲区的峰值压力,不是省激活显存,B 正确。检查点与梯度累积是两种独立手段,A 错;梯度累积并不直接省激活显存,C 错;检查点不改变梯度值,D 错。

Q9. 对于忽略参数和梯度的纯激活显存,检查点方案在最优分段下的显存复杂度是?

单选题 · hard

  • A.k=1 时内存最小
  • B.k=N 时内存最小
  • C.k=√N 时内存最小← 正确答案
  • D.k=2N 时内存最小

答案:C。M_ckpt = k·m + (N/k)·m,对 k 求导令其为零可得 k = √N,此时两项相等,总和最小。k=1 时重算临时显存巨大,k=N 时检查点本身占满显存,k=2N 已超出合理范围。

Q10. 关于梯度检查点,下列说法正确的有?

多选题 · easy

  • A.数值与不检查点基本一致← 正确答案
  • B.训练时间约增三成← 正确答案
  • C.能减少模型参数量
  • D.显存由线性降为开方← 正确答案

答案:ABD。梯度检查点通过重算得到与原来一致的激活,数值基本一致,A 正确;时间代价约为 33%,B 正确;显存复杂度从 O(N) 降到 O(√N),D 正确。它不改变参数数量,C 错误。