Skip to content

Add situ activation - #395

Open
ZJY0516 wants to merge 3 commits into
deepseek-ai:nv_devfrom
vllm-project:situ-activation
Open

Add situ activation#395
ZJY0516 wants to merge 3 commits into
deepseek-ai:nv_devfrom
vllm-project:situ-activation

Conversation

@ZJY0516

@ZJY0516 ZJY0516 commented Jul 29, 2026

Copy link
Copy Markdown

Test

DG_JIT_CACHE_DIR="$PWD/.cache/deep_gemm" \
    python tests/test_mega_moe.py \
      --num-processes 1 \
      --num-max-tokens-per-rank 128 \
      --num-tokens 32 \
      --num-experts 8 \
      --num-topk 1 \
      --num-shared-experts 0 \
      --activation situ \
      --activation-clamp inf

Comment on lines +163 to +164
activation_beta: Optional[float] = None,
activation_linear_beta: Optional[float] = None,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 critical: 保持 fast_math 的原有位置参数索引: 现有调用若以位置参数传入 fast_math(如 ..., 'swiglu', 10, False),这里新增的参数会让 False 被绑定为 activation_beta,而 fast_math 回落为 True;SwiGLU 路径不会拒绝该 beta,因此会静默改变数值和性能行为。应保留原参数顺序或将新参数设为仅限关键字。

🤖 v6

mma_type: str = 'fp8xfp4',
activation: str = 'swiglu'):
assert activation == 'swiglu', f'Only `swiglu` activation is supported, got `{activation}`'
assert activation in ('swiglu', 'situ'), f'Unsupported activation `{activation}`'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 warning: 不要为 BF16 路径放行 situ: 当 mma_type='bf16xbf16'activation='situ' 时,此处及缓冲区大小接口会接受配置,但 bf16_mega_moe 仍执行 DG_HOST_ASSERT(activation == "swiglu"),因此该公开配置必然在运行时失败。应按 MMA 类型限制这里的取值,或同时实现 BF16 SiTU。

🤖 v6

Comment thread tests/test_mega_moe.py
y=y, l1_weights=transformed_l1_weights, l2_weights=transformed_l2_weights,
sym_buffer=buffer,
cumulative_local_expert_recv_stats=cumulative_local_expert_recv_stats_fused,
activation=args.activation,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 warning: 避免用 SwiGLU 基线校验 SiTU 输出: 当 legacy deep_ep/tilelang 可用且使用 --activation situ 时,融合路径在这里切换为 SiTU,但 run_baseline 和共享专家基线仍固定调用 swiglu_apply_weight_to_fp8;默认正确性测试随后进行精确比较,因而必然失败。SiTU 应使用对应基线,或跳过该 legacy 比较并运行新的 PyTorch 参考实现。

🤖 v6

Comment thread tests/test_mega_moe.py
Comment on lines +365 to +367
l1 = x_ref[token] @ l1_weights_ref[expert].T
gate, up = l1.to(torch.bfloat16).float().chunk(2)
if args.activation == 'situ':

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 warning: 在参考实现中复现 activation_clamp: 在无 legacy 基线的单卡参考测试中,只要 activation_clamp 有限(默认是 10),内核会先将 gate 上界及 up 双边截断,而这里直接对未截断的 L1 输出应用激活。默认随机矩阵乘积通常远超 10,因此该断言比较的是不同函数,SwiGLU 和 SiTU 都可能稳定失败。

🤖 v6

Comment thread tests/test_mega_moe.py
else:
create_inputs()

if (not is_legacy_loaded and not is_bf16xbf16 and num_ranks == 1 and

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 critical: New reference check ignores activation_clamp, so it fails with default arguments. The kernel clamps the L1 output before the activation (kActivationClamp, default --activation-clamp 10): the gate is clamped from above only (__hmin2), the up branch symmetrically (__hmax2 + __hmin2). The new PyTorch reference computes gate/up with no clamping at all. With the default --input-scale 1.0 --weight-scale 1.0 and hidden=7168 the L1 pre-activations have std ~ sqrt(7168) ~ 85, so virtually every element is clamped by the kernel and not by the reference, and assert_close(rtol=0.08, atol=5e-4) cannot pass. The check therefore only works with undocumented flag combinations (tiny scales, or --activation-clamp inf). Suggestion: mirror the kernel in the reference - gate = gate.clamp(max=args.activation_clamp) and up = up.clamp(-args.activation_clamp, args.activation_clamp) when the clamp is finite - and/or document/assert the required flags.

🤖 v7

Comment thread tests/test_mega_moe.py
num_topk == 1 and num_shared_experts == 0):
fused_y = run_fused()[0]
ref_y = torch.empty_like(fused_y)
for token in range(num_tokens):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 warning: The per-token Python reference loop is prohibitively slow, and masked tokens index expert -1. The loop runs once per token (up to --num-max-tokens-per-rank, default 8192) and does a 7168x6144 fp32 matmul plus an FP8 quantisation each iteration. Also, with --masked-ratio > 0, expert = topk_idx[token, 0].item() can be -1, silently selecting the last expert (it only happens to produce ~0 because topk_weights is 0 there). Suggestion: check a bounded random subset of tokens (e.g. 32-64) or batch the reference with a single grouped matmul, and continue explicitly when expert < 0 while asserting the fused output is zero.

🤖 v7

Comment thread tests/test_mega_moe.py
f'{fused_y.float().abs().max().item():.3f}, ref mean/max='
f'{ref_y.float().abs().mean().item():.3f}/{ref_y.float().abs().max().item():.3f}',
once_in_node=True)
torch.testing.assert_close(fused_y, ref_y, rtol=0.08, atol=5e-4)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 suggestion: The tolerances are simultaneously too loose and too tight: rtol=0.08 allows an 8% per-element error (which would hide real regressions), while atol=5e-4 is far below the quantisation noise floor for near-zero elements of an output whose magnitude is O(10^2), making the check seed-dependent and flaky. Suggestion: use the repository's aggregate metric (calc_diff, already used at line 351) with a documented threshold, or keep assert_close with an atol derived from the output scale (e.g. 0.02 * ref_y.abs().mean()).

🤖 v7

recipe: Tuple[int, int, int] = (1, 1, 32),
activation: str = 'swiglu',
activation_clamp: Optional[float] = None,
activation_beta: Optional[float] = None,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 suggestion: The new public option is undocumented. activation='situ' and the activation_beta / activation_linear_beta parameters are new public API surface, but the Mega MoE section still describes the epilogue as 'SwiGLU' and the usage snippet does not mention the activation options. The kernel comments were only partially updated too (// Apply gated activation. at sm100_fp8_fp4_mega_moe.cuh:1045 while the surrounding 'Unified L1 epilogue: SwiGLU in-place' comment and csrc/jit_kernels/heuristics/mega_moe.hpp:153 still say SwiGLU). Suggestion: document the formula (gate = beta*tanh(x/beta)sigmoid(x), optional up = beta_lintanh(up/beta_lin)), the defaults (beta=1.0, beta_lin=-1.0 meaning disabled) and the FP8xFP4-only support, and refresh the SwiGLU-specific comments in the touched epilogue.

🤖 v7

) -> Tuple[Union[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]],
Union[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]]]:
assert activation == 'swiglu', f'Only `swiglu` activation is supported, got `{activation}`'
Union[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]]]:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 suggestion: Unrelated indentation churn: the continuation line of the transform_weights_for_mega_moe return annotation was re-indented from 11 to 13 spaces, which has nothing to do with this feature and now mis-aligns with the opening bracket. Also activation stays a validate-only parameter in this function, so it reads as dead - a one-line comment saying situ reuses the same gate/up interleaved layout as swiglu would help. Suggestion: revert the whitespace change and add the clarifying comment.

🤖 v7

Comment thread csrc/apis/mega.hpp
@@ -168,6 +168,8 @@ static void fp8_fp4_mega_moe(
const std::tuple<int, int, int>& recipe,
const std::string& activation,
const std::optional<float>& activation_clamp_opt,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 suggestion: Two positional parameters were inserted before fast_math in the pybind signature. _C.fp8_fp4_mega_moe is registered without py::arg names (register_apis), so the new activation_beta_opt / activation_linear_beta_opt are positional-only and any external caller that passed fast_math positionally now silently mis-binds a bool into a float slot. Suggestion: append the new parameters at the end of the signature, or add named py::arg(...) bindings, and mention the change in the release notes.

🤖 v7

@ds-review-bot

Copy link
Copy Markdown
Collaborator

🤖 ds-review-bot Code Review

v6

该变更会静默破坏现有位置参数调用,并暴露一个实际不受支持的 BF16 SiTU 配置。此外,两条新增或既有的正确性校验路径都没有与 SiTU 内核保持一致。

v4

⚠️ 未完成评审(no_result_file:模型未产出结果文件)

v7

The MR adds a second gated activation ('situ': gate = beta*tanh(x/beta)sigmoid(x), with an optional soft-clamped up = beta_lintanh(up/beta_lin)) to the SM100 FP8xFP4 Mega-MoE epilogue, threads two new optional host parameters (activation_beta, activation_linear_beta) through the Python wrapper -> pybind API -> JIT codegen -> kernel template, and adds a PyTorch reference check plus new CLI knobs to tests/test_mega_moe.py. The kernel math is correct and matches the new PyTorch reference, the codegen bookkeeping lines up (26 placeholders / 26 arguments / 26 non-defaulted template params, same order), and hex-float to_string keeps the constants exact, so the swiglu path is unchanged under fast math. The problems are mostly on the host/test side: (1) the new reference check does not model activation_clamp, so it cannot pass with the default flags; (2) when the legacy baseline is loaded, situ output is still compared bit-exactly against the tilelang SwiGLU baseline (guaranteed failure) while the new reference block is skipped in exactly that configuration, leaving situ without a green validation path; (3) _cast_weights_to_fp4 now unconditionally materialises fp32 dequantised copies of all expert weights (tens of GB in the default config) even when the reference check never runs; (4) the BF16 Mega-MoE path accepts 'situ' at buffer-creation / weight-transform time but hard-asserts activation == "swiglu" inside bf16_mega_moe, so --mma-type bf16xbf16 --activation situ dies on an opaque assert. Additionally there is an IEEE division by a compile-time constant in the hottest epilogue loop, an accidental numerical change to the non-fast-math swiglu path, JIT-cache duplication for swiglu with non-default betas, and no documentation of the new public option.

Files reviewed: 5
Issues found: 🔴 5 critical | 🟡 8 warning | 🔵 6 suggestion
Inline comments posted: 19

⚠️ Parse warning: [v4] no_result_file:模型未产出结果文件

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants