Support strided Liger MoE input weights - #1377
Merged
supercharleszhu merged 2 commits intoAug 13, 2026
Merged
Conversation
Allow fused forward MoE to consume gate and up projections as inner-contiguous views with a larger expert stride, avoiding persistent copies of packed w13 weights. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Validate gate hidden dimensions before constructing TMA descriptors and reject expert-strided weights in the contiguous-only autograd path before native forward allocation. Cover both behaviors in binding and distributed autograd tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
kolehma8
reviewed
Aug 12, 2026
| mlp_dims.intermediate_dim = intermediate_dim; | ||
| mlp_dims.total_n_rows_1 = total_n_rows_1; | ||
| mlp_dims.total_n_rows_2 = total_n_rows_2; | ||
| mlp_dims.expert_n_stride_1 = weight_expert_stride_rows / Traits1::TileN; |
Collaborator
There was a problem hiding this comment.
would this break the existing use cases?
Collaborator
Author
There was a problem hiding this comment.
It will not (verified in unit test as well), weight_expert_stride_rows = (a.weight_expert_stride / hidden_dim), where weight_expert_stride is all_stride(0) by default. In original setup it is I * D. So expert_n_stride_1 will become I / TileN which is same as num_n_tiles_1
kolehma8
approved these changes
Aug 13, 2026
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.
Summary
Support strided input weights for MOE.
Problems
Qwen-style MoE checkpoints store both input projections in one packed tensor:
Each gate/up matrix is contiguous internally, but adjacent experts are
2 * intermediate * hiddenelements apart. The current binding rejects theseviews because the overall tensor is not contiguous. Serving integrations must
therefore call
.contiguous()on both views. For Qwen3-235B, those retainedcopies consume approximately 0.375 GiB per layer, or 35.25 GiB per GPU across
94 MoE layers, reducing KV-cache capacity and causing OOM at 90% memory
utilization.
Relaxing only the binding check would be incorrect. The old kernel
defines
num_n_tiles_1asintermediate_dim / TileNand then
uses
expert * dims.num_n_tiles_1as the expert's starting weight tile.Together, these lines assume adjacent experts are separated by exactly
intermediate / TileNweight tiles:For packed gate weights, physical tiles are:
Using the old
expert * 12offset makes expert 1 gate computation read expert0 up weights. The same issue causes the up descriptor to read the next expert's
gate weights. Outputs would therefore be silently corrupted.
This PR passes the actual expert stride from the tensor metadata and uses it
only to locate each expert's first tile. Each expert still computes exactly
intermediate / TileNuseful tiles. For ordinary contiguous weights, thephysical stride equals the useful tile count, so existing behavior is unchanged.
Notes
This PR supports expert-strided gate/up weights for forward no-grad inference.
The public
moe_fusedno-grad path calls the native forward directly and popsits symmetric buffers immediately.
The grad-enabled path enters
LigerExpertParallelFusedMoEFunction.forward,which rejects non-contiguous gate/up tensors before resolving the NVSHMEM team
or launching native forward:
Testing Done
make testto ensure correctnessmake checkstyleto ensure code stylemake test-convergenceto ensure convergenceTargeted validation:
Built
liger_cute_kernels-0.1.0+cu130.torch2.11.0-cp312-cp312-linux_x86_64.whl(
sha256: 22a12d6f8825b377f94f8b4a6c48a0350c2c488e2baa33bf569c8b2ce4ce3993).Ran the complete fused-MoE CUDA graph test file on eight GPUs: 6 passed,
including packed-view parity, forward/backward graphs, unaligned token tails,
and single-token automatic dispatch.
Verified the final review fixes:
w13views match contiguous weights on eight GPUs; andgrad mode before native allocation, and preserves the contiguous grad path.
Integrated DP8+EP8 Qwen3-235B vLLM replay at 90% GPU memory completed 2,048
requests with zero errors in 36.20 seconds, allocating 47.98 GiB of KV cache
and 267,584 KV tokens per rank.
Native layout microbenchmark using identical weights, routes, tuned
configurations, and alternating execution order:
The differences are within measurement noise; expert-strided TMA addressing
has no meaningful kernel latency penalty. Raw measurements:
/shared/public/sharing/seeker_summary_rl/v07_test/liger_strided_weight_microbench_20260812_080042.🤖 Generated with GitHub Copilot CLI