先定义负载,再选择计量口径
“一个 7B 模型”既没有说明权重的表示方式,也没有说明要执行的工作。请记录其修订版本、框架、扩展版本、实际加载的格式以及操作类型:训练、微调还是生成。对于文本,记录输入和输出长度;对于视觉,记录分辨率和图像数量。多模态模型需要同时保留这两个维度。
请准备一个常规输入、一个较长但可预期的输入,以及一个接近您功能上限的输入。在对比期间一直保留它们。检查分词、padding、分组或缩放之后的形状:写在配置里的值并不能证明实际处理的形状。
还要确定哪些内容会同时留在内存中:一个序列、一个微批次、多个请求,还是训练后启动的评估。您的问题就变得可验证了:这一完整负载能否装进所用的每个设备,包括在其要求最高的阶段?
- 试验标识:模型或代码、修订版本、输入集以及相关时的随机种子。
- 维度:batch、上下文、生成的 token 数、分辨率或并发请求数。
- 环境:选定的 GPU、驱动、Python、PyTorch、CUDA 或 HIP/ROCm 后端以及分配器设置。
- 范围:加载、计算、传输、评估、导出;首次运行或预热后的运行。
计算权重时不要混用 GB 和 GiB
1 GB 等于 1 000 000 000 字节;1 GiB 等于 1 073 741 824 字节。这里使用的 PyTorch 计数器返回的是字节。请将这一原始值保留在结果文件中,然后只做一次换算来比较各行。显卡的商业标称并不能替代设备实际报告的容量。
对于一个由七十亿个参数组成、每个参数以两字节存储的稠密模型,权重占 14 000 000 000 字节:即 14 GB,约合 13.04 GiB。该计算不包含激活值、梯度、KV 缓存或优化器状态。再加上 4 GiB 的余量,约 17.04 GiB 可作为准备阶段的假设;这并不能证明某个负载一定能装进这个范围。
四比特的理论除法假设存储是紧凑且均匀的。真实的量化加载可能会增加缩放因子和其他信息,并将某些模块保留在其他精度下。因此,权重的存储格式和计算格式必须在你的记录中分别列出。
| 存储假设 | 计算出的字节数 | 约合 GiB |
|---|---|---|
| 32 位均匀 | 28 000 000 000 | 26,08 |
| 16 位均匀 | 14 000 000 000 | 13,04 |
| 4 位紧凑,不含元数据 | 3 500 000 000 | 3,26 |
技术来源: NIST — 二进制前缀与 GB/GiB 对比 · Hugging Face — 使用 bitsandbytes 的量化格式与模块
训练时,测量完整的一步
权重与其他对象共存:梯度、优化器状态、反向传播所需的激活值以及临时张量。它们的大小取决于训练循环、精度和负载的规模。一个通用的每参数字节数常量会掩盖微批大小和输入所带来的影响。
请对前向传播、损失计算、反向传播和更新进行监测。要观察优化器实际创建的状态,不要只停留在模型加载阶段。同时保留对第一个完整步骤的测量:一次成功的预热可能已经执行了某种初始化,而你需要在启动时为其提供足够的内存。
再加上你的项目所需的评估和导出环节。如果失败发生在评估阶段,只减小训练批量并不能解决这一阶段的问题。一种只训练少量参数的适配方法仍可能保留一个基础模型和大量激活值。
技术来源: Hugging Face — 训练期间的内存类别
推理时,关注上下文和并发
在使用注意力的自回归生成中,KV 缓存保存与 token 相关的状态。对于均匀的稠密缓存,其大小取决于层数、KV 头数、头维度、保留的 token 数以及同时存在的序列数。请使用模型的 KV 头数,而不是自动使用其查询头数。
算术示例:32 层、8 个 KV 头、维度为 128、8 192 个 token、每个值两字节,单条序列得到 1 073 741 824 字节,即 K 和 V 合计 1 GiB。四条相同的序列仅这一项就是 4 GiB。该计算既不能衡量吞吐量,也不能衡量 GPU 的完整占用情况。
请根据实际使用的缓存来调整公式。滑动窗口不一定会保留全部历史;静态缓存可能会预分配其最大容量。量化缓存和卸载缓存也会改变这一问题。请分别测量输入的初始处理和生成过程,不要自动将两者的全部差异都归因于缓存。
Allocated 与 reserved:两种读数,不能相加
memory_allocated 描述 PyTorch 在设备上跟踪的张量所占用的字节数。memory_reserved 描述其带缓存分配器所管理的内存,其中已包括用于这些张量的部分。将两者相加会把一部分内存重复计算。请将它们保留在两个独立的列中。
它们的最大值变体分别记录自跟踪开始或其上次重置以来的峰值。这些是统计周期内的绝对峰值,包含周期开始时已存在的分配。其结果并不自动代表仅由该阶段创建的对象。
系统层面的读取可能范围更广。由 CUDA 库直接完成的分配,例如某些 NCCL 通信,并不都能在 PyTorch 分配器中看到。因此,与系统工具的差异本身并不能证明存在泄漏。
| 计数器 | 它所回答的问题 | 需避免的错误 |
|---|---|---|
| memory_allocated | 在此读取点,张量占用了多少? | 将其视为整块显卡的占用。 |
| memory_reserved | 在此读取点,分配器管理了多少? | 将其加到 allocated 上。 |
| max_memory_allocated | 该周期内跟踪到的张量峰值是多少? | 将其与阶段结束时的值混为一谈。 |
| max_memory_reserved | 分配器报告的预留峰值是多少? | 假设它与另一个峰值出现在同一时刻。 |
技术来源: PyTorch — memory_allocated · PyTorch — memory_reserved · PyTorch — max_memory_allocated · PyTorch — 其分配器之外的分配
为什么两个峰值之差不能衡量缓存
仅考虑表中两个虚构的时刻。allocated 峰值为 8 GiB,reserved 峰值为 12 GiB。二者之差 4 GiB,并不是这两个时刻中任一时刻所观察到的差值:该差值分别为 2 GiB 和 6 GiB。两个最大值未必描述同一个状态。
若要在某一时刻研究二者的差距,请在同一检查点、同步之后且两次读取之间不进行新的主动操作的情况下,读取 allocated 和 reserved。你得到的是该时刻的计数器差值,而不是模型 KV 缓存的度量,也不保证这一整段差值都能满足下一次分配。
还要在报告中保留分配器的后端。PyTorch 2.14 文档指出,在使用 cudaMallocAsync 时,max_memory_reserved 可能合并两个池的最高水平,给出同时峰值的上界。这进一步说明有必要保留计数器的名称和范围。
| 示例时刻 | Allocated | Reserved | 该时刻的 Reserved − allocated |
|---|---|---|---|
| A | 8 GiB | 10 GiB | 2 GiB |
| B | 6 GiB | 12 GiB | 6 GiB |
在读取峰值之前先界定每个阶段
GPU 操作可能在完成之前就被排队。要按阶段测量,请在将峰值重置为零之前先结束之前的工作,然后在该阶段结束后再进行读取。torch.cuda.synchronize 会等待所选设备所有流上的内核;这一选择为该协议定义了一条明确的边界。
reset_peak_memory_stats 会从当前状态重新开始跟踪峰值;它不会释放程序中的张量。请先读取起始水平。结束时,保留两个绝对峰值和两个当前水平。不要将起始水平的相减当作所有临时张量的精确体积:先前存在的对象也可能在该阶段期间被释放。
这种插桩可能改变通常的阶段重叠。用它来定位问题,然后用其真实的调度顺序验证完整循环。在多卡情况下,请为每块设备重复读取;对 cuda:0 的测量不能描述其他 GPU。
- 1. 为阶段命名,并记录其确切的输入。
- 2. 同步设备,然后读取起始的 allocated 和 reserved。
- 3. 在同一设备上调用 reset_peak_memory_stats。
- 4. 执行所定义的阶段,并保留后续所需的输出。
- 5. 同步,读取峰值和结束水平,然后记录成功或错误。
- 6. 保留原始结果、维度和配置;不要用零填补任何缺失的测量值。
技术来源: PyTorch — 设备同步 · PyTorch — 重置峰值统计
区分首次运行与预热后的运行
首次试运行与已经准备好的循环回答的并不是同一个问题。保留加载和首次运行的记录,然后记录重复运行前的预热迭代次数。不要因为后续运行看起来更轻量,就删除初始化失败的记录。
IteraGPU 脚本区分 model_load、inputs、cold_forward、warmup 和 warm_forward。cold_forward 是设备初始化后小模型的第一次运行。它不测量服务器、驱动或服务的整个启动过程。warm_forward 的重复运行仍在同一进程内,并受益于其已有状态。
对于你的模型,当你更改某个可能遗留先前对象或预留的条件时,请在新进程中开始新的运行序列。记录试验顺序和预热策略。将同一个循环重新运行五次与启动五个进程并不构成相同的协议。
使用 notebook 和 IteraGPU Lab v1 脚本
请先阅读 README,然后下载独立的 notebook 或 Python 脚本。estimate 计算使用标准库。measure 需要安装 PyTorch 并配备兼容的 GPU 后端和可访问的设备;它不会下载模型或软件包。notebook 需要能够读取 ipynb 文件的环境。
测量练习使用一个原始的小型稠密网络和合成输入。batch、context 和 width 选项描述其张量;此处的 context 不是带 KV 缓存的真正 LLM 的长度。此材料用于考察测量方法并改变某一个维度。它并不证明某块显卡对您研究模型的承载能力。
请在包含脚本的文件夹中执行以下命令。先查看 environment 报告。如果缺少 PyTorch 或 GPU,measure 必须以代码 2 显式停止;任何 CPU 结果都不得被解读为 GPU 测量。成功测量的输出 JSON 在您的环境中生成。每轮测试请选择新的文件名:脚本拒绝覆盖已有结果。
第一条命令重新计算权重和假设的 4 Gio 预留。对于后续命令,请使用您获准使用的设备,并一开始就保持较小的维度。记录实际使用的 PyTorch 版本:本页的技术参考主要描述 2.14 版本,但并不要求您安装该版本。
该脚本的运行已在一个小案例上验证:目录外的本地 RTX 5070、驱动 610.62、Python 3.14.6 和 PyTorch 2.11.0+cu128。该试验使用 batch 1、上下文 16、宽度 64、float32、一次预热和两次重复。它验证了该执行路径,但并不评定某个 LLM、训练或可供租用的 GPU。notebook 交付时不含输出,对比表不含结果;无 PyTorch 时的防护也已在一个独立环境中验证。
python mesure_memoire.py estimate --parameters 7000000000 --bits 16 --reserve-gib 4
python mesure_memoire.py environment --device cuda:0
python mesure_memoire.py measure --device cuda:0 --batch 2 --context 128 --width 1024 --dtype float32 --warmup 3 --repeats 5 --output mesures.json- 计算与测量 notebook
可在您环境中打开、审阅并运行的独立 notebook。
- mesure_memoire.py 脚本
无需外部依赖的计算、环境检查和显式 GPU 测量。
- 文件夹使用说明
前提条件、命令、各阶段范围及解读限制。
- IteraGPU Lab v1 归档
汇集各版本化资源及其使用说明和许可证。
- 资源许可证
所提供文件的使用条件。
在更换显卡前解读故障
不完整的试验仍是有用的观察。请保留阶段、请求的维度、错误消息和最后可用的数值。饱和前的部分峰值并不构成完整运行的内存需求。只减小一个维度来构建一个能成功的案例,然后寻找成功与失败之间的边界。
empty_cache 会释放分配器缓存中未使用的块,但不会释放仍然存活的张量。它不是应对负载过大的通用解决方案。在每次迭代之间调用它会改变实验条件:应当记录这一选择,而不是把这些试验与保留缓存的试验混在一起。
如果简单的计数器无法解释当前情况,内存跟踪有助于识别随时间变化的分配情况。其范围仅限于 PyTorch 可见的分配。因此,allocated 峰值较低并不能排除存在外部分配或显卡上的其他用户。
| 观察 | 有用的检查 | 下一步试验 |
|---|---|---|
| 加载过程中失败 | 已加载的格式、权重放置方式以及已占用的内存。 | 在全新进程中单独重现加载。 |
| 加载成功,反向传播失败 | 微批次、输入、保留的激活值和循环状态。 | 缩减一个维度后重新执行完整步骤。 |
| 单独评估失败 | 评估批次、保留的输出和计算上下文。 | 用其自身的限度来衡量评估。 |
| Allocated 在每次重复中都会增加 | 引用被保留在列表、应用缓存或图中。 | 在归咎于分配器之前,先检查它们的生命周期。 |
| 计算后 Reserved 仍居高不下 | 仍存活的张量与缓存策略。 | 比较当前值,不要累加计数器。 |
| 系统工具显示的值更高 | 工具的作用范围、GPU 上下文、其他进程和库。 | 隔离负载,并对比同一时刻采集的读数。 |
基于可比负载构建余量
不要给出一个被当作通用标准的余量百分比。余量必须覆盖已识别的变化:更长的输入、允许的批次、评估、导出、库版本或其他占用显卡的情况。测试预期的边界情况,然后记录哪些仍在范围之外。仅在一个小输入上成功运行,并不代表通过了最大负载验证。
每次只改变一个变量:在上下文不变的情况下先批次 1 再批次 2,或在批次不变的情况下先上下文 2 048 再 4 096。保持相同的内容和相同的预处理规则。截断如果去掉了必要信息,就会使任务变得不同,即使它降低了峰值。
如果权重占主导,在控制质量的前提下研究另一种格式。如果激活值占主导,微批次或激活检查点可能是有希望的途径。后者以重新计算换取内存:也要测量耗时并验证结果。如果 KV 缓存占主导,检查上下文、并发和缓存策略。对比档案以统一的质量规则补充这一流程。
技术来源: PyTorch — 激活检查点与重新计算
从痕迹到配置决策
预期输出是一份简短记录:权重估算、测试的最大负载、成功或失败的阶段、四个带单位的计数器、环境以及最终选择。将原始结果附在这份记录后面。把您计算出的内容、观察到的内容和仍属假设的内容分开列出。
然后将需求与每张卡的能力进行比较,同时保留软件约束。多块 GPU 需要拆分工作和数据;它们的存在并不会自动为应用创建一个统一的内存池。某张卡上的失败可能在其他卡仍有空闲内存时依然存在。
PyTorch 协议使用 torch.cuda 接口;PyTorch 的 HIP/ROCm 构建会沿用这个名称。在比较两个硬件系列之前,先确认实际安装的是哪个后端。使用同一个 Python 函数并不能证明内核、精度或结果是等同的。
估算器可让您回到初始假设;GPU 记录可让您比较各项能力。然后回到同一个工作用例来验证选择。下载中的小网络仍然只是一个插桩练习:只有在有文档记录的环境中运行您自己的负载,才能验证您自己的余量。
技术来源: NVIDIA — 将工作分配到多块 GPU · PyTorch — HIP/ROCm 构建中的 torch.cuda 接口