perf(rlhf): vectorize padding-free log-probability restore - #10021
Open
Ruihan11 wants to merge 1 commit into
Open
perf(rlhf): vectorize padding-free log-probability restore#10021Ruihan11 wants to merge 1 commit into
Ruihan11 wants to merge 1 commit into
Conversation
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
Summary
Optimize padding-free RLHF log-probability restoration for larger batches by replacing per-sequence NPU synchronization and slice assignments with a batched padding path.
Motivation
pad_logps_back_to_batchis shared by the GRPO, DPO, KTO, HF, Megatron, and Ray RLHF paths. The previous implementation performed a Python loop over every batch element. For each sequence it:.item();This overhead grows with the number of packed sequences and is visible in padding-free RLHF batches containing many short completions.
Changes
batch_size <= 2.pad_sequence/temporary construction overhead for tiny batches.tolist()transfer instead of one.item()transfer per boundary;pad_sequenceto preserve left-padding semantics on older PyTorch versions;F.padto reachlogits_to_keepwhen necessary;valid_maskwith vectorized device-side indexing.seq_lengthsandposition_idsfallback paths;dtypeandpad_valuehandling;tests/test_align/test_rlhf_loss.py.Correctness validation
The focused test compares the optimized implementation with an independent loop reference and covers:
seq_lengthsandposition_idsinput paths;Results:
A separate Ascend NPU correctness harness also compared the real production caller against the original implementation for FP32/BF16 normal, empty, and truncated inputs. Output tensors, masks, loss, gradients, and finite-state checks all passed.
Experiment results
Environment
Baseline and optimized measurements used the same inputs, sequence lengths, dtype, and benchmark settings.
Helper microbenchmark
The helper benchmark covered FP32/BF16, uniform and skewed sequence distributions, 4096 and 16384 total tokens, and representative batch sizes up to 256. The following table shows synchronized p50/p95 results for the 4096-token uniform distribution:
FP32
BF16
Skewed distributions and 16384-token inputs showed the same trend. For example, at 4096 tokens and batch size 256:
Production-caller synthetic NPU E2E
The benchmark invokes the actual production method:
It covers both the logps-only path (
compute_entropy=False) and the logps-plus-entropy path (compute_entropy=True). Results below are FP32, 4096 total tokens, synchronized p50 latency:Logps only
Logps plus entropy
Peak allocation increases slightly on the optimized path because it uses temporary batched padding buffers. For the 4096-token uniform FP32 helper case at batch 256, peak allocation was approximately 54 KiB baseline versus 163 KiB optimized. Skewed/longer inputs reached approximately 0.1--1.7 MiB additional peak allocation depending on the sequence distribution, with no persistent growth observed. Reserved memory remained allocator-dependent and was not used as a correctness criterion.
Validation commands
python -m pytest -q tests/test_align/test_rlhf_loss.py python -m compileall -q swift flake8 isort --check-only . yapf --diff --recursive swift tests git diff --checkAll commands passed.
Limitations and scope