perf(megatron): remove per-document device syncs in channel loss aggregation - #9795
Open
gakkiri wants to merge 1 commit into
Open
perf(megatron): remove per-document device syncs in channel loss aggregation#9795gakkiri wants to merge 1 commit into
gakkiri wants to merge 1 commit into
Conversation
The per-document loop in _compute_channel_loss triggered three device synchronizations per document (two scalar reads from cu_seqlens and the masked select), so its cost grew linearly with the number of packed documents and became significant for datasets with many short samples. Aggregate all documents with a single index_add_ over token-to-channel ids instead, which makes the cost independent of the document count.
Contributor
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR type
PR information
When
--enable_channel_lossis used together withpadding_free,MegatronTrainer._compute_channel_lossaggregates the per-channel loss with a Python loop over every document in the pack. Each iteration forces three GPU -> CPU synchronizations:slice(cu_seqlens[i], cu_seqlens[i + 1])converts two CUDA scalars via__index__, i.e. two implicititem()calls;losses[0, slice_][loss_mask[0, slice_]]needsnonzeroto resolve the output length, andc_loss.shape[0]depends on that same result.So the cost of this function grows linearly with the number of documents in a pack. On the machine used for the benchmark below it is ~113 us per document, and since the function runs inside
loss_funcfor every micro-batch on the last PP stage, the overhead is paidgrad_accumtimes per step. Datasets made of many short samples are hit hardest, which is exactly the case where channel loss is most useful. Beyond the raw microseconds, the syncs also destroy CPU run-ahead, so the last PP stage cannot enqueue the next micro-batch in time and the pipeline bubble grows.This PR replaces the loop with a single vectorized reduction:
repeat_interleaveover the segment lengths, withoutput_sizepassed explicitly so this call does not synchronize either;index_add_into a(num_channels, 2)buffer.The only remaining synchronization is
int(cu_seqlens[-1]), once per call instead of three per document, so the cost is now essentially independent of the document count.Experiment results
Microbenchmark of the aggregation itself, isolated from the rest of the training step. Total pack length is fixed at 131072 tokens and split into a varying number of documents; timings are per call.
The 16384-document case was re-measured as a median over 10 rounds to rule out noise, and stays around 1340x: 1831.777 ms -> 1.366 ms at 25% non-masked tokens, 1840.980 ms -> 1.367 ms at 100%.
The old timings scale strictly linearly with the document count (~113 us per document across all rows), which matches the three synchronizations per iteration. The new timings are nearly flat. The lower rows are deliberately extreme to show the scaling; the realistic operating range for short-sample datasets is the 128 - 1024 document region, where the aggregation drops from 15 - 115 ms to well under 0.4 ms per micro-batch.
Correctness was verified against the original implementation on the same inputs:
Environment: NVIDIA H20, torch 2.8.0+cu128, Megatron-LM 0.18.0