Skip to content

Commit e93ba33

Browse files
committed
perf(pt): replace SeZM CuTe inference kernels
1 parent 7efec3a commit e93ba33

86 files changed

Lines changed: 248 additions & 1796 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

deepmd/dpmodel/descriptor/dpa4_nn/so2.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1616,7 +1616,6 @@ def __init__(
16161616
# value path: every hook stays ``None`` and ``so2_message`` takes the
16171617
# dense branch. The ``pt_expt`` backend binds the selected implementation.
16181618
self._triton_value_path = None
1619-
self._cute_value_path = None
16201619
self._cutile_value_path = None
16211620

16221621
# === Step 14. Optional fused training seams ===
@@ -2375,12 +2374,6 @@ def so2_message(
23752374
if self._cached_edge_csr_fn is not None:
23762375
self._cached_edge_csr_fn(edge_cache, "src", x.shape[0])
23772376
x_local, rad_feat = self._triton_value_path(x, edge_cache, radial_feat)
2378-
elif self._cute_value_path is not None and not training:
2379-
# === Steps 1-5 (fused CuTe operator). The operator folds
2380-
# rotate_to_local, radial degree mixing, the multi-layer gated SO(2)
2381-
# stack, and the focus competition into the bucketed kernels; the
2382-
# per-edge focus-major intermediates stay resident on chip. ===
2383-
x_local, rad_feat = self._cute_value_path(x, edge_cache, radial_feat)
23842377
else:
23852378
# === Steps 1-3. Rotation, radial mixing and the focus-major cast ===
23862379
x_local, rad_feat = self._rotate_mix(x, edge_cache, radial_feat)

deepmd/kernels/cute/neo/__init__.py

Lines changed: 0 additions & 3 deletions
This file was deleted.

deepmd/pt/model/descriptor/sezm.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@
5252
from deepmd.dpmodel.utils.seed import (
5353
child_seed,
5454
)
55-
from deepmd.kernels.cute.neo import runtime_policy as cute_runtime_policy
5655
from deepmd.pt.utils import (
5756
env,
5857
)
@@ -66,6 +65,7 @@
6665
from deepmd.pt.utils.update_sel import (
6766
UpdateSel,
6867
)
68+
from deepmd.pt_expt.kernels.cute.sezm import runtime_policy as cute_runtime_policy
6969
from deepmd.pt_expt.kernels.utils import (
7070
cuda_infer_level,
7171
use_amp_infer,
@@ -1776,7 +1776,7 @@ def forward_with_edges(
17761776
@torch.jit.unused
17771777
def _run_output_readout(self, ffn_in: torch.Tensor) -> torch.Tensor:
17781778
"""Return the residual-inclusive scalar output with guarded CuTe routing."""
1779-
from deepmd.kernels.cute.neo.readout_l0 import (
1779+
from deepmd.pt_expt.kernels.cute.sezm.readout_l0 import (
17801780
run_neo_output_readout,
17811781
)
17821782

@@ -1953,7 +1953,7 @@ def _packed_wigner_candidate(
19531953
geometry_dtype: torch.dtype,
19541954
) -> bool:
19551955
"""Return whether all blocks satisfy packed K1's stable contract."""
1956-
from deepmd.kernels.cute.neo.k1 import (
1956+
from deepmd.pt_expt.kernels.cute.sezm.k1 import (
19571957
is_packed_wigner_candidate,
19581958
)
19591959

deepmd/pt/model/descriptor/sezm_nn/block.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,16 @@
2626
from deepmd.dpmodel.utils.seed import (
2727
child_seed,
2828
)
29-
from deepmd.kernels.cute.neo.runtime_policy import (
30-
is_cute_infer_enabled,
31-
)
3229
from deepmd.pt.utils import (
3330
env,
3431
)
3532
from deepmd.pt.utils.env import (
3633
PRECISION_DICT,
3734
RESERVED_PRECISION_DICT,
3835
)
36+
from deepmd.pt_expt.kernels.cute.sezm.runtime_policy import (
37+
is_cute_infer_enabled,
38+
)
3939
from deepmd.utils.version import (
4040
check_version_compatibility,
4141
)
@@ -834,7 +834,7 @@ def _run_so2_unit_impl(
834834
) -> torch.Tensor:
835835
"""Run the SO(2) unit implementation."""
836836
if not self.training and is_cute_infer_enabled():
837-
from deepmd.kernels.cute.neo.k1 import (
837+
from deepmd.pt_expt.kernels.cute.sezm.k1 import (
838838
maybe_run_cute_k1,
839839
)
840840

deepmd/pt/model/descriptor/sezm_nn/edge_cache.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
rearrange,
2626
)
2727

28-
from deepmd.kernels.cute.neo.runtime_policy import (
28+
from deepmd.pt_expt.kernels.cute.sezm.runtime_policy import (
2929
is_cute_infer_enabled,
3030
)
3131

@@ -795,7 +795,7 @@ def _build_edge_wigner(
795795
if not build_full:
796796
return None, None, edge_quat
797797
if packed_wigner:
798-
from deepmd.kernels.cute.neo.k4_wignerd import (
798+
from deepmd.pt_expt.kernels.cute.sezm.k4_wignerd import (
799799
run_cute_wignerd,
800800
)
801801

@@ -819,7 +819,7 @@ def _packed_wigner_edges_eligible(
819819
runtime_dtypes: tuple[torch.dtype, ...] = (),
820820
) -> bool:
821821
"""Finish packed eligibility from scalar shape and provenance metadata."""
822-
from deepmd.kernels.cute.neo.k1 import (
822+
from deepmd.pt_expt.kernels.cute.sezm.k1 import (
823823
packed_wigner_edges_eligible,
824824
)
825825

deepmd/pt/model/descriptor/sezm_nn/embedding.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,6 @@
2222
from deepmd.dpmodel.utils.seed import (
2323
child_seed,
2424
)
25-
from deepmd.kernels.cute.neo.k1_wigner_layout import (
26-
PACKED_VALUE_COUNT,
27-
ZONAL_PANEL_OFFSETS,
28-
)
2925
from deepmd.pt.model.network.mlp import (
3026
MLPLayer,
3127
)
@@ -39,6 +35,10 @@
3935
from deepmd.pt.utils.utils import (
4036
get_generator,
4137
)
38+
from deepmd.pt_expt.kernels.cute.sezm.k1_wigner_layout import (
39+
PACKED_VALUE_COUNT,
40+
ZONAL_PANEL_OFFSETS,
41+
)
4242
from deepmd.pt_expt.kernels.utils import (
4343
cuda_infer_level,
4444
)
@@ -305,7 +305,7 @@ def forward(
305305

306306
# === Step 3. Optional fused message construction and reduction ===
307307
if not self.training:
308-
from deepmd.kernels.cute.neo.gie import (
308+
from deepmd.pt_expt.kernels.cute.sezm.gie import (
309309
is_cute_gie_enabled,
310310
maybe_run_cute_gie,
311311
)

deepmd/pt/model/descriptor/sezm_nn/grid_net.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@
3030
from deepmd.dpmodel.utils.seed import (
3131
child_seed,
3232
)
33-
from deepmd.kernels.cute.neo import runtime_policy as cute_runtime_policy
3433
from deepmd.pt.utils import (
3534
env,
3635
)
3736
from deepmd.pt.utils.utils import (
3837
get_generator,
3938
)
39+
from deepmd.pt_expt.kernels.cute.sezm import runtime_policy as cute_runtime_policy
4040
from deepmd.pt_expt.kernels.utils import (
4141
cuda_infer_level,
4242
triton_train_level,
@@ -1062,7 +1062,7 @@ def _pair_grid(
10621062
and cute_runtime_policy.is_cute_infer_enabled()
10631063
and _inference_mode_is_frozen(self)
10641064
):
1065-
from deepmd.kernels.cute.neo.output_grid_product import (
1065+
from deepmd.pt_expt.kernels.cute.sezm.output_grid_product import (
10661066
maybe_run_cute_output_grid_product,
10671067
)
10681068

deepmd/pt/model/descriptor/sezm_nn/lora.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -487,20 +487,20 @@ def _clear_sezm_compile_cache(model: nn.Module) -> None:
487487
crash or silently skip LoRA parameters. Mirrors the pattern used in
488488
:meth:`SeZMModel.reset_head_for_mode`.
489489
"""
490-
from deepmd.kernels.cute.neo.k1 import (
491-
invalidate_cute_k1_state,
492-
)
493490
from deepmd.pt.model.model.sezm_model import (
494491
_clear_shared_sezm_compile_cache,
495492
)
493+
from deepmd.pt_expt.kernels.cute.sezm.k1 import (
494+
invalidate_cute_k1_state,
495+
)
496496

497497
readout_invalidator = None
498498

499499
for m in model.modules():
500500
invalidate_cute_k1_state(m)
501501
if hasattr(m, "_neo_sm80_readout_input_fold_cache"):
502502
if readout_invalidator is None:
503-
from deepmd.kernels.cute.neo.readout_l0 import (
503+
from deepmd.pt_expt.kernels.cute.sezm.readout_l0 import (
504504
invalidate_neo_readout_input_fold,
505505
)
506506

deepmd/pt/model/descriptor/sezm_nn/so2.py

Lines changed: 13 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
cuda_train_enabled,
3838
triton_infer_level,
3939
triton_train_level,
40-
use_cute_infer,
4140
use_cutile_infer,
4241
)
4342
from deepmd.utils.version import (
@@ -1215,31 +1214,27 @@ def __init__(
12151214
self.compute_dtype = get_promoted_dtype(self.dtype)
12161215
# Opt-in fused fast paths, selected by ``DP_TRITON_INFER`` /
12171216
# ``DP_TRITON_TRAIN`` (cumulative levels, see :func:`triton_infer_level`
1218-
# and :func:`triton_train_level`) and ``DP_CUTE_INFER``. Each is read
1217+
# and :func:`triton_train_level`). Each is read
12191218
# once at construction so it becomes a compile-time constant in the
12201219
# traced (``make_fx``) graph. Level 1 replaces the dense ``bmm``
12211220
# rotation with universal Triton kernels; level 2 additionally binds the
12221221
# table-configured fused value path; inference level 3 routes the mixing
12231222
# stack through the fp16x3 tensor-core operator on swept shapes.
1224-
# ``DP_CUTE_INFER`` selects the experimental CuTe value-path operator
1225-
# instead; both gates claim the same ``so2_message`` value path, so
1226-
# enabling them together has no coherent meaning and is rejected at
1227-
# construction. The CuTe, cuTile and hand-written CUDA paths remain
1228-
# inference-only. The fused value-path entries are bound at the end of
1229-
# construction (once every submodule exists) and stay ``None`` when the
1230-
# backend is unavailable or the block layout is unsupported.
1223+
# ``DP_CUTILE_INFER`` selects a complete alternative SO(2) path and is
1224+
# therefore mutually exclusive with Triton. CuTe dispatch is resolved at
1225+
# the enclosing SeZM block, where its exact-shape K1 kernel can coexist
1226+
# with these fallback paths. cuTile and the hand-written CUDA paths remain
1227+
# inference-only. Fused entries stay ``None`` when their backend is
1228+
# unavailable or the block layout is unsupported.
12311229
self.triton_infer_level = triton_infer_level()
12321230
self.triton_train_level = triton_train_level()
12331231
self.use_triton_infer = self.triton_infer_level >= 1
1234-
self.use_cute_infer = use_cute_infer()
12351232
self.use_cutile_infer = use_cutile_infer()
1236-
if sum((self.use_triton_infer, self.use_cute_infer, self.use_cutile_infer)) > 1:
1233+
if self.use_triton_infer and self.use_cutile_infer:
12371234
raise ValueError(
1238-
"DP_TRITON_INFER, DP_CUTE_INFER and DP_CUTILE_INFER are mutually "
1239-
"exclusive: each selects a complete accelerated inference path. "
1240-
"Enable exactly one of them."
1235+
"DP_TRITON_INFER and DP_CUTILE_INFER are mutually exclusive: "
1236+
"each selects a complete accelerated SO(2) inference path."
12411237
)
1242-
self._cute_value_path = None
12431238
self._triton_value_path = None
12441239
self._cutile_value_path = None
12451240

@@ -1753,19 +1748,9 @@ def __init__(
17531748
if SEGMENT_SOFTMAX_TRITON_AVAILABLE:
17541749
self._segment_softmax_fn = segment_softmax
17551750

1756-
# === Step 17. Optional fused CuTe SO(2) value-path operator ===
1757-
# Experimental alternative backend; mutually exclusive with the Triton
1758-
# flag (enforced above).
1759-
if self.use_cute_infer:
1760-
from deepmd.pt_expt.kernels.cute.sezm import (
1761-
make_cute_value_path,
1762-
)
1763-
1764-
self._cute_value_path = make_cute_value_path(self)
1765-
1766-
# === Step 18. Optional fused cuTile SO(2) value-path operators ===
1767-
# Complete cuTile inference path, mutually exclusive with the two gates
1768-
# above. The factory validates the block layout and returns ``None``
1751+
# === Step 17. Optional fused cuTile SO(2) value-path operators ===
1752+
# Complete cuTile inference path, mutually exclusive with Triton. The
1753+
# factory validates the block layout and returns ``None``
17691754
# otherwise, leaving the dense reference path in charge.
17701755
if self.use_cutile_infer:
17711756
from deepmd.pt_expt.kernels.cutile.sezm.so2_value_path import (
@@ -2460,12 +2445,6 @@ def so2_message(
24602445
# inter-layer activations off the traced graph. ===
24612446
cached_edge_csr(edge_cache, "src", x.shape[0])
24622447
x_local, rad_feat = self._triton_value_path(x, edge_cache, radial_feat)
2463-
elif self._cute_value_path is not None and not self.training:
2464-
# === Steps 1-5 (fused CuTe operator). The operator folds
2465-
# rotate_to_local, radial degree mixing, the multi-layer gated SO(2)
2466-
# stack, and the focus competition into the bucketed kernels; the
2467-
# per-edge focus-major intermediates stay resident on chip. ===
2468-
x_local, rad_feat = self._cute_value_path(x, edge_cache, radial_feat)
24692448
elif self._triton_rotate_mix is not None and active_triton_level(self) >= 1:
24702449
# === Steps 1-3 (fused rotate-mix operator). One edge-parallel
24712450
# kernel gathers the source features, applies the block-diagonal

deepmd/pt/model/model/sezm_model.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@
532532

533533
def _neo_cute_infer_enabled() -> bool:
534534
"""Return whether the model builder must destination-sort CuTe edges."""
535-
from deepmd.kernels.cute.neo.runtime_policy import (
535+
from deepmd.pt_expt.kernels.cute.sezm.runtime_policy import (
536536
is_cute_infer_enabled,
537537
)
538538

@@ -548,7 +548,7 @@ def _neo_cute_nlist_eager_island_enabled(device: torch.device) -> bool:
548548
compute_capability = tuple(torch.cuda.get_device_capability(device))
549549
except RuntimeError:
550550
return False
551-
from deepmd.kernels.cute.neo.runtime_policy import (
551+
from deepmd.pt_expt.kernels.cute.sezm.runtime_policy import (
552552
is_k1_eager_island_enabled,
553553
)
554554

@@ -929,7 +929,7 @@ def _invalidate_compiled_state_after_load(
929929
):
930930
continue
931931
if k1_invalidator is None:
932-
from deepmd.kernels.cute.neo.k1 import (
932+
from deepmd.pt_expt.kernels.cute.sezm.k1 import (
933933
invalidate_cute_k1_state,
934934
)
935935

@@ -2156,15 +2156,17 @@ def trace_and_compile(
21562156
# Register Python-owned K1 state before make_fx starts. The opt-in thin
21572157
# path can then keep adjacent linears in this graph while the CuTe work
21582158
# remains opaque behind its existing custom op.
2159-
from deepmd.kernels.cute.neo import runtime_policy as cute_runtime_policy
2159+
from deepmd.pt_expt.kernels.cute.sezm import (
2160+
runtime_policy as cute_runtime_policy,
2161+
)
21602162

21612163
compute_capability = (
21622164
tuple(torch.cuda.get_device_capability(coord.device))
21632165
if coord.device.type == "cuda"
21642166
else None
21652167
)
21662168
if not self.training and cute_runtime_policy.is_cute_infer_enabled():
2167-
from deepmd.kernels.cute.neo.readout_l0 import (
2169+
from deepmd.pt_expt.kernels.cute.sezm.readout_l0 import (
21682170
maybe_prepare_sm80_readout_input_fold,
21692171
)
21702172

@@ -2179,7 +2181,7 @@ def trace_and_compile(
21792181
and cute_runtime_policy.is_cute_infer_enabled()
21802182
and cute_runtime_policy.is_supported_k1_capability(compute_capability)
21812183
):
2182-
from deepmd.kernels.cute.neo.k1 import (
2184+
from deepmd.pt_expt.kernels.cute.sezm.k1 import (
21832185
prepare_cute_k1_blocks,
21842186
)
21852187

0 commit comments

Comments
 (0)