feat(kt-kernel): add score-aware expert placement#2064
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a new expert placement planning module (expert_placement.py) for heterogeneous MoE inference, adding a score_aware_layer_balanced strategy with EMA-smoothed scores and per-layer bounds, and integrates it into the existing generate_gpu_experts_masks API. Feedback focuses on PyTorch performance optimizations, specifically converting tensors to lists to avoid slow .item() calls inside nested loops, and vectorizing the minimum layer coverage constraint loop using torch.topk and scatter_.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| candidates: list[tuple[float, int, int]] = [] | ||
| for layer_idx in range(num_layers): | ||
| for expert_idx in range(num_experts_per_layer): | ||
| if not bool(mask[layer_idx, expert_idx].item()): | ||
| candidates.append( | ||
| (float(scores[layer_idx, expert_idx].item()), layer_idx, expert_idx) | ||
| ) |
There was a problem hiding this comment.
Calling .item() on individual tensor elements inside a nested loop is extremely slow in PyTorch due to host-device synchronization and Python-C++ boundary crossing overhead. Converting the tensors to Python lists using .tolist() beforehand allows the loop to run entirely in pure Python, which is orders of magnitude faster.
| candidates: list[tuple[float, int, int]] = [] | |
| for layer_idx in range(num_layers): | |
| for expert_idx in range(num_experts_per_layer): | |
| if not bool(mask[layer_idx, expert_idx].item()): | |
| candidates.append( | |
| (float(scores[layer_idx, expert_idx].item()), layer_idx, expert_idx) | |
| ) | |
| scores_list = scores.tolist() | |
| mask_list = mask.tolist() | |
| candidates: list[tuple[float, int, int]] = [] | |
| for layer_idx in range(num_layers): | |
| for expert_idx in range(num_experts_per_layer): | |
| if not mask_list[layer_idx][expert_idx]: | |
| candidates.append( | |
| (scores_list[layer_idx][expert_idx], layer_idx, expert_idx) | |
| ) |
| # First satisfy the minimum layer coverage constraint. | ||
| if min_experts_per_layer > 0: | ||
| for layer_idx in range(num_layers): | ||
| layer_scores = scores[layer_idx] | ||
| _, expert_indices = torch.topk( | ||
| layer_scores, | ||
| k=min_experts_per_layer, | ||
| largest=True, | ||
| sorted=False, | ||
| ) | ||
| mask[layer_idx, expert_indices] = True | ||
| per_layer_count[layer_idx] = min_experts_per_layer |
There was a problem hiding this comment.
The minimum layer coverage constraint can be fully vectorized using torch.topk along dim=1 and Tensor.scatter_, completely avoiding the Python loop over num_layers.
# First satisfy the minimum layer coverage constraint.
if min_experts_per_layer > 0:
_, expert_indices = torch.topk(
scores,
k=min_experts_per_layer,
dim=1,
largest=True,
sorted=False,
)
mask.scatter_(1, expert_indices, True)
per_layer_count = [min_experts_per_layer] * num_layers
Summary
This PR adds an optional
score_aware_layer_balancedstrategy for generating GPU expert masks inkt-kernel.The existing default behavior is unchanged:
still uses the current global frequency top-k placement.
The new strategy adds:
previous_scoresandalphamin_experts_per_layer/max_experts_per_layerMotivation
KTransformers already supports [CPU-GPU expert scheduling] and documents placement strategies such as
uniform,frequency,front-loading, andrandom.The current [
[generate_gpu_experts_masks](https://github.com/kvcache-ai/ktransformers/blob/main/kt-kernel/python/experts_base.py)] helper uses global top-k frequency placement. That is useful, but it can over-concentrate GPU experts in a few layers. This PR keeps the existing behavior intact while adding a score-aware, layer-balanced option for offline profiling and future scheduling work.This also aligns with the [KTransformers 2026 Q2 roadmap](#1921), which mentions expert offloading/scheduling optimization and CPU-GPU coordination.
Background
This PR is inspired by recent hybrid MoE inference work:
This PR does not implement a full runtime scheduler, prefetcher, cache manager, CUDA kernel, or SGLang runtime change. It only adds a small placement-mask utility while preserving default behavior.
Changed files
kt-kernel/python/expert_placement.pykt-kernel/python/experts_base.pygenerate_gpu_experts_maskswhile preserving default behavior.kt-kernel/python/__init__.pyplan_gpu_expert_placement.kt-kernel/test/per_commit/test_expert_placement.pydoc/en/kt-kernel/experts-sched-Tutorial.mdValidation
Scope
This PR is intentionally limited to placement-mask generation. It avoids CUDA, kernel changes, SGLang runtime changes, and runtime prefetch/cache behavior.