train_global_batch_size = prompts × generations, and each rollout is exactly one row.
This PR
Under context compaction (CC), the batch size still counts rollouts. The number of rows per step varies, and padding keeps it even across GPUs.
Status
Explains the PR's code — no change proposed. The example numbers are worked by hand from the code's formulas, not taken from a run.
Nine pages on this PR, one question each. This one: what "batch size" means when one rollout can be several rows.
The config check is unchanged: prompts × generations must equal train_global_batch_size (config.py L1355-1363).
Under CC, that number counts rollouts, not rows. A step closes when it holds exactly that many rollouts, however many rows they produced, and raises otherwise (single_controller.py L3206-3213).
Two things make a variable row count work. Each group is padded to an even multiple, so every GPU runs the same number of micro batches. And gradients are added up across all micro batches and divided once, by the total token count, at the end of the step.
Why the row count does not change the math
Loss: each micro batch adds its summed token loss to the gradients. finish_train_step sums the valid tokens over every GPU and scales the gradients by 1/N (L2018-2036). Each generated token is trained once, whether its rollout sits in 1 row or 3. Padding rows have no valid tokens, so they add nothing.
Advantage: computed once per rollout and copied to all its rows (page 5). Padding rows get 0.
Optimizer: one step per training step, as before. More rows means more micro batches, not more optimizer steps.
What it costs
Cost
Why
Megatron only, fixed batch: no sequence packing, no dynamic batching, no interleaved pipeline
Padding to a fixed multiple only works when every micro batch has a fixed number of rows. The config check rejects the other modes (config.py L891-900).
Up to Q − 1 padding rows per group
Here 3 of 16 rows (19%) are padding. More GPUs or a larger micro batch raise Q, and with it the waste.
Step time grows with compaction
6 rollouts cost 16 forward/backward rows here, against 6 in ordinary GRPO. Memory per micro batch stays the same.
Row-count metrics change meaning
global_valid_seqs counts rows, so under CC it can exceed the number of rollouts. The proposed L1 test uses this to check that rows were split.
So what. You get no more than train_global_batch_size rollouts per step, and no fewer. Extra compaction rows become extra micro batches inside the same optimizer step, normalized by tokens. This is also why a dropped group cannot simply be skipped (page 6): the step insists on the full rollout count.