main
py 96 lines 3.27 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 import torch
4
5 from vllm import _custom_ops as ops
6
7
8 def mhc_pre_cpu(
9 residual: torch.Tensor,
10 fn: torch.Tensor,
11 hc_scale: torch.Tensor,
12 hc_base: torch.Tensor,
13 rms_eps: float,
14 hc_pre_eps: float,
15 hc_sinkhorn_eps: float,
16 hc_post_mult_value: float,
17 sinkhorn_repeat: int,
18 n_splits: int = 1,
19 norm_weight: torch.Tensor | None = None,
20 norm_eps: float = 0.0,
21 ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
22 """CPU-ported mHC pre block (see `mhc_pre_torch` for the eager reference).
23
24 The ported kernel (`hc_pre_fused_cpu`) only exposes one merged `hc_eps`
25 (used for both `hc_pre_eps`/`hc_sinkhorn_eps`) and hardcodes the post-mix
26 multiplier to 2.0 -- true of every real call site in
27 `models/deepseek_v4/cpu/model.py`, so this is not a capability loss here.
28 """
29 assert n_splits == 1, "mhc_pre_cpu does not support n_splits != 1"
30 assert hc_pre_eps == hc_sinkhorn_eps, (
31 "mhc_pre_cpu requires hc_pre_eps == hc_sinkhorn_eps (single merged hc_eps)"
32 )
33 assert hc_post_mult_value == 2.0, "mhc_pre_cpu hardcodes the post-mix multiplier"
34
35 hc_mult, hidden_size = residual.shape[-2:]
36 outer_shape = residual.shape[:-2]
37 x_flat = residual.reshape(-1, hc_mult, hidden_size)
38
39 layer_input, post, comb = ops.hc_pre_fused_cpu(
40 x_flat,
41 fn,
42 hc_scale,
43 hc_base,
44 hc_mult,
45 sinkhorn_repeat,
46 rms_eps,
47 hc_pre_eps,
48 )
49
50 post_mix = post.view(*outer_shape, hc_mult, 1)
51 comb_mix = comb.view(*outer_shape, hc_mult, hc_mult)
52 layer_input = layer_input.view(*outer_shape, hidden_size)
53 return post_mix, comb_mix, layer_input
54
55
56 def mhc_post_cpu(
57 x: torch.Tensor,
58 residual: torch.Tensor,
59 post_layer_mix: torch.Tensor,
60 comb_res_mix: torch.Tensor,
61 ) -> torch.Tensor:
62 """CPU-ported mHC post block (see `mhc_post_torch` for the eager reference)."""
63 hc_mult, hidden_size = residual.shape[-2:]
64 outer_shape = residual.shape[:-2]
65
66 x_flat = x.reshape(-1, hidden_size)
67 residual_flat = residual.reshape(-1, hc_mult, hidden_size)
68 post_flat = post_layer_mix.reshape(-1, hc_mult).float()
69 comb_flat = comb_res_mix.reshape(-1, hc_mult, hc_mult).float()
70
71 out = ops.hc_post_fused_cpu(x_flat, residual_flat, post_flat, comb_flat)
72 return out.view(*outer_shape, hc_mult, hidden_size)
73
74
75 def hc_head_fused_cpu(
76 hidden_states: torch.Tensor,
77 hc_fn: torch.Tensor,
78 hc_scale: torch.Tensor,
79 hc_base: torch.Tensor,
80 rms_norm_eps: float,
81 hc_eps: float,
82 ) -> torch.Tensor:
83 """CPU-ported HC head reduction (see `test_hc_head_cpu` in
84 tests/kernels/mhc/test_mhc_kernels.py for the eager reference this is tested
85 against).
86
87 The ported kernel's C++ signature takes `(hc_eps, norm_eps)` -- the
88 opposite order from this wrapper's `(rms_norm_eps, hc_eps)`, which matches
89 the real call site in `models/deepseek_v4/cpu/model.py`.
90 """
91 hc_mult, hidden_size = hidden_states.shape[-2:]
92 outer_shape = hidden_states.shape[:-2]
93 hs_flat = hidden_states.reshape(-1, hc_mult, hidden_size)
94
95 out = ops.hc_head_fused_cpu(hs_flat, hc_fn, hc_scale, hc_base, hc_eps, rms_norm_eps)
96 return out.view(*outer_shape, hidden_size)