feat(engine): MTP training loss and speculative decoding for bailing_v3 - #550
Open
Dayuxiaoshui wants to merge 4 commits into
Open
feat(engine): MTP training loss and speculative decoding for bailing_v3#550Dayuxiaoshui wants to merge 4 commits into
Dayuxiaoshui wants to merge 4 commits into
Conversation
Phase 0 - MTP training loss: - Load and save bailing_v3 MTP layers (generic ExtraLayerListSpec in the checkpoint spec) and run them as BailingMTPLayer when TrainMeta.mtp_enabled. - Auxiliary t+2 loss, opt-in only via runtime.mtp_loss_scale; the checkpoint's mtp_loss_scaling_factor is never inherited (it would corrupt DPO rows). - Validated on Ling-3.0-tiny-base: pretrained head scores t+2 at NLL 0.78 vs trunk t+1 0.77 (uniform 12.0). Phase 2 - rollout speculative decoding (runtime.speculative_draft_tokens=k): - InferMeta.tokens_per_seq lets one decode forward verify k+1 tokens per row; flash backend regroups the flat token axis for flash_attn_with_kvcache. - KDA layers reuse the recurrent kernel's target-verify mode (intermediate_states_buffer + disable_state_update); recurrent and conv caches are stacked across layers so commit_speculative_state is 4 kernels. The verify-state buffer is allocated once and shared by all CUDA graphs. - The MTP layer drafts EAGLE-style with its own paged KV cache and fused MoE weights; SpeculativeDraftModel is the model-side protocol. - engine/runtime/speculative.py: distribution-preserving chain rejection sampling mirroring the single-token sampler's processing; Gumbel-max draws. - Decode loop: multi-token writes with stop/length masking inside the step, prefill runs the MTP layer to fill its KV, per-bucket verify/draft graphs, spec_verify_rows metric and an accept-length log line. - Decode-phase speedup on Ling-3.0-tiny-base (1x H200, T=1, k=2): 1.5-1.6x for 1-32 concurrent rows, 1.4x at 64; accept length 2.3-2.4. Load test with EOS, top-p and continuous batching churn passes. Also fixes _cancel_stop_token crashing on ignore_eos (eos_token_id=()) and stops the cancel fallback marker from becoming a truncation stop token. Tests: CPU tests for the speculative math, the decode loop with a fake model, MTP layers, cancel-stop handling; GPU equivalence of multi-token verify vs sequential decode and of draft logits vs the training path. RFC: docs/issues/mtp-speculative-decoding.md
…est survives a polluted global context
Collaborator
|
@Dayuxiaoshui Here are some points need to be resolved.
|
- Build MTP layers only when a feature needs them: EngineConfig derives ModelConfig.mtp_layers_enabled from runtime.mtp_loss_scale and runtime.speculative_draft_tokens (shared by train and rollout partitions so policy-sync plans stay aligned); reference/critic/reward roles never build them and load the actor's base weights while ignoring its MTP tensors. The model logs once when a checkpoint's MTP layers are skipped. - Release rollout HBM on role switching: the stacked KDA caches and the shared verify-state buffers are dropped by clear_kv_caches, the verify buffers are dropped by offload_kv_caches and reallocated lazily on the next verify forward. - Speculative mode captures only verify and draft CUDA graphs; the unused single-token decode graphs are no longer captured per bucket. - Expose mtp_loss_scale (TrainerConfig) and speculative_draft_tokens (RolloutTrainerConfig) and the matching `areno train` flags. Verified on Ling-3.0-tiny-base (H200): model-side equivalence passes, k=2 decode phase 1.54 s vs 2.50 s plain (1.62x) with accept length 2.37.
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.
What does this PR do?
Wires bailing_v3's native multi-token-prediction (MTP) head into both halves of the train-infer loop. Until now the MTP layer shipped in Ling / Bailing V3 checkpoints was dropped at load time, so it degraded silently during RL fine-tuning and the rollout engine could not use it to draft tokens.
Phase 0, MTP training loss. The checkpoint spec loads and saves the MTP layer through a generic
ExtraLayerListSpec, the model runs it asBailingMTPLayerwhenTrainMeta.mtp_enabledis set, and an auxiliary t+2 loss is added whenruntime.mtp_loss_scaleis given explicitly. The checkpoint'smtp_loss_scaling_factoris never inherited: the loss trains toward every response token and would push preference objectives such as DPO toward their rejected rows.Phase 2, rollout speculative decoding,
runtime.speculative_draft_tokens = k. One decode forward verifiesk + 1tokens per row viaInferMeta.tokens_per_seq(flash backend only, the native backend refuses it). KDA linear-attention layers reuse the recurrent kernel's existing target-verify mode, with their recurrent and conv caches stacked across layers so the commit is four kernels and one shared verify-state buffer serves every CUDA-graph bucket. The MTP layer drafts EAGLE-style with its own paged KV cache;SpeculativeDraftModelinareno/models/base.pyis the model-side protocol.areno/engine/runtime/speculative.pyimplements the sampler-equivalent target distribution and exact chain rejection sampling, so the sampled distribution and the reported logprobs are unchanged. Verify and draft forwards have per-bucket CUDA graphs, and the rollout logs the mean accept length.Also fixes
_cancel_stop_tokencrashing onignore_eos=True(the CUDA backend passeseos_token_id=(); that path had never worked) and stops the cancel fallback marker from becoming a truncation stop token. Design and method:docs/issues/mtp-speculative-decoding.md.Results on
inclusionAI/Ling-3.0-tiny-base, 1x H200, flash backendMTP head wiring (Phase 0), natural text, 24-layer trunk plus one MTP layer:
On-policy accept probability of the MTP head at temperature 1.0 (closed form,
alpha = sum min(p, q), 8192 gsm8k positions):Decode phase inside the worker (sum of decode steps, 256 forced tokens per row, temperature 1.0, k=2; the client wall clock also carries ~10 s per session of weight fuse/offload and is not a decode measure):
k=1 at 16 rows gives 1.29x (accept length 1.87), so k=2 is the default worth using with this single-layer head. Verify at
3 x rowstokens costs 1.2x to 1.3x a plain step, matching the memory-bound L(B) curve in the RFC.Per-step optimizations that brought the speculative step from 16.3 ms to 13.2 ms at 16 rows:
torch.multinomial, chunked logprobs, per-layer commitnonzero/ boolean-index host syncs, one-pass logprobs, Gumbel-max drawsRelated issue
No tracking issue; the RFC at
docs/issues/mtp-speculative-decoding.mdholds the motivation, method and results.Type of change
How was it tested?
CPU (no GPU):
pytest tests/test_speculative_cpu.py tests/test_speculative_rollout_cpu.py tests/test_inference_scheduler_cpu.py tests/test_bailing_kv_cache_cpu.py tests/test_bailing_v3_mtp_cpu.py tests/test_cancel_stop_token_cpu.py -k cpu, 161 passed together with the neighbouring LoRA, routing-replay, registry, recompute, config and engine-role suites. They cover sampler equivalence with and without top-k/top-p, distribution preservation of rejection sampling (1.5% over 40k trials, exact under greedy), the real decode loop driven by a deterministic fake model (accepted and rejected drafts, stop token inside a step, length cap, continuous-batching admission, k=1), MTP layer forward and checkpoint round trip, and the cancel-stop regression.GPU (one H200, Ling-3.0-tiny-base, not in the CPU suite):
Hardware limitations: TP=1 on a single GPU with the flash backend; TP>1 is only exercised through the CPU tests' single-rank context; the native backend rejects
tokens_per_seq > 1.Checklist
pytest tests/ -k cpu): all touched suites pass; the threetest_moe_sequence_parallel_cpuand twotest_policy_tensor_sync_cpufailures reproduce on the base commit and are unrelated.RuntimeConfigfields with inert defaults (mtp_loss_scale=None,speculative_draft_tokens=0), one optionalCausalLMOutputfield, no CLI changes.