NVIDIA-NeMo / NVIDIA-NeMo/Automodel

[NeMo-RL-DSV4] Review peak memory from FP32 cast before MoE grouped-mm scatter_add

Open
#2,086 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

dsv4
Dominant language
Python
Stars
963
Forks
318
Avg merge
3d 20h
Merged PRs (30d)
143

Description

During DeepSeek V4 GRPO bring-up in NeMo-RL, we observed an OOM in the Automodel policy path when using backend.experts: torch_mm. We have not reproduced this issue in a standalone Automodel training run, so this report is mainly to share the integration-time observation and ask for Automodel maintainers' review.

Issue

The suspected peak-memory source is in the grouped MoE forward path. After the down projection, Automodel accumulates expert outputs into an FP32 buffer via:

scatter_ids = sorted_token_ids.unsqueeze(1).expand_as(output2)
y.scatter_add_(0, scatter_ids, output2.float())

For large MoE / GRPO shapes, output2.float() appears to materialize a full FP32 temporary tensor before the scatter, which can create a large transient memory spike.

Local workaround in fork

In my fork, I added a local mitigation in this commit:

https://github.com/zpqiu/Automodel/commit/e2564e22c107369db814d57de71dfa42c5b5d047

The change introduces an optional env var:

NEMO_AUTOMODEL_MOE_SCATTER_CHUNK_ROWS

When unset or 0, behavior stays unchanged. When set, the FP32 cast and scatter are done in row chunks:

for start in range(0, output.size(0), chunk_rows):
    end = min(start + chunk_rows, output.size(0))
    y.scatter_add_(0, scatter_ids[start:end], output[start:end].float())

This is intended to preserve FP32 accumulation semantics while reducing the peak temporary buffer size from the full output2.float() tensor to one chunk at a time. In the NeMo-RL DS V4 GRPO experiment path, I used NEMO_AUTOMODEL_MOE_SCATTER_CHUNK_ROWS=4096 as a temporary workaround.

Request

Could you review whether this memory pattern is expected in Automodel's grouped MoE path, and whether a chunked scatter approach, or another upstream-friendly implementation, makes sense?

This workaround has not been rigorously validated for standalone Automodel correctness or performance.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing the grouped MoE forward path containing the FP32 cast and scatter_add_, then compare it with the local workaround in commit e2564e22c107369db814d57de71dfa42c5b5d047. Validate the chunked approach in standalone Automodel runs for correctness, performance, and peak memory, including the NEMO_AUTOMODEL_MOE_SCATTER_CHUNK_ROWS=4096 setting.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, pytorch
Domain
machine-learning
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.