{{ message }}
Repository navigation
[CUDA] Make native CTC loss backward deterministic - #201617
Open
shuo-ouyang wants to merge 1 commit into
Open
shuo-ouyang wants to merge 1 commit into
shuo-ouyang wants to merge 1 commit into
Conversation
Signed-off-by: shuo-ouyang <shuo-ouyang@foxmail.com>
This branch was successfully deployed
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.

Linked issue or supporting maintainer
Fixes #178052
BC-breaking?
No. With
torch.use_deterministic_algorithms(True), CUDActc_lossbackward used to raise and now succeeds. Gradients on large inputs may differ from the non-deterministic path in the last bits (due to reduction order).Summary
Currently, only the large-input CUDA CTC backward used
atomicAdd(the nonblank kernel); the small-input kernel was already deterministic, butctc_loss_backward_gpuraised for every size.This PR removes the blanket alert and, in deterministic mode, replaces the nonblank atomic update with label grouping (stable sort + binary-searched offsets) and a fixed-order warp reduction.
Benchmarks
Backward latency in milliseconds on an NVIDIA RTX 3080 (10 GB), CUDA 12.8, cuDNN 9.8.0 (cuDNN disabled for these runs, so the native kernels are measured). Each number is the median of 3 rounds of 10 calls after 5 warmup calls, timed with CUDA events [state whether each round reports the mean of its 10 calls]. Shapes are (T, B, C, L): input length, batch size, vocabulary size, and target length.
* Uses the small-input kernel in both modes, which is unchanged, so the difference reflects measurement noise.
On large inputs the deterministic path takes 0.92x-1.32x the time of the non-deterministic path.
For reference, the native deterministic path versus cuDNN (float32 only, forward + backward combined, since cuDNN computes gradients in the forward pass):
Native deterministic vs cuDNN
cuDNN is only used when blank == 0, targets are contiguous int32 on CPU, log_probs is float32, all input lengths equal T, and target lengths are below 256. The native path remains the fallback for all other inputs.
Agent details (if applicable)
Worked with GPT-6.1-Sol and Claude Code Sonnet 5.5