通过profile可以看到iter2开始时,随着前向计算进行,显存值仍在上升,iter2存储前向激活时需要额外的显存吗?iter1占用的显存不会被释放了吗?


您好,已收到您的反馈,使用npu-smi info查看到的显存占用除了包含allocated以外,还包含了os固定占用、CANN占用(通信、GE)和跨流开销等;另外,iter2优化器开始占用显存,显存有上升是正常现象,建议您进一步观察iter3之后的显存值是否平稳


您好,已收到您的反馈,使用npu-smi info查看到的显存占用除了包含allocated以外,还包含了os固定占用、CANN占用(通信、GE)和跨流开销等;另外,iter2优化器开始占用显存,显存有上升是正常现象,建议您进一步观察iter3之后的显存值是否平稳
感谢回复
iter3之后的显存值是平稳的,但megatron本来的iter2也是会额外占用显存去存前向激活吗,有点反直觉,这样一来前向激活不是占了两份空间吗


您好,已收到您的反馈,使用npu-smi info查看到的显存占用除了包含allocated以外,还包含了os固定占用、CANN占用(通信、GE)和跨流开销等;另外,iter2优化器开始占用显存,显存有上升是正常现象,建议您进一步观察iter3之后的显存值是否平稳
您提到iter2刚开始显存上升是优化器的占用,这部分难道不是前向激活的占用吗。profile里iter2每一层前向结束时间与显存上升时间几乎相同。


您好!关于您的疑问,回复如下:
iter3之后的显存值是平稳的,但megatron本来的iter2也是会额外占用显存去存前向激活吗,有点反直觉,这样一来前向激活不是占了两份空间吗
您提到iter2刚开始显存上升是优化器的占用,这部分难道不是前向激活的占用吗。profile里iter2每一层前向结束时间与显存上升时间几乎相同。
llm与megatron是相同的逻辑:第一步激活值在第一步反向传播中释放,您观察到的显存随前向计算上升,是当前步新的前向激活在累积。激活值在对应的计算完成以后会释放,不会占用两份空间。从iter2开始的显存增加,主要是由于优化器的延时分配:优化器在iter1末尾被初始化并分配空间,从iter2开始常驻显存,iter2的前向激活将在这个基础上逐渐累积。优化器状态分配后即常驻,到iter3时,显存结构已定型,后续显存平稳不再飙升,说明您的训练状态是健康的。


您好!关于您的疑问,回复如下:
iter3之后的显存值是平稳的,但megatron本来的iter2也是会额外占用显存去存前向激活吗,有点反直觉,这样一来前向激活不是占了两份空间吗
您提到iter2刚开始显存上升是优化器的占用,这部分难道不是前向激活的占用吗。profile里iter2每一层前向结束时间与显存上升时间几乎相同。
llm与megatron是相同的逻辑:第一步激活值在第一步反向传播中释放,您观察到的显存随前向计算上升,是当前步新的前向激活在累积。激活值在对应的计算完成以后会释放,不会占用两份空间。从iter2开始的显存增加,主要是由于优化器的延时分配:优化器在iter1末尾被初始化并分配空间,从iter2开始常驻显存,iter2的前向激活将在这个基础上逐渐累积。优化器状态分配后即常驻,到iter3时,显存结构已定型,后续显存平稳不再飙升,说明您的训练状态是健康的。
感谢回复,可能是我理解不当,还是有些问题。
您提到“激活值在对应的计算完成以后会释放,不会占用两份空间”,那为什么对iter2的前向激活存储时显存占用会上升呢,iter2不能使用原本iter1的激活占用的显存吗?
如果iter1的激活对应的显存已经被完全释放,有一个显存占用下降的过程,所以iter2存激活要重新分配显存,那iter2的激活被释放的时候显存是否也应该出现大幅下降呢?但iter2之后的显存占用是完全平稳的。


你好,这个观察和前面的解释其实不矛盾,关于你的问题:
- "iter2 前向时显存为什么还会上升?iter2 不能复用 iter1 激活的空间吗?"
可以复用,但新增上升的那部分不是激活本身,而是优化器状态 + 临时 workspace。时间线大致是:
iter1 forward:分配激活 A1(峰值出现在 forward 末尾);
iter1 backward:A1 随反向逐层释放,同时分配梯度 G;
iter1 optimizer.step():首次访问 master weights / m / v 时才真正分配优化器状态 O(distributed optimizer + lazy init 的典型行为),这一步显存会跳一档;
iter2 forward:在 "权重 + 梯度 + 优化器状态 O" 的基础上,重新累积新的激活 A2。
你看到的 iter2 前向期间的上升曲线,底座抬高的部分是 O,叠加在上面的爬升才是 A2 的累积。A2 占用的空间是可以复用 A1 释放出来的 block 的,并不会是两份。
- "如果 iter1 激活释放过,为什么没看到一次显存下降?"
这一点取决于你用什么工具看显存:
- torch_npu使用的是 caching allocator:tensor 释放时只是把 block 还回 allocator 的 pool,device 侧并不会立刻归还,留着给后面复用;
- npu-smi info 看到的是 reserved 高点 + allocator 外占用,本质上只涨不退,到达稳态后就平稳;你不会看到 iter1 backward 期间激活释放对应的"下降"。
真正能看到"上升 → 下降 → 上升"完整曲线的,是 torch_npu.npu.memory_allocated()(对应实际占用,不含缓存);如果用 memory_reserved() 或 npu-smi,看到的就是单调上升到稳态。所以你 profile 看到的"iter2 上升、之后平稳"是预期行为:上升 = 优化器状态首次分配 + 新激活在已 reserve 的池里继续要新 block 把池抬到稳态高点;之后所有 iter 的激活分配/释放都在这个池子里循环,device 视角自然就稳定了。
如果想验证这个解释,可以在每个 iter 前后打印 torch_npu.npu.memory_allocated() 和 torch_npu.npu.memory_reserved() 对比看:allocated 会在 forward 末峰值、backward 末回落,呈周期性;reserved 则单调上升到稳态后不变。这两条曲线放一起,前面的所有现象就都能对上了。


你好,这个观察和前面的解释其实不矛盾,关于你的问题:
- "iter2 前向时显存为什么还会上升?iter2 不能复用 iter1 激活的空间吗?"
可以复用,但新增上升的那部分不是激活本身,而是优化器状态 + 临时 workspace。时间线大致是:
iter1 forward:分配激活 A1(峰值出现在 forward 末尾);
iter1 backward:A1 随反向逐层释放,同时分配梯度 G;
iter1 optimizer.step():首次访问 master weights / m / v 时才真正分配优化器状态 O(distributed optimizer + lazy init 的典型行为),这一步显存会跳一档;
iter2 forward:在 "权重 + 梯度 + 优化器状态 O" 的基础上,重新累积新的激活 A2。你看到的 iter2 前向期间的上升曲线,底座抬高的部分是 O,叠加在上面的爬升才是 A2 的累积。A2 占用的空间是可以复用 A1 释放出来的 block 的,并不会是两份。
- "如果 iter1 激活释放过,为什么没看到一次显存下降?"
这一点取决于你用什么工具看显存:
- torch_npu使用的是 caching allocator:tensor 释放时只是把 block 还回 allocator 的 pool,device 侧并不会立刻归还,留着给后面复用;
- npu-smi info 看到的是 reserved 高点 + allocator 外占用,本质上只涨不退,到达稳态后就平稳;你不会看到 iter1 backward 期间激活释放对应的"下降"。
真正能看到"上升 → 下降 → 上升"完整曲线的,是 torch_npu.npu.memory_allocated()(对应实际占用,不含缓存);如果用 memory_reserved() 或 npu-smi,看到的就是单调上升到稳态。所以你 profile 看到的"iter2 上升、之后平稳"是预期行为:上升 = 优化器状态首次分配 + 新激活在已 reserve 的池里继续要新 block 把池抬到稳态高点;之后所有 iter 的激活分配/释放都在这个池子里循环,device 视角自然就稳定了。
如果想验证这个解释,可以在每个 iter 前后打印 torch_npu.npu.memory_allocated() 和 torch_npu.npu.memory_reserved() 对比看:allocated 会在 forward 末峰值、backward 末回落,呈周期性;reserved 则单调上升到稳态后不变。这两条曲线放一起,前面的所有现象就都能对上了。
完全理解了,非常感谢


在提交新问题之前,请确保您已经在社区中搜索过相关问题,并使用了社区中提供的资源/工具后,仍未找到满意的解决方式。
环境信息
使用场景及问题
训练时输出的显存信息为:
但训练过程中使用npu-smi info查看显存占用,发现rank 0实际使用了53000MB显存,多出约三分之二:
其他rank都是类似的情况,这部分多出的显存分配在了哪一部分呢?为什么训练时的输出会偏低这么多呢?
欢迎加入社区,感谢您对社区的贡献 🎉!