Conversation
…e test Add examples/pytorch/llm/: a self-contained Llama/Qwen2/Qwen3 dense decoder built from FlashInfer serving-path ops (BatchPrefill/BatchDecode paged-KV wrappers, append_paged_kv_cache, RoPE, rmsnorm/fused_add_rmsnorm, silu_and_mul, top-k/top-p sampling), loading weights directly from HF safetensors with no inference framework in the dependency chain. smoke_test.py verifies integration-level invariants unit tests cannot see: JIT cache reuse across processes (zero rebuilds on a warm run), zero steady-state recompiles during decode, greedy determinism, and liveness. Tracking doc: docs/design_docs/e2e_pytorch_llm_examples.md (motivation, B200 model-fit analysis, roadmap for MoE / quantized / TP phases). AI-assisted (Claude Code). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…uild() calls JitSpecNvcc.try_load() returns None for JIT-path modules by design (ninja owns freshness), so build() runs every process and no-ops on a warm cache. Count a compile only when the built artifact changes; report raw build() invocations separately as jit_build_calls. Record first-deployment findings in the design doc. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… v5 compat) apply_chat_template's tokenized return type changed across transformers versions; render to text and tokenize explicitly instead. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rving Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…eference check Add qwen3_moe to the example model: HF expert weights stacked into the cutlass_fused_moe w31/w2 layout (up_proj above gate_proj; SiLU applied in-kernel), router softmax->topk->renorm in fp32 mirroring the HF Qwen3MoeSparseMoeBlock, per-layer sparse/dense selection. reference_check.py builds tiny random-weight dense/MoE checkpoints with transformers and asserts our last-token prefill logits match transformers eager within a relative-L2 tolerance — same kernel paths as Qwen3-30B-A3B without the 60GB download. GenerationEngine gains prefill_logits() for this. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…, num_local_experts) v5 nests rope under config.rope_parameters and serializes the MoE expert count as num_local_experts. The old flat schema read rope_theta=1e4 by default for v5-saved checkpoints, skewing RoPE frequencies — caught by reference_check.py as a with-length-growing logits divergence. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Shard weights at load: attention QKV column-parallel / o_proj row-parallel, dense FFN gate/up column- / down row-parallel, MoE experts expert-parallel via cutlass_fused_moe ep_size/ep_rank with global routing on every rank. Two allreduces per layer (post-attention, post-FFN/MoE) over NCCL. Launch with torchrun; reference_check.py compares the TEP result on rank 0 against the single-GPU transformers reference. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Measures import/load/cold-prefill (JIT warmup)/warm prefill/decode throughput and steady-state recompile count, single-GPU or TEP via torchrun; JSON output for future performance gates. Autotune re-measure behind --autotune. CUDA-graph decode capture is a noted follow-up. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ops note Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Closes a structural hole in the harness: every stage ran greedy (`--temperature 0.0` short-circuits to `argmax`), so `flashinfer.sampling.top_k_top_p_sampling_from_logits` was never invoked and the `sampling` and `topk` JIT modules were never even compiled. Measured on B200: greedy builds 4 modules, sampling builds 2 more — nothing in the suite had ever touched them. Running the kernel is not enough; a wrong answer has to be caught. So `--check-sampling` audits every sampled token against a plain-torch reference support (top-k ∩ nucleus over the same temperature-scaled logits). Both boundaries close over ties and the eps slack is applied on the permissive side only, so the mask is a superset of what any correct implementation may keep and a violation is unambiguous. Mirrors how tests/utils/test_sampling.py asserts membership. Membership alone has two blind spots, both covered: - a *vacuous* check — with top_k=0/top_p=1.0 the admissible set is the whole vocabulary and can never fail — so the mean admissible set size is reported and bounded (measured 4.3 of 151936, i.e. genuinely selective); - a sampler silently degenerated to argmax, which is always inside the support — so divergences from greedy are counted against how many the filtered distribution predicts (measured 15 observed vs 16.58 expected). Also audited: token ids in range, seeded replay on identical logits, and the same membership check with per-request *tensor* top_k/top_p, which takes a different kernel path (a scalar top_k on a large vocab only ever exercises the top_k_first fast path). smoke_test.py gains a sampling run pair alongside the greedy pair, asserting all of the above plus seeded cross-process determinism and sampling/topk JIT cache reuse. Greedy remains the default everywhere and its existing assertions are untouched. `--skip-sampling` restores the old behavior. Validated on B200 against flashinfer 0.6.16rc3 (which carries flashinfer-ai#4189's `__launch_bounds__` gate): all bars green, reference_check unregressed. AI-assisted (Claude Code).
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
📌 Description
Closes a structural hole in the e2e LLM example harness (#4083, which this
stacks on — the diff includes #4083's commits until it lands).
Every stage of the harness ran greedy:
--temperaturedefaults to0.0andsample_tokens()short-circuits tologits.argmax(), soflashinfer.sampling.top_k_top_p_sampling_from_logitswas never invokedand the
samplingandtopkJIT modules were never even compiled.Measured on B200: the greedy path builds 4 modules, the sampling path builds
2 more. Nothing in the suite had ever touched them.
Running the kernel is not enough — a wrong answer has to be caught. So
--check-samplingaudits every sampled token against a plain-torch referencesupport (top-k ∩ nucleus, from the same temperature-scaled logits). Both
boundaries close over ties and the
epsslack is applied on the permissiveside only, so the mask is a superset of what any correct implementation may
keep and a violation is unambiguous. This mirrors how
tests/utils/test_sampling.pyasserts membership.Membership alone has two blind spots, both covered:
top_k=0/top_p=1.0the admissible set is thewhole vocabulary and can never fail. So the mean admissible set size is
reported and bounded. Measured: 4.3 of 151936, i.e. genuinely selective.
membership is blind to it. So divergences from greedy are counted against
how many the filtered distribution predicts. Measured: 15 observed vs
16.58 expected.
Also audited: ids in range, seeded replay on identical logits, and the same
membership check with per-request tensor
top_k/top_p— a differentkernel path, since a scalar
top_kon a large vocab only ever exercises thetop_k_firstfast path.smoke_test.pygains a sampling run pair alongside the greedy pair, assertingall of the above plus seeded cross-process determinism and
sampling/topkJIT cache reuse. Greedy remains the default everywhere and its existing
assertions are untouched;
--skip-samplingrestores the old behavior.🔍 Related Issues
Stacks on #4083. Relevant to #4189 (
__launch_bounds__gated to SM107): thatchange makes B200 sampling codegen match what
mainalready ships (main haszero
launch_boundsinsampling.cuh), so it is not a new Blackwell path —but this is the first e2e coverage of sampling either way.
🧪 Tests
Validated on B200 (sm100a) against flashinfer 0.6.16rc3 (the tree that
carries #4189's gate — verified present in the tested checkout):
sample_violations/ 72 drawssample_out_of_rangesample_allowed_meansample_replay_matchsample_perreq_violationssmoke_test.py(4 runs)topk+sampling, run 4 built 0reference_check.py --arch denseNote on the cross-process sampled-determinism bar: it is a hard assertion
rather than gated on a logits fingerprint, because the harness already
asserts greedy determinism as a hard bar. If model numerics ever stopped being
bit-reproducible, greedy determinism would fail first and more legibly.
✅ Checklist
pre-commit run -aviolation there surfaces only as a nonzero exit code)
AI-assisted (Claude Code).