liangsu9988 commited on
Commit
32b700f
·
verified ·
1 Parent(s): ff2f6be

Promote latest kernel artifacts to main

Browse files
CARD.md ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # flashrt/adaptive-layernorm-producers
2
+
3
+ FlashRT native CUDA adaptive LayerNorm producer kernels for DiT, Wan-style
4
+ video diffusion, and VLA/runtime demo pipelines.
5
+
6
+ This package fuses normalization/modulation and low-precision activation
7
+ production before FP8 or NVFP4 GEMM consumers.
8
+
9
+ ## Functions
10
+
11
+ - `ada_layer_norm_quant_fp8_bf16`
12
+ - `ada_layer_norm_quant_fp8_ptok_bf16`
13
+ - `ada_layer_norm_quant_fp8_ptok_table_bf16`
14
+ - `ada_layer_norm_quant_fp8_modfp8_bf16`
15
+ - `awq_ada_layer_norm_quant_fp8_bf16`
16
+ - `ada_layer_norm_quant_nvfp4_swizzled_bf16`
17
+ - `ada_layer_norm_quant_nvfp4_swizzled_modfp8_bf16`
18
+ - `layer_norm_no_affine_quant_fp8_static_bf16`
19
+ - `layer_norm_no_affine_quant_nvfp4_swizzled_bf16`
20
+ - `adaln_modulation6_bf16`
21
+ - `swizzled_sf_size`
22
+
23
+ ## Quick Start
24
+
25
+ ```python
26
+ from kernels import get_kernel
27
+ import torch
28
+
29
+ ops = get_kernel("flashrt/adaptive-layernorm-producers", version=1, trust_remote_code=True)
30
+
31
+ x = torch.randn((2520, 3072), device="cuda", dtype=torch.bfloat16)
32
+ scale = torch.zeros((3072,), device="cuda", dtype=torch.bfloat16)
33
+ shift = torch.zeros((3072,), device="cuda", dtype=torch.bfloat16)
34
+ act_scale = torch.tensor([0.025], device="cuda", dtype=torch.float32)
35
+
36
+ x_fp8 = ops.ada_layer_norm_quant_fp8_bf16(x, scale, shift, act_scale)
37
+ ```
38
+
39
+ Per-token modulation and table-fused modulation are available for video DiT
40
+ and VLA blocks whose shift/scale values vary by token:
41
+
42
+ ```python
43
+ ptok_scale = torch.zeros_like(x)
44
+ ptok_shift = torch.zeros_like(x)
45
+ x_fp8 = ops.ada_layer_norm_quant_fp8_ptok_bf16(
46
+ x, ptok_scale, ptok_shift, act_scale
47
+ )
48
+
49
+ chunks = 6
50
+ temb = torch.zeros((x.shape[0], chunks, x.shape[1]), device="cuda",
51
+ dtype=torch.bfloat16)
52
+ table = torch.zeros((chunks, x.shape[1]), device="cuda",
53
+ dtype=torch.float32)
54
+ x_fp8 = ops.ada_layer_norm_quant_fp8_ptok_table_bf16(
55
+ x, temb, table, act_scale, shift_idx=0, scale_idx=1
56
+ )
57
+ ```
58
+
59
+ The `torch211-cxx11-cu130-aarch64-linux` variant is a native fat binary with
60
+ SM87 (Jetson AGX Orin) and SM110a (Jetson AGX Thor) code objects. The SM110a
61
+ path is runtime-validated on Thor; SM87 runtime validation remains pending on
62
+ Orin hardware. Runtime variant selection is handled by `get_kernel`.
63
+
64
+ Use `README.md` for tensor contracts and `VALIDATION.md` for correctness and
65
+ benchmark status.
README.md CHANGED
@@ -1,9 +1,151 @@
1
- # flashrt/adaptive-layernorm-producers
2
 
3
- This repository is a compatibility mirror for older `kernels` clients
4
- that resolve repositories through the default Hugging Face model repo API.
5
 
6
- Canonical Kernel Hub repo: https://huggingface.co/kernels/flashrt/adaptive-layernorm-producers
7
 
8
- Do not edit this mirror by hand. It is generated from the Kernel Hub
9
- `vN` branches and contains the same `build/**` artifacts.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # adaptive-layernorm-producers
2
 
3
+ FlashRT native CUDA producer kernels for DiT/Wan-style adaptive LayerNorm
4
+ blocks.
5
 
6
+ This package fuses the producer side of the block:
7
 
8
+ ```text
9
+ LayerNorm / adaptive LayerNorm modulation -> low-precision activation
10
+ ```
11
+
12
+ into a single Kernel Hub operator. It is intended for transformer and diffuser
13
+ runtimes where the following GEMM already consumes FP8 or NVFP4 activations.
14
+ Without this fusion, the runtime pays for separate normalization, modulation,
15
+ BF16 materialization, and quantization launches before the GEMM.
16
+
17
+ The source kernels are derived from the production FlashRT runtime:
18
+
19
+ - `official/FlashRT/csrc/quantize/ada_layer_norm_fp8.cu`
20
+ - `official/FlashRT/csrc/kernels/dit_bf16.cu::layer_norm_no_affine_fp8_static_bf16`
21
+
22
+ The full FlashRT model runtime and serving pipeline live upstream at
23
+ [LiangSu8899/FlashRT](https://github.com/LiangSu8899/FlashRT).
24
+
25
+ ## Available Functions
26
+
27
+ - `ada_layer_norm_quant_fp8_bf16(x, scale, shift, act_scale, eps=1e-5, out=None)`
28
+ - `ada_layer_norm_quant_fp8_ptok_bf16(x, scale, shift, act_scale, eps=1e-5, out=None)`
29
+ - `ada_layer_norm_quant_fp8_ptok_table_bf16(x, temb, table, act_scale, shift_idx, scale_idx, eps=1e-5, out=None)`
30
+ - `ada_layer_norm_quant_fp8_modfp8_bf16(x, scale_fp8, shift_fp8, scale_deq, shift_deq, act_scale, eps=1e-5, out=None)`
31
+ - `awq_ada_layer_norm_quant_fp8_bf16(x, scale, shift, inv_s, act_scale, eps=1e-5, out=None)`
32
+ - `ada_layer_norm_quant_nvfp4_swizzled_bf16(x, scale, shift, eps=1e-5, packed=None, sf_swizzled=None)`
33
+ - `ada_layer_norm_quant_nvfp4_swizzled_modfp8_bf16(x, scale_fp8, shift_fp8, scale_deq, shift_deq, eps=1e-5, packed=None, sf_swizzled=None)`
34
+ - `layer_norm_no_affine_quant_fp8_static_bf16(x, act_scale, eps=1e-5, out=None)`
35
+ - `layer_norm_no_affine_quant_nvfp4_swizzled_bf16(x, eps=1e-5, packed=None, sf_swizzled=None)`
36
+ - `adaln_modulation6_bf16(adaln_params, layer_modulation, out=None)`
37
+ - `swizzled_sf_size(rows, dim)`
38
+
39
+ ## Tensor Contract
40
+
41
+ - `x`: contiguous CUDA `torch.bfloat16`, shape `(rows, dim)`.
42
+ - Broadcast `scale`, `shift`, and `inv_s`: contiguous CUDA
43
+ `torch.bfloat16`, shape `(dim,)`.
44
+ - Per-token `scale` and `shift`: contiguous CUDA `torch.bfloat16`, shape
45
+ `(rows, dim)`.
46
+ - Table form `temb`: contiguous CUDA `torch.bfloat16`, shape
47
+ `(rows, chunks, dim)`; `table`: contiguous CUDA `torch.float32`, shape
48
+ `(chunks, dim)`.
49
+ - `scale_fp8`, `shift_fp8`: contiguous CUDA `torch.float8_e4m3fn`, shape `(dim,)`.
50
+ - `scale_deq`, `shift_deq`, `act_scale`: CUDA `torch.float32` scalar tensors.
51
+ - FP8 outputs use `torch.float8_e4m3fn`, shape `(rows, dim)`.
52
+ - NVFP4 packed output uses `torch.uint8`, shape `(rows, dim // 2)`.
53
+ - NVFP4 scale output uses the FlashRT/CUTLASS 128x4 swizzled uint8 scale
54
+ layout. Allocate with `swizzled_sf_size(rows, dim)`.
55
+ - `dim` must be even for FP8 outputs and divisible by 16 for NVFP4 outputs.
56
+ - The package targets CUDA 12.8+ and Blackwell-class deployment paths.
57
+ - `adaln_modulation6_bf16` takes FP32 `(batch, sequence, 6, dim)` parameters
58
+ plus FP32 `(6, dim)` layer modulation and returns six BF16
59
+ `(batch, sequence, dim)` tensors.
60
+
61
+ ## Minimal Usage
62
+
63
+ ```python
64
+ from kernels import get_kernel
65
+ import torch
66
+
67
+ ops = get_kernel("flashrt/adaptive-layernorm-producers", version=1, trust_remote_code=True)
68
+
69
+ rows, dim = 2520, 3072
70
+ x = torch.randn((rows, dim), device="cuda", dtype=torch.bfloat16)
71
+ scale = torch.zeros((dim,), device="cuda", dtype=torch.bfloat16)
72
+ shift = torch.zeros((dim,), device="cuda", dtype=torch.bfloat16)
73
+ act_scale = torch.tensor([0.025], device="cuda", dtype=torch.float32)
74
+
75
+ x_fp8 = ops.ada_layer_norm_quant_fp8_bf16(x, scale, shift, act_scale)
76
+ ```
77
+
78
+ Per-token modulation without materializing a broadcast buffer:
79
+
80
+ ```python
81
+ ptok_scale = torch.zeros_like(x)
82
+ ptok_shift = torch.zeros_like(x)
83
+ x_fp8 = ops.ada_layer_norm_quant_fp8_ptok_bf16(
84
+ x, ptok_scale, ptok_shift, act_scale
85
+ )
86
+ ```
87
+
88
+ Fused host modulation table add and chunk selection:
89
+
90
+ ```python
91
+ chunks = 6
92
+ temb = torch.zeros((rows, chunks, dim), device="cuda", dtype=torch.bfloat16)
93
+ table = torch.zeros((chunks, dim), device="cuda", dtype=torch.float32)
94
+ x_fp8 = ops.ada_layer_norm_quant_fp8_ptok_table_bf16(
95
+ x, temb, table, act_scale, shift_idx=0, scale_idx=1
96
+ )
97
+ ```
98
+
99
+ Static-buffer usage for CUDA Graph capture:
100
+
101
+ ```python
102
+ out = torch.empty_like(x, dtype=torch.float8_e4m3fn)
103
+ ops.ada_layer_norm_quant_fp8_bf16(x, scale, shift, act_scale, out=out)
104
+ ```
105
+
106
+ NVFP4 producer:
107
+
108
+ ```python
109
+ packed, sf = ops.ada_layer_norm_quant_nvfp4_swizzled_bf16(x, scale, shift)
110
+
111
+ # GROOT N1.7 pre-FFN producer on Thor.
112
+ packed_ln, sf_ln = ops.layer_norm_no_affine_quant_nvfp4_swizzled_bf16(x)
113
+ ```
114
+
115
+ Six-way DiT modulation:
116
+
117
+ ```python
118
+ params = torch.randn((1, rows, 6, dim), device="cuda", dtype=torch.float32)
119
+ modulation = torch.randn((6, dim), device="cuda", dtype=torch.float32)
120
+ outputs = ops.adaln_modulation6_bf16(params, modulation)
121
+ ```
122
+
123
+ ## Validation
124
+
125
+ ```bash
126
+ python adaptive-layernorm-producers/tests/test_adaptive_layernorm_producers.py --backend source --mode full
127
+ python adaptive-layernorm-producers/benchmarks/benchmark.py --backend source --iters 100
128
+ ```
129
+
130
+ The validation suite checks exact FP8 output for small producer shapes, exact
131
+ NVFP4 packed/scalefactor output against the native staged BF16-norm plus FP4
132
+ quantizer contract on SM110, and strict FP8
133
+ boundary accounting for long video shapes. The long-shape policy requires
134
+ `p99_abs == 0` and only a tiny count of adjacent FP8-code boundary differences
135
+ against the eager reference.
136
+
137
+ See `VALIDATION.md` and `benchmarks/RESULTS.md` for the current local RTX 5090
138
+ source-build results.
139
+
140
+ The SM110 FP4 producer uses the native GROOT N1.7 contract from FlashRT commit
141
+ `24df793f4fa2d50780aea03b644208c6e0cb4162`. Its scale conversion and FP4 bin
142
+ boundaries intentionally differ from the older SM120 producer; release tests
143
+ compare each architecture against its own production contract.
144
+
145
+ The aarch64 release variant `torch211-cxx11-cu130-aarch64-linux` contains
146
+ native SM87 and SM110a code objects. Its SM110a path was validated on NVIDIA
147
+ Thor from the exact Hub-downloaded artifact over decode, DiT, vision, and
148
+ 2K/4K video rows. The two per-token entry points were also compared directly
149
+ with their raw registered ops using A-B-B-A timing; all six wrapper/raw rows
150
+ were bit-exact and the measured ratio was `0.997-1.000`. SM87 runtime
151
+ validation remains pending on Jetson AGX Orin hardware.
SYNC.md ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Source Sync
2
+
3
+ - Upstream: `flashrt-project/FlashRT`
4
+ - GROOT N1.7 sync commit:
5
+ `24df793f4fa2d50780aea03b644208c6e0cb4162`
6
+ - Copied sources: `csrc/dit_norm_fp4_sfa.cu/.cuh`
7
+
8
+ The package adds `sm110_fp4_dispatch.cu/.cuh` and Tensor-facing bindings around
9
+ the native producer. The SM110 implementation is an independent CUDA 13,
10
+ CUTLASS 4.4 target. Existing SM120 FP8/FP4 paths are unchanged.
11
+
12
+ The SM110 FP4 scale contract is E4M3 round-to-nearest. It must be checked
13
+ against the staged native BF16 norm plus native FP4 quantizer, including exact
14
+ packed values and swizzled scale bytes. Do not reuse the older SM120 ceil-scale
15
+ reference for this target.
16
+
17
+ `tests/native_reference/dit_bf16.cu` is an exact, test-only copy from the same
18
+ FlashRT revision. It keeps source and installed-artifact gates self-contained;
19
+ it is not listed in `build.toml` and is never linked into release artifacts.
benchmarks/README.md ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Benchmarks
2
+
3
+ Run source benchmarks:
4
+
5
+ ```bash
6
+ python adaptive-layernorm-producers/benchmarks/benchmark.py --backend source --iters 100
7
+ ```
8
+
9
+ Run installed-artifact benchmarks after Hub packaging:
10
+
11
+ ```bash
12
+ python adaptive-layernorm-producers/benchmarks/benchmark.py --backend installed --iters 100
13
+ ```
14
+
15
+ `RESULTS.md` records the current local source-build numbers. Public benchmark
16
+ claims should be refreshed after installed-artifact testing on the target
17
+ hardware.
benchmarks/native_binding.cpp ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ #include <torch/extension.h>
3
+ #include <ATen/cuda/CUDAContext.h>
4
+
5
+ #include "adaln_modulation6.cuh"
6
+
7
+ void adaln_modulation6(
8
+ uintptr_t params, uintptr_t modulation, uintptr_t out0, uintptr_t out1,
9
+ uintptr_t out2, uintptr_t out3, uintptr_t out4, uintptr_t out5,
10
+ int batch, int sequence, int dim) {
11
+ flash_rt::adaln_producers::adaln_modulation6_bf16(
12
+ reinterpret_cast<const float*>(params),
13
+ reinterpret_cast<const float*>(modulation),
14
+ reinterpret_cast<void*>(out0), reinterpret_cast<void*>(out1),
15
+ reinterpret_cast<void*>(out2), reinterpret_cast<void*>(out3),
16
+ reinterpret_cast<void*>(out4), reinterpret_cast<void*>(out5),
17
+ batch, sequence, dim, at::cuda::getCurrentCUDAStream().stream());
18
+ }
19
+
20
+ PYBIND11_MODULE(TORCH_EXTENSION_NAME, module) {
21
+ module.def("adaln_modulation6", &adaln_modulation6);
22
+ }
build.toml ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [general]
2
+ name = "adaptive-layernorm-producers"
3
+ license = "Apache-2.0"
4
+ version = 1
5
+ backends = ["cuda"]
6
+
7
+ [general.cuda]
8
+ minver = "12.8"
9
+
10
+ [general.hub]
11
+ repo-id = "flashrt/adaptive-layernorm-producers"
12
+
13
+ [torch]
14
+ include = ["csrc"]
15
+ src = [
16
+ "torch-ext/torch_binding.cpp",
17
+ ]
18
+
19
+ [kernel.adaptive_layernorm_producers]
20
+ backend = "cuda"
21
+ depends = ["torch"]
22
+ include = ["csrc"]
23
+ cuda-minver = "12.8"
24
+ src = [
25
+ "csrc/ada_layer_norm_fp8.cu",
26
+ "csrc/ada_layer_norm_fp8_ptok.cu",
27
+ "csrc/ada_layer_norm_fp8.cuh",
28
+ "csrc/dit_layer_norm_fp8.cu",
29
+ "csrc/dit_layer_norm_fp8.cuh",
30
+ "csrc/adaln_modulation6.cu",
31
+ "csrc/adaln_modulation6.cuh",
32
+ ]
33
+
34
+ [kernel.adaptive_layernorm_producers_sm110_fp4]
35
+ backend = "cuda"
36
+ depends = ["torch", "cutlass_4_4"]
37
+ include = ["csrc"]
38
+ cuda-minver = "13"
39
+ cuda-capabilities = ["11.0a"]
40
+ cuda-flags = [
41
+ "-O3",
42
+ "--use_fast_math",
43
+ "-DCUTLASS_ARCH_MMA_SM100_SUPPORTED=1",
44
+ ]
45
+ src = [
46
+ "csrc/dit_norm_fp4_sfa.cu",
47
+ "csrc/dit_norm_fp4_sfa.cuh",
48
+ "csrc/sm110_fp4_dispatch.cu",
49
+ "csrc/sm110_fp4_dispatch.cuh",
50
+ ]
build/torch211-cxx11-cu130-aarch64-linux/__init__.py CHANGED
@@ -198,6 +198,22 @@ def _layer_norm_no_affine_quant_fp8_static_bf16_fake(
198
  return None
199
 
200
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
  def ada_layer_norm_quant_fp8_bf16(
202
  x: torch.Tensor,
203
  scale: torch.Tensor,
@@ -353,6 +369,21 @@ def layer_norm_no_affine_quant_fp8_static_bf16(
353
  return out
354
 
355
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
356
  @torch.library.register_fake(add_op_namespace_prefix("adaln_modulation6_bf16"))
357
  def _adaln_modulation6_bf16_fake(
358
  adaln_params: torch.Tensor,
@@ -418,6 +449,7 @@ __all__ = [
418
  "ada_layer_norm_quant_nvfp4_swizzled_bf16",
419
  "ada_layer_norm_quant_nvfp4_swizzled_modfp8_bf16",
420
  "layer_norm_no_affine_quant_fp8_static_bf16",
 
421
  "adaln_modulation6_bf16",
422
  "swizzled_sf_size",
423
  ]
 
198
  return None
199
 
200
 
201
+ @torch.library.register_fake(add_op_namespace_prefix("layer_norm_no_affine_quant_nvfp4_swizzled_bf16"))
202
+ def _layer_norm_no_affine_quant_nvfp4_swizzled_bf16_fake(
203
+ x: torch.Tensor,
204
+ eps: float,
205
+ packed: torch.Tensor,
206
+ sf_swizzled: torch.Tensor,
207
+ ) -> None:
208
+ _check_x(x)
209
+ rows, dim = x.shape
210
+ if packed.shape != (rows, dim // 2):
211
+ raise RuntimeError("packed must have shape (rows, dim // 2)")
212
+ if sf_swizzled.numel() < swizzled_sf_size(rows, dim):
213
+ raise RuntimeError("sf_swizzled is too small")
214
+ return None
215
+
216
+
217
  def ada_layer_norm_quant_fp8_bf16(
218
  x: torch.Tensor,
219
  scale: torch.Tensor,
 
369
  return out
370
 
371
 
372
+ def layer_norm_no_affine_quant_nvfp4_swizzled_bf16(
373
+ x: torch.Tensor,
374
+ eps: float = 1e-5,
375
+ packed: torch.Tensor | None = None,
376
+ sf_swizzled: torch.Tensor | None = None,
377
+ ) -> tuple[torch.Tensor, torch.Tensor]:
378
+ """SM110 no-affine LayerNorm producing NVFP4 and CUTLASS SFA."""
379
+ if packed is None or sf_swizzled is None:
380
+ packed, sf_swizzled = _alloc_nvfp4(x)
381
+ ops.layer_norm_no_affine_quant_nvfp4_swizzled_bf16(
382
+ x, float(eps), packed, sf_swizzled
383
+ )
384
+ return packed, sf_swizzled
385
+
386
+
387
  @torch.library.register_fake(add_op_namespace_prefix("adaln_modulation6_bf16"))
388
  def _adaln_modulation6_bf16_fake(
389
  adaln_params: torch.Tensor,
 
449
  "ada_layer_norm_quant_nvfp4_swizzled_bf16",
450
  "ada_layer_norm_quant_nvfp4_swizzled_modfp8_bf16",
451
  "layer_norm_no_affine_quant_fp8_static_bf16",
452
+ "layer_norm_no_affine_quant_nvfp4_swizzled_bf16",
453
  "adaln_modulation6_bf16",
454
  "swizzled_sf_size",
455
  ]
build/torch211-cxx11-cu130-aarch64-linux/{_adaptive_layernorm_producers_cuda_7781728.abi3.so → _adaptive_layernorm_producers_cuda_8a66d8b.abi3.so} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:2b5542ae448332ebd4d1f2ca2f0030f88200061f8d2e64eb8581c314e7d7322c
3
- size 592256
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b7a2db2e007dbc80da262c206891058c7db8c1c7f249b92ad6185c1ce11b814f
3
+ size 535776
build/torch211-cxx11-cu130-aarch64-linux/_ops.py CHANGED
@@ -1,6 +1,6 @@
1
  import torch
2
- from . import _adaptive_layernorm_producers_cuda_7781728
3
- ops = torch.ops._adaptive_layernorm_producers_cuda_7781728
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
- return f"_adaptive_layernorm_producers_cuda_7781728::{op_name}"
 
1
  import torch
2
+ from . import _adaptive_layernorm_producers_cuda_8a66d8b
3
+ ops = torch.ops._adaptive_layernorm_producers_cuda_8a66d8b
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
+ return f"_adaptive_layernorm_producers_cuda_8a66d8b::{op_name}"
build/torch211-cxx11-cu130-aarch64-linux/metadata.json CHANGED
@@ -1,33 +1,28 @@
1
  {
2
  "name": "adaptive-layernorm-producers",
3
- "id": "_adaptive_layernorm_producers_cuda_7781728",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
7
  "backend": {
8
  "type": "cuda",
9
  "archs": [
10
- "8.7",
11
  "11.0a"
12
  ]
13
  },
14
  "digest": {
15
  "algorithm": "sha256",
16
  "files": {
17
- "__init__.py": "Y0RRm5MDP9m0wKQRpuGRFg0YewrbqdZnVIBItbh7DAc=",
18
- "_adaptive_layernorm_producers_cuda_7781728.abi3.so": "K1VCrkSDMuvU0fLKLwAw+IIABh+NLmTrhYHDFOfXMiw=",
19
- "_ops.py": "kG1EL+EuLDtXPuUtyj/ygYLPUZg6eszWjMCBtbLC0pw=",
20
  "adaptive_layernorm_producers/__init__.py": "v6p5XMfQzddhi1fLSAw4HX9CyS0rQsidvu9VsT01xi4="
21
  }
22
  },
23
  "provenance": {
24
  "kernel": {
25
- "sha": "9b532b42ad71d0ef6bc79d1372e96910087faad4",
26
  "dirty": false
27
- },
28
- "validation": {
29
- "torch": "2.11.0+cu130",
30
- "cuda": "13.0"
31
  }
32
  }
33
  }
 
1
  {
2
  "name": "adaptive-layernorm-producers",
3
+ "id": "_adaptive_layernorm_producers_cuda_8a66d8b",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
7
  "backend": {
8
  "type": "cuda",
9
  "archs": [
 
10
  "11.0a"
11
  ]
12
  },
13
  "digest": {
14
  "algorithm": "sha256",
15
  "files": {
16
+ "__init__.py": "/6Ld6WSyL7PjILcYt4P7x3fnXi2C+ovbSP/7nNFetb8=",
17
+ "_adaptive_layernorm_producers_cuda_8a66d8b.abi3.so": "t6LbLgB9vIDaJiwgaJEFjH24wcfySbkq1hhcHOEbgU8=",
18
+ "_ops.py": "8CjL8CxdQouAOnaox+O0AKwLERGSDc8mao+V3ArMuTk=",
19
  "adaptive_layernorm_producers/__init__.py": "v6p5XMfQzddhi1fLSAw4HX9CyS0rQsidvu9VsT01xi4="
20
  }
21
  },
22
  "provenance": {
23
  "kernel": {
24
+ "sha": "8a66d8b",
25
  "dirty": false
 
 
 
 
26
  }
27
  }
28
  }
csrc/ada_layer_norm_fp8.cu ADDED
@@ -0,0 +1,666 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // G7.17 — Fused AdaLayerNorm + per-tensor FP8 quantize. See header.
3
+ // Math mirrors csrc/kernels/dit_bf16.cu::ada_layer_norm_bf16 with the
4
+ // final store path replaced by fp8 e4m3 quantize+pack.
5
+
6
+ #include "ada_layer_norm_fp8.cuh"
7
+
8
+ #include <cstdint>
9
+ #include <cuda_bf16.h>
10
+ #include <cuda_fp8.h>
11
+ #include <cuda_runtime.h>
12
+
13
+ namespace flash_rt {
14
+ namespace quantize {
15
+
16
+ namespace {
17
+
18
+ constexpr float kFp8Max = 448.0f;
19
+
20
+ __device__ __forceinline__ uint8_t f32_to_fp4_e2m1(float x) {
21
+ if (x == 0.0f) return 0;
22
+ uint8_t sign = x < 0 ? 0x8 : 0;
23
+ float ax = fabsf(x);
24
+ if (ax < 0.25f) return sign;
25
+ if (ax < 0.75f) return sign | 0x1; // 0.5
26
+ if (ax < 1.5f) return sign | 0x2; // 1
27
+ if (ax < 3.0f) return sign | 0x3; // 2
28
+ if (ax < 5.0f) return sign | 0x6; // 4
29
+ return sign | 0x7; // 6
30
+ }
31
+
32
+ __device__ __forceinline__ uint8_t f32_to_ue4m3_ceil_local(float x) {
33
+ if (x <= 0.0f) return 0;
34
+ if (x < 0.0009765625f) return 1;
35
+ int exp;
36
+ float mant = frexpf(x, &exp);
37
+ exp -= 1;
38
+ float frac = mant * 2.0f - 1.0f;
39
+ int mantissa = (int)ceilf(frac * 8.0f);
40
+ if (mantissa >= 8) {
41
+ mantissa = 0;
42
+ exp += 1;
43
+ }
44
+ int biased_exp = exp + 7;
45
+ if (biased_exp <= 0) return 1;
46
+ if (biased_exp >= 15) return 0x7F;
47
+ return (uint8_t)((biased_exp << 3) | mantissa);
48
+ }
49
+
50
+ __device__ __forceinline__ float ue4m3_to_f32_local(uint8_t v) {
51
+ if (v == 0) return 0.0f;
52
+ int exp = ((v >> 3) & 0xF) - 7;
53
+ int mant = v & 0x7;
54
+ float m = 1.0f + mant / 8.0f;
55
+ return ldexpf(m, exp);
56
+ }
57
+
58
+ __global__ void ada_layer_norm_fp8_kernel(
59
+ const __nv_bfloat16* __restrict__ x,
60
+ const __nv_bfloat16* __restrict__ scale,
61
+ const __nv_bfloat16* __restrict__ shift,
62
+ __nv_fp8_e4m3* __restrict__ out,
63
+ const float* __restrict__ act_scale_ptr,
64
+ int dim, float eps)
65
+ {
66
+ const int row = blockIdx.x;
67
+ const __nv_bfloat162* x2 =
68
+ reinterpret_cast<const __nv_bfloat162*>(x + (long long)row * dim);
69
+ const __nv_bfloat162* sc2 =
70
+ reinterpret_cast<const __nv_bfloat162*>(scale);
71
+ const __nv_bfloat162* sh2 =
72
+ reinterpret_cast<const __nv_bfloat162*>(shift);
73
+ __nv_fp8_e4m3* out_row = out + (long long)row * dim;
74
+ const int dim2 = dim >> 1;
75
+
76
+ extern __shared__ float shared[];
77
+
78
+ // ── Pass 1: mean ──
79
+ float local_sum = 0.f;
80
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
81
+ __nv_bfloat162 v = x2[i];
82
+ local_sum += __bfloat162float(v.x) + __bfloat162float(v.y);
83
+ }
84
+ float val = local_sum;
85
+ for (int o = 16; o > 0; o >>= 1)
86
+ val += __shfl_xor_sync(0xffffffffu, val, o);
87
+ const int lane = threadIdx.x & 31;
88
+ const int wid = threadIdx.x >> 5;
89
+ if (!lane) shared[wid] = val;
90
+ __syncthreads();
91
+ if (!wid) {
92
+ val = (lane < (blockDim.x >> 5)) ? shared[lane] : 0.f;
93
+ for (int o = 16; o > 0; o >>= 1)
94
+ val += __shfl_xor_sync(0xffffffffu, val, o);
95
+ }
96
+ __syncthreads();
97
+ if (!threadIdx.x) shared[0] = val;
98
+ __syncthreads();
99
+ const float mean = shared[0] / static_cast<float>(dim);
100
+
101
+ // ── Pass 2: variance ──
102
+ float local_var = 0.f;
103
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
104
+ __nv_bfloat162 v = x2[i];
105
+ const float d0 = __bfloat162float(v.x) - mean;
106
+ const float d1 = __bfloat162float(v.y) - mean;
107
+ local_var += d0 * d0 + d1 * d1;
108
+ }
109
+ val = local_var;
110
+ for (int o = 16; o > 0; o >>= 1)
111
+ val += __shfl_xor_sync(0xffffffffu, val, o);
112
+ if (!lane) shared[wid] = val;
113
+ __syncthreads();
114
+ if (!wid) {
115
+ val = (lane < (blockDim.x >> 5)) ? shared[lane] : 0.f;
116
+ for (int o = 16; o > 0; o >>= 1)
117
+ val += __shfl_xor_sync(0xffffffffu, val, o);
118
+ }
119
+ __syncthreads();
120
+ if (!threadIdx.x) shared[0] = val;
121
+ __syncthreads();
122
+ const float inv_std = rsqrtf(shared[0] / static_cast<float>(dim) + eps);
123
+
124
+ // ── Pass 3: ada_modulate + fp8 quantize ──
125
+ // Register-level round-through bf16 BEFORE fp8 conversion to match
126
+ // the reference (ada_layer_norm_bf16 → bf16 store → quantize_fp8)
127
+ // bit-exactly while skipping the actual bf16 global-memory round-trip.
128
+ // This is the precision/memory tradeoff sweet spot: zero memory cost
129
+ // for the bf16 intermediate, exact cos match with the 2-launch chain.
130
+ const float inv_a = 1.0f / *act_scale_ptr;
131
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
132
+ __nv_bfloat162 xv = x2[i], sv = sc2[i], hv = sh2[i];
133
+ const float n0 = (__bfloat162float(xv.x) - mean) * inv_std;
134
+ const float n1 = (__bfloat162float(xv.y) - mean) * inv_std;
135
+ const float v0_f32 = n0 * (1.0f + __bfloat162float(sv.x))
136
+ + __bfloat162float(hv.x);
137
+ const float v1_f32 = n1 * (1.0f + __bfloat162float(sv.y))
138
+ + __bfloat162float(hv.y);
139
+ // Round through bf16 in registers (no memory write).
140
+ const float v0 = __bfloat162float(__float2bfloat16(v0_f32));
141
+ const float v1 = __bfloat162float(__float2bfloat16(v1_f32));
142
+ float q0 = fminf(fmaxf(v0 * inv_a, -kFp8Max), kFp8Max);
143
+ float q1 = fminf(fmaxf(v1 * inv_a, -kFp8Max), kFp8Max);
144
+ out_row[2 * i] = __nv_fp8_e4m3(q0);
145
+ out_row[2 * i + 1] = __nv_fp8_e4m3(q1);
146
+ }
147
+ }
148
+
149
+ __global__ void awq_ada_layer_norm_fp8_kernel(
150
+ const __nv_bfloat16* __restrict__ x,
151
+ const __nv_bfloat16* __restrict__ scale,
152
+ const __nv_bfloat16* __restrict__ shift,
153
+ const __nv_bfloat16* __restrict__ inv_s,
154
+ __nv_fp8_e4m3* __restrict__ out,
155
+ const float* __restrict__ act_scale_ptr,
156
+ int dim, float eps)
157
+ {
158
+ const int row = blockIdx.x;
159
+ const __nv_bfloat162* x2 =
160
+ reinterpret_cast<const __nv_bfloat162*>(x + (long long)row * dim);
161
+ const __nv_bfloat162* sc2 =
162
+ reinterpret_cast<const __nv_bfloat162*>(scale);
163
+ const __nv_bfloat162* sh2 =
164
+ reinterpret_cast<const __nv_bfloat162*>(shift);
165
+ const __nv_bfloat162* inv2 =
166
+ reinterpret_cast<const __nv_bfloat162*>(inv_s);
167
+ __nv_fp8_e4m3* out_row = out + (long long)row * dim;
168
+ const int dim2 = dim >> 1;
169
+
170
+ extern __shared__ float shared[];
171
+
172
+ float local_sum = 0.f;
173
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
174
+ __nv_bfloat162 v = x2[i];
175
+ local_sum += __bfloat162float(v.x) + __bfloat162float(v.y);
176
+ }
177
+ float val = local_sum;
178
+ for (int o = 16; o > 0; o >>= 1)
179
+ val += __shfl_xor_sync(0xffffffffu, val, o);
180
+ const int lane = threadIdx.x & 31;
181
+ const int wid = threadIdx.x >> 5;
182
+ if (!lane) shared[wid] = val;
183
+ __syncthreads();
184
+ if (!wid) {
185
+ val = (lane < (blockDim.x >> 5)) ? shared[lane] : 0.f;
186
+ for (int o = 16; o > 0; o >>= 1)
187
+ val += __shfl_xor_sync(0xffffffffu, val, o);
188
+ }
189
+ __syncthreads();
190
+ if (!threadIdx.x) shared[0] = val;
191
+ __syncthreads();
192
+ const float mean = shared[0] / static_cast<float>(dim);
193
+
194
+ float local_var = 0.f;
195
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
196
+ __nv_bfloat162 v = x2[i];
197
+ const float d0 = __bfloat162float(v.x) - mean;
198
+ const float d1 = __bfloat162float(v.y) - mean;
199
+ local_var += d0 * d0 + d1 * d1;
200
+ }
201
+ val = local_var;
202
+ for (int o = 16; o > 0; o >>= 1)
203
+ val += __shfl_xor_sync(0xffffffffu, val, o);
204
+ if (!lane) shared[wid] = val;
205
+ __syncthreads();
206
+ if (!wid) {
207
+ val = (lane < (blockDim.x >> 5)) ? shared[lane] : 0.f;
208
+ for (int o = 16; o > 0; o >>= 1)
209
+ val += __shfl_xor_sync(0xffffffffu, val, o);
210
+ }
211
+ __syncthreads();
212
+ if (!threadIdx.x) shared[0] = val;
213
+ __syncthreads();
214
+ const float inv_std = rsqrtf(shared[0] / static_cast<float>(dim) + eps);
215
+
216
+ const float inv_a = 1.0f / *act_scale_ptr;
217
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
218
+ __nv_bfloat162 xv = x2[i], sv = sc2[i], hv = sh2[i], iv = inv2[i];
219
+ const float n0 = (__bfloat162float(xv.x) - mean) * inv_std;
220
+ const float n1 = (__bfloat162float(xv.y) - mean) * inv_std;
221
+ const float v0 = __bfloat162float(__float2bfloat16(
222
+ n0 * (1.0f + __bfloat162float(sv.x)) + __bfloat162float(hv.x)));
223
+ const float v1 = __bfloat162float(__float2bfloat16(
224
+ n1 * (1.0f + __bfloat162float(sv.y)) + __bfloat162float(hv.y)));
225
+ float q0 = fminf(fmaxf(v0 * __bfloat162float(iv.x) * inv_a,
226
+ -kFp8Max), kFp8Max);
227
+ float q1 = fminf(fmaxf(v1 * __bfloat162float(iv.y) * inv_a,
228
+ -kFp8Max), kFp8Max);
229
+ out_row[2 * i] = __nv_fp8_e4m3(q0);
230
+ out_row[2 * i + 1] = __nv_fp8_e4m3(q1);
231
+ }
232
+ }
233
+
234
+ __global__ void ada_layer_norm_fp8_modfp8_kernel(
235
+ const __nv_bfloat16* __restrict__ x,
236
+ const __nv_fp8_e4m3* __restrict__ scale,
237
+ const __nv_fp8_e4m3* __restrict__ shift,
238
+ const float* __restrict__ scale_deq,
239
+ const float* __restrict__ shift_deq,
240
+ __nv_fp8_e4m3* __restrict__ out,
241
+ const float* __restrict__ act_scale_ptr,
242
+ int dim, float eps)
243
+ {
244
+ const int row = blockIdx.x;
245
+ const __nv_bfloat162* x2 =
246
+ reinterpret_cast<const __nv_bfloat162*>(x + (long long)row * dim);
247
+ __nv_fp8_e4m3* out_row = out + (long long)row * dim;
248
+ const int dim2 = dim >> 1;
249
+
250
+ extern __shared__ float shared[];
251
+ float local_sum = 0.f;
252
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
253
+ __nv_bfloat162 v = x2[i];
254
+ local_sum += __bfloat162float(v.x) + __bfloat162float(v.y);
255
+ }
256
+ float val = local_sum;
257
+ for (int o = 16; o > 0; o >>= 1)
258
+ val += __shfl_xor_sync(0xffffffffu, val, o);
259
+ const int lane = threadIdx.x & 31;
260
+ const int wid = threadIdx.x >> 5;
261
+ if (!lane) shared[wid] = val;
262
+ __syncthreads();
263
+ if (!wid) {
264
+ val = (lane < (blockDim.x >> 5)) ? shared[lane] : 0.f;
265
+ for (int o = 16; o > 0; o >>= 1)
266
+ val += __shfl_xor_sync(0xffffffffu, val, o);
267
+ }
268
+ __syncthreads();
269
+ if (!threadIdx.x) shared[0] = val;
270
+ __syncthreads();
271
+ const float mean = shared[0] / static_cast<float>(dim);
272
+
273
+ float local_var = 0.f;
274
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
275
+ __nv_bfloat162 v = x2[i];
276
+ const float d0 = __bfloat162float(v.x) - mean;
277
+ const float d1 = __bfloat162float(v.y) - mean;
278
+ local_var += d0 * d0 + d1 * d1;
279
+ }
280
+ val = local_var;
281
+ for (int o = 16; o > 0; o >>= 1)
282
+ val += __shfl_xor_sync(0xffffffffu, val, o);
283
+ if (!lane) shared[wid] = val;
284
+ __syncthreads();
285
+ if (!wid) {
286
+ val = (lane < (blockDim.x >> 5)) ? shared[lane] : 0.f;
287
+ for (int o = 16; o > 0; o >>= 1)
288
+ val += __shfl_xor_sync(0xffffffffu, val, o);
289
+ }
290
+ __syncthreads();
291
+ if (!threadIdx.x) shared[0] = val;
292
+ __syncthreads();
293
+ const float inv_std = rsqrtf(shared[0] / static_cast<float>(dim) + eps);
294
+
295
+ const float s_deq = *scale_deq;
296
+ const float h_deq = *shift_deq;
297
+ const float inv_a = 1.0f / *act_scale_ptr;
298
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
299
+ __nv_bfloat162 xv = x2[i];
300
+ const int j = i << 1;
301
+ const float s0 = static_cast<float>(scale[j]) * s_deq;
302
+ const float s1 = static_cast<float>(scale[j + 1]) * s_deq;
303
+ const float h0 = static_cast<float>(shift[j]) * h_deq;
304
+ const float h1 = static_cast<float>(shift[j + 1]) * h_deq;
305
+ const float n0 = (__bfloat162float(xv.x) - mean) * inv_std;
306
+ const float n1 = (__bfloat162float(xv.y) - mean) * inv_std;
307
+ const float v0 = __bfloat162float(__float2bfloat16(n0 * (1.0f + s0) + h0));
308
+ const float v1 = __bfloat162float(__float2bfloat16(n1 * (1.0f + s1) + h1));
309
+ out_row[j] = __nv_fp8_e4m3(fminf(fmaxf(v0 * inv_a, -kFp8Max), kFp8Max));
310
+ out_row[j + 1] = __nv_fp8_e4m3(fminf(fmaxf(v1 * inv_a, -kFp8Max), kFp8Max));
311
+ }
312
+ }
313
+
314
+ __global__ void ada_layer_norm_nvfp4_swizzled_kernel(
315
+ const __nv_bfloat16* __restrict__ x,
316
+ const __nv_bfloat16* __restrict__ scale,
317
+ const __nv_bfloat16* __restrict__ shift,
318
+ uint8_t* __restrict__ packed,
319
+ uint8_t* __restrict__ sf_swizzled,
320
+ int dim, int num_blocks, int n_col_blocks, float eps)
321
+ {
322
+ const int row = blockIdx.x;
323
+ const __nv_bfloat162* x2 =
324
+ reinterpret_cast<const __nv_bfloat162*>(x + (long long)row * dim);
325
+ const __nv_bfloat162* sc2 =
326
+ reinterpret_cast<const __nv_bfloat162*>(scale);
327
+ const __nv_bfloat162* sh2 =
328
+ reinterpret_cast<const __nv_bfloat162*>(shift);
329
+ uint8_t* row_packed = packed + (long long)row * dim / 2;
330
+ const int dim2 = dim >> 1;
331
+
332
+ extern __shared__ float shared[];
333
+ float* red = shared;
334
+ float* blk_scale = shared + 256;
335
+
336
+ float local_sum = 0.f;
337
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
338
+ __nv_bfloat162 v = x2[i];
339
+ local_sum += __bfloat162float(v.x) + __bfloat162float(v.y);
340
+ }
341
+ float val = local_sum;
342
+ for (int o = 16; o > 0; o >>= 1)
343
+ val += __shfl_xor_sync(0xffffffffu, val, o);
344
+ const int lane = threadIdx.x & 31;
345
+ const int wid = threadIdx.x >> 5;
346
+ if (!lane) red[wid] = val;
347
+ __syncthreads();
348
+ if (!wid) {
349
+ val = (lane < (blockDim.x >> 5)) ? red[lane] : 0.f;
350
+ for (int o = 16; o > 0; o >>= 1)
351
+ val += __shfl_xor_sync(0xffffffffu, val, o);
352
+ }
353
+ __syncthreads();
354
+ if (!threadIdx.x) red[0] = val;
355
+ __syncthreads();
356
+ const float mean = red[0] / static_cast<float>(dim);
357
+
358
+ float local_var = 0.f;
359
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
360
+ __nv_bfloat162 v = x2[i];
361
+ const float d0 = __bfloat162float(v.x) - mean;
362
+ const float d1 = __bfloat162float(v.y) - mean;
363
+ local_var += d0 * d0 + d1 * d1;
364
+ }
365
+ val = local_var;
366
+ for (int o = 16; o > 0; o >>= 1)
367
+ val += __shfl_xor_sync(0xffffffffu, val, o);
368
+ if (!lane) red[wid] = val;
369
+ __syncthreads();
370
+ if (!wid) {
371
+ val = (lane < (blockDim.x >> 5)) ? red[lane] : 0.f;
372
+ for (int o = 16; o > 0; o >>= 1)
373
+ val += __shfl_xor_sync(0xffffffffu, val, o);
374
+ }
375
+ __syncthreads();
376
+ if (!threadIdx.x) red[0] = val;
377
+ __syncthreads();
378
+ const float inv_std = rsqrtf(red[0] / static_cast<float>(dim) + eps);
379
+
380
+ for (int b = threadIdx.x; b < num_blocks; b += blockDim.x)
381
+ blk_scale[b] = 0.0f;
382
+ __syncthreads();
383
+
384
+ for (int i2 = threadIdx.x; i2 < dim2; i2 += blockDim.x) {
385
+ __nv_bfloat162 xv = x2[i2], sv = sc2[i2], hv = sh2[i2];
386
+ const int i = i2 << 1;
387
+ const float n0 = (__bfloat162float(xv.x) - mean) * inv_std;
388
+ const float n1 = (__bfloat162float(xv.y) - mean) * inv_std;
389
+ const float v0 = __bfloat162float(__float2bfloat16(
390
+ n0 * (1.0f + __bfloat162float(sv.x)) + __bfloat162float(hv.x)));
391
+ const float v1 = __bfloat162float(__float2bfloat16(
392
+ n1 * (1.0f + __bfloat162float(sv.y)) + __bfloat162float(hv.y)));
393
+ atomicMax((int*)&blk_scale[i >> 4], __float_as_int(fabsf(v0)));
394
+ atomicMax((int*)&blk_scale[(i + 1) >> 4], __float_as_int(fabsf(v1)));
395
+ }
396
+ __syncthreads();
397
+
398
+ const int rb = row / 128;
399
+ const int ri = row % 128;
400
+ for (int b = threadIdx.x; b < num_blocks; b += blockDim.x) {
401
+ float amax = __int_as_float(*(int*)&blk_scale[b]);
402
+ uint8_t ue = f32_to_ue4m3_ceil_local(amax / 6.0f);
403
+ int cb = b / 4;
404
+ int ci = b % 4;
405
+ int out_idx = (rb * n_col_blocks + cb) * 512
406
+ + (ri % 32) * 16 + (ri / 32) * 4 + ci;
407
+ sf_swizzled[out_idx] = ue;
408
+ blk_scale[b] = ue4m3_to_f32_local(ue);
409
+ }
410
+ __syncthreads();
411
+
412
+ for (int p = threadIdx.x; p < dim / 2; p += blockDim.x) {
413
+ const int i = p << 1;
414
+ const int i2 = p;
415
+ __nv_bfloat162 xv = x2[i2], sv = sc2[i2], hv = sh2[i2];
416
+ const float n0 = (__bfloat162float(xv.x) - mean) * inv_std;
417
+ const float n1 = (__bfloat162float(xv.y) - mean) * inv_std;
418
+ const float m0 = __bfloat162float(__float2bfloat16(
419
+ n0 * (1.0f + __bfloat162float(sv.x)) + __bfloat162float(hv.x)));
420
+ const float m1 = __bfloat162float(__float2bfloat16(
421
+ n1 * (1.0f + __bfloat162float(sv.y)) + __bfloat162float(hv.y)));
422
+ const int b0 = i >> 4;
423
+ const int b1 = (i + 1) >> 4;
424
+ const float inv0 = blk_scale[b0] > 0.0f ? 1.0f / blk_scale[b0] : 0.0f;
425
+ const float inv1 = blk_scale[b1] > 0.0f ? 1.0f / blk_scale[b1] : 0.0f;
426
+ uint8_t lo = f32_to_fp4_e2m1(m0 * inv0);
427
+ uint8_t hi = f32_to_fp4_e2m1(m1 * inv1);
428
+ row_packed[p] = (hi << 4) | (lo & 0x0F);
429
+ }
430
+ }
431
+
432
+ __global__ void ada_layer_norm_nvfp4_swizzled_modfp8_kernel(
433
+ const __nv_bfloat16* __restrict__ x,
434
+ const __nv_fp8_e4m3* __restrict__ scale,
435
+ const __nv_fp8_e4m3* __restrict__ shift,
436
+ const float* __restrict__ scale_deq,
437
+ const float* __restrict__ shift_deq,
438
+ uint8_t* __restrict__ packed,
439
+ uint8_t* __restrict__ sf_swizzled,
440
+ int dim, int num_blocks, int n_col_blocks, float eps)
441
+ {
442
+ const int row = blockIdx.x;
443
+ const __nv_bfloat162* x2 =
444
+ reinterpret_cast<const __nv_bfloat162*>(x + (long long)row * dim);
445
+ uint8_t* row_packed = packed + (long long)row * dim / 2;
446
+ const int dim2 = dim >> 1;
447
+
448
+ extern __shared__ float shared[];
449
+ float* red = shared;
450
+ float* blk_scale = shared + 256;
451
+
452
+ float local_sum = 0.f;
453
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
454
+ __nv_bfloat162 v = x2[i];
455
+ local_sum += __bfloat162float(v.x) + __bfloat162float(v.y);
456
+ }
457
+ float val = local_sum;
458
+ for (int o = 16; o > 0; o >>= 1)
459
+ val += __shfl_xor_sync(0xffffffffu, val, o);
460
+ const int lane = threadIdx.x & 31;
461
+ const int wid = threadIdx.x >> 5;
462
+ if (!lane) red[wid] = val;
463
+ __syncthreads();
464
+ if (!wid) {
465
+ val = (lane < (blockDim.x >> 5)) ? red[lane] : 0.f;
466
+ for (int o = 16; o > 0; o >>= 1)
467
+ val += __shfl_xor_sync(0xffffffffu, val, o);
468
+ }
469
+ __syncthreads();
470
+ if (!threadIdx.x) red[0] = val;
471
+ __syncthreads();
472
+ const float mean = red[0] / static_cast<float>(dim);
473
+
474
+ float local_var = 0.f;
475
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
476
+ __nv_bfloat162 v = x2[i];
477
+ const float d0 = __bfloat162float(v.x) - mean;
478
+ const float d1 = __bfloat162float(v.y) - mean;
479
+ local_var += d0 * d0 + d1 * d1;
480
+ }
481
+ val = local_var;
482
+ for (int o = 16; o > 0; o >>= 1)
483
+ val += __shfl_xor_sync(0xffffffffu, val, o);
484
+ if (!lane) red[wid] = val;
485
+ __syncthreads();
486
+ if (!wid) {
487
+ val = (lane < (blockDim.x >> 5)) ? red[lane] : 0.f;
488
+ for (int o = 16; o > 0; o >>= 1)
489
+ val += __shfl_xor_sync(0xffffffffu, val, o);
490
+ }
491
+ __syncthreads();
492
+ if (!threadIdx.x) red[0] = val;
493
+ __syncthreads();
494
+ const float inv_std = rsqrtf(red[0] / static_cast<float>(dim) + eps);
495
+
496
+ for (int b = threadIdx.x; b < num_blocks; b += blockDim.x)
497
+ blk_scale[b] = 0.0f;
498
+ __syncthreads();
499
+
500
+ const float s_deq = *scale_deq;
501
+ const float h_deq = *shift_deq;
502
+ for (int i2 = threadIdx.x; i2 < dim2; i2 += blockDim.x) {
503
+ __nv_bfloat162 xv = x2[i2];
504
+ const int i = i2 << 1;
505
+ const float s0 = static_cast<float>(scale[i]) * s_deq;
506
+ const float s1 = static_cast<float>(scale[i + 1]) * s_deq;
507
+ const float h0 = static_cast<float>(shift[i]) * h_deq;
508
+ const float h1 = static_cast<float>(shift[i + 1]) * h_deq;
509
+ const float n0 = (__bfloat162float(xv.x) - mean) * inv_std;
510
+ const float n1 = (__bfloat162float(xv.y) - mean) * inv_std;
511
+ const float v0 = __bfloat162float(__float2bfloat16(n0 * (1.0f + s0) + h0));
512
+ const float v1 = __bfloat162float(__float2bfloat16(n1 * (1.0f + s1) + h1));
513
+ atomicMax((int*)&blk_scale[i >> 4], __float_as_int(fabsf(v0)));
514
+ atomicMax((int*)&blk_scale[(i + 1) >> 4], __float_as_int(fabsf(v1)));
515
+ }
516
+ __syncthreads();
517
+
518
+ const int rb = row / 128;
519
+ const int ri = row % 128;
520
+ for (int b = threadIdx.x; b < num_blocks; b += blockDim.x) {
521
+ float amax = __int_as_float(*(int*)&blk_scale[b]);
522
+ uint8_t ue = f32_to_ue4m3_ceil_local(amax / 6.0f);
523
+ int cb = b / 4;
524
+ int ci = b % 4;
525
+ int out_idx = (rb * n_col_blocks + cb) * 512
526
+ + (ri % 32) * 16 + (ri / 32) * 4 + ci;
527
+ sf_swizzled[out_idx] = ue;
528
+ blk_scale[b] = ue4m3_to_f32_local(ue);
529
+ }
530
+ __syncthreads();
531
+
532
+ for (int p = threadIdx.x; p < dim / 2; p += blockDim.x) {
533
+ const int i = p << 1;
534
+ __nv_bfloat162 xv = x2[p];
535
+ const float s0 = static_cast<float>(scale[i]) * s_deq;
536
+ const float s1 = static_cast<float>(scale[i + 1]) * s_deq;
537
+ const float h0 = static_cast<float>(shift[i]) * h_deq;
538
+ const float h1 = static_cast<float>(shift[i + 1]) * h_deq;
539
+ const float n0 = (__bfloat162float(xv.x) - mean) * inv_std;
540
+ const float n1 = (__bfloat162float(xv.y) - mean) * inv_std;
541
+ const float m0 = __bfloat162float(__float2bfloat16(n0 * (1.0f + s0) + h0));
542
+ const float m1 = __bfloat162float(__float2bfloat16(n1 * (1.0f + s1) + h1));
543
+ const int b0 = i >> 4;
544
+ const int b1 = (i + 1) >> 4;
545
+ const float inv0 = blk_scale[b0] > 0.0f ? 1.0f / blk_scale[b0] : 0.0f;
546
+ const float inv1 = blk_scale[b1] > 0.0f ? 1.0f / blk_scale[b1] : 0.0f;
547
+ uint8_t lo = f32_to_fp4_e2m1(m0 * inv0);
548
+ uint8_t hi = f32_to_fp4_e2m1(m1 * inv1);
549
+ row_packed[p] = (hi << 4) | (lo & 0x0F);
550
+ }
551
+ }
552
+
553
+ } // namespace
554
+
555
+ void ada_layer_norm_fp8(
556
+ const void* x_bf16,
557
+ const void* scale_bf16,
558
+ const void* shift_bf16,
559
+ void* out_fp8,
560
+ const float* act_scale,
561
+ int seq_len, int dim, float eps,
562
+ cudaStream_t stream)
563
+ {
564
+ if (seq_len <= 0 || dim <= 0) return;
565
+ // dim must be even for bf162 vectorization (always true for our shapes).
566
+ ada_layer_norm_fp8_kernel<<<seq_len, 256, 256 * sizeof(float), stream>>>(
567
+ reinterpret_cast<const __nv_bfloat16*>(x_bf16),
568
+ reinterpret_cast<const __nv_bfloat16*>(scale_bf16),
569
+ reinterpret_cast<const __nv_bfloat16*>(shift_bf16),
570
+ reinterpret_cast<__nv_fp8_e4m3*>(out_fp8),
571
+ act_scale,
572
+ dim, eps);
573
+ }
574
+
575
+ void ada_layer_norm_fp8_modfp8(
576
+ const void* x_bf16,
577
+ const void* scale_fp8,
578
+ const void* shift_fp8,
579
+ const float* scale_deq,
580
+ const float* shift_deq,
581
+ void* out_fp8,
582
+ const float* act_scale,
583
+ int seq_len, int dim, float eps,
584
+ cudaStream_t stream)
585
+ {
586
+ if (seq_len <= 0 || dim <= 0) return;
587
+ ada_layer_norm_fp8_modfp8_kernel<<<seq_len, 256, 256 * sizeof(float), stream>>>(
588
+ reinterpret_cast<const __nv_bfloat16*>(x_bf16),
589
+ reinterpret_cast<const __nv_fp8_e4m3*>(scale_fp8),
590
+ reinterpret_cast<const __nv_fp8_e4m3*>(shift_fp8),
591
+ scale_deq, shift_deq,
592
+ reinterpret_cast<__nv_fp8_e4m3*>(out_fp8),
593
+ act_scale,
594
+ dim, eps);
595
+ }
596
+
597
+ void awq_ada_layer_norm_fp8(
598
+ const void* x_bf16,
599
+ const void* scale_bf16,
600
+ const void* shift_bf16,
601
+ const void* inv_s_bf16,
602
+ void* out_fp8,
603
+ const float* act_scale,
604
+ int seq_len, int dim, float eps,
605
+ cudaStream_t stream)
606
+ {
607
+ if (seq_len <= 0 || dim <= 0) return;
608
+ awq_ada_layer_norm_fp8_kernel
609
+ <<<seq_len, 256, 256 * sizeof(float), stream>>>(
610
+ reinterpret_cast<const __nv_bfloat16*>(x_bf16),
611
+ reinterpret_cast<const __nv_bfloat16*>(scale_bf16),
612
+ reinterpret_cast<const __nv_bfloat16*>(shift_bf16),
613
+ reinterpret_cast<const __nv_bfloat16*>(inv_s_bf16),
614
+ reinterpret_cast<__nv_fp8_e4m3*>(out_fp8),
615
+ act_scale, dim, eps);
616
+ }
617
+
618
+ void ada_layer_norm_nvfp4_swizzled(
619
+ const void* x_bf16,
620
+ const void* scale_bf16,
621
+ const void* shift_bf16,
622
+ void* packed_u8,
623
+ void* sf_swizzled_u8,
624
+ int seq_len, int dim, float eps,
625
+ cudaStream_t stream)
626
+ {
627
+ if (seq_len <= 0 || dim <= 0) return;
628
+ const int num_blocks = (dim + 15) / 16;
629
+ const int n_col_blocks = (num_blocks + 3) / 4;
630
+ const int smem = (256 + num_blocks) * sizeof(float);
631
+ ada_layer_norm_nvfp4_swizzled_kernel<<<seq_len, 256, smem, stream>>>(
632
+ reinterpret_cast<const __nv_bfloat16*>(x_bf16),
633
+ reinterpret_cast<const __nv_bfloat16*>(scale_bf16),
634
+ reinterpret_cast<const __nv_bfloat16*>(shift_bf16),
635
+ reinterpret_cast<uint8_t*>(packed_u8),
636
+ reinterpret_cast<uint8_t*>(sf_swizzled_u8),
637
+ dim, num_blocks, n_col_blocks, eps);
638
+ }
639
+
640
+ void ada_layer_norm_nvfp4_swizzled_modfp8(
641
+ const void* x_bf16,
642
+ const void* scale_fp8,
643
+ const void* shift_fp8,
644
+ const float* scale_deq,
645
+ const float* shift_deq,
646
+ void* packed_u8,
647
+ void* sf_swizzled_u8,
648
+ int seq_len, int dim, float eps,
649
+ cudaStream_t stream)
650
+ {
651
+ if (seq_len <= 0 || dim <= 0) return;
652
+ const int num_blocks = (dim + 15) / 16;
653
+ const int n_col_blocks = (num_blocks + 3) / 4;
654
+ const int smem = (256 + num_blocks) * sizeof(float);
655
+ ada_layer_norm_nvfp4_swizzled_modfp8_kernel<<<seq_len, 256, smem, stream>>>(
656
+ reinterpret_cast<const __nv_bfloat16*>(x_bf16),
657
+ reinterpret_cast<const __nv_fp8_e4m3*>(scale_fp8),
658
+ reinterpret_cast<const __nv_fp8_e4m3*>(shift_fp8),
659
+ scale_deq, shift_deq,
660
+ reinterpret_cast<uint8_t*>(packed_u8),
661
+ reinterpret_cast<uint8_t*>(sf_swizzled_u8),
662
+ dim, num_blocks, n_col_blocks, eps);
663
+ }
664
+
665
+ } // namespace quantize
666
+ } // namespace flash_rt
csrc/ada_layer_norm_fp8.cuh ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ //
3
+ // G7.17 — Fused AdaLayerNorm + per-tensor FP8 e4m3 quantize.
4
+ //
5
+ // Replaces the motus 2-launch chain
6
+ // ada_layer_norm_bf16(x, scale, shift) -> bf16 modulated
7
+ // quantize_fp8_static(modulated) -> fp8
8
+ // with a single kernel. Eliminates the bf16 (B*L, D) intermediate
9
+ // (~15 MB at T=2520 D=3072 for Wan video), which is the dominant
10
+ // cost — memory traffic round-trip dwarfs launch overhead.
11
+ //
12
+ // Math (per row, given mean μ and variance σ² of x):
13
+ // norm[i] = (x[i] - μ) / sqrt(σ² + eps)
14
+ // mod[i] = norm[i] * (1 + scale[i]) + shift[i]
15
+ // out[i] = clamp(mod[i] / *act_scale, ±448).to(fp8_e4m3)
16
+ //
17
+ // Layout: x, scale, shift are (B*L, D) bf16 row-major (or scale/shift
18
+ // broadcast over rows when their leading dim == 1). out is (B*L, D)
19
+ // fp8_e4m3 row-major. act_scale is a device fp32 scalar.
20
+
21
+ #pragma once
22
+
23
+ #include <cuda_runtime.h>
24
+
25
+ namespace flash_rt {
26
+ namespace quantize {
27
+
28
+ void ada_layer_norm_fp8(
29
+ const void* x_bf16,
30
+ const void* scale_bf16,
31
+ const void* shift_bf16,
32
+ void* out_fp8,
33
+ const float* act_scale,
34
+ int seq_len, int dim, float eps,
35
+ cudaStream_t stream);
36
+
37
+ void ada_layer_norm_fp8_modfp8(
38
+ const void* x_bf16,
39
+ const void* scale_fp8,
40
+ const void* shift_fp8,
41
+ const float* scale_deq,
42
+ const float* shift_deq,
43
+ void* out_fp8,
44
+ const float* act_scale,
45
+ int seq_len, int dim, float eps,
46
+ cudaStream_t stream);
47
+
48
+ void awq_ada_layer_norm_fp8(
49
+ const void* x_bf16,
50
+ const void* scale_bf16,
51
+ const void* shift_bf16,
52
+ const void* inv_s_bf16,
53
+ void* out_fp8,
54
+ const float* act_scale,
55
+ int seq_len, int dim, float eps,
56
+ cudaStream_t stream);
57
+
58
+ void ada_layer_norm_nvfp4_swizzled(
59
+ const void* x_bf16,
60
+ const void* scale_bf16,
61
+ const void* shift_bf16,
62
+ void* packed_u8,
63
+ void* sf_swizzled_u8,
64
+ int seq_len, int dim, float eps,
65
+ cudaStream_t stream);
66
+
67
+ void ada_layer_norm_nvfp4_swizzled_modfp8(
68
+ const void* x_bf16,
69
+ const void* scale_fp8,
70
+ const void* shift_fp8,
71
+ const float* scale_deq,
72
+ const float* shift_deq,
73
+ void* packed_u8,
74
+ void* sf_swizzled_u8,
75
+ int seq_len, int dim, float eps,
76
+ cudaStream_t stream);
77
+
78
+ // Per-token modulation form: scale/shift are [seq_len, dim], one row per
79
+ // activation row (video-DiT per-token timestep tables).
80
+ void ada_layer_norm_ptok_fp8(
81
+ const void* x_bf16,
82
+ const void* scale_bf16,
83
+ const void* shift_bf16,
84
+ void* out_fp8,
85
+ const float* act_scale,
86
+ int seq_len, int dim, float eps,
87
+ cudaStream_t stream);
88
+
89
+ // Table form: the block's [n_chunks, dim] modulation table is added to
90
+ // the per-token embedding [seq_len, n_chunks, dim] inside the kernel —
91
+ // the host-side per-block chunk materialization disappears.
92
+ void ada_layer_norm_ptok_table_fp8(
93
+ const void* x_bf16,
94
+ const void* temb_bf16,
95
+ const float* table_f32,
96
+ void* out_fp8,
97
+ const float* act_scale,
98
+ int seq_len, int dim, int n_chunks, int shift_idx, int scale_idx,
99
+ float eps, cudaStream_t stream);
100
+
101
+ } // namespace quantize
102
+ } // namespace flash_rt
csrc/ada_layer_norm_fp8_ptok.cu ADDED
@@ -0,0 +1,254 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Per-token AdaLayerNorm + per-tensor FP8 quantize.
3
+ //
4
+ // Same math as ada_layer_norm_fp8.cu::ada_layer_norm_fp8_kernel with one
5
+ // difference: the modulation vectors are per token ([M, D], one row per
6
+ // activation row) instead of broadcast per channel ([D]). This is the
7
+ // producer form modern video DiTs need — their timestep embedding carries
8
+ // a scale/shift *per token* (e.g. a [B, S, 6, D] table chunked per site),
9
+ // so a [D] broadcast producer cannot serve the seam at all.
10
+
11
+ #include "ada_layer_norm_fp8.cuh"
12
+
13
+ #include <cstdint>
14
+ #include <cuda_bf16.h>
15
+ #include <cuda_fp8.h>
16
+ #include <cuda_runtime.h>
17
+
18
+ namespace flash_rt {
19
+ namespace quantize {
20
+
21
+ namespace {
22
+
23
+ constexpr float kFp8MaxPtok = 448.0f;
24
+
25
+ __global__ void ada_layer_norm_ptok_fp8_kernel(
26
+ const __nv_bfloat16* __restrict__ x,
27
+ const __nv_bfloat16* __restrict__ scale,
28
+ const __nv_bfloat16* __restrict__ shift,
29
+ __nv_fp8_e4m3* __restrict__ out,
30
+ const float* __restrict__ act_scale_ptr,
31
+ int dim, float eps)
32
+ {
33
+ const int row = blockIdx.x;
34
+ const __nv_bfloat162* x2 =
35
+ reinterpret_cast<const __nv_bfloat162*>(x + (long long)row * dim);
36
+ const __nv_bfloat162* sc2 =
37
+ reinterpret_cast<const __nv_bfloat162*>(scale + (long long)row * dim);
38
+ const __nv_bfloat162* sh2 =
39
+ reinterpret_cast<const __nv_bfloat162*>(shift + (long long)row * dim);
40
+ __nv_fp8_e4m3* out_row = out + (long long)row * dim;
41
+ const int dim2 = dim >> 1;
42
+
43
+ extern __shared__ float shared[];
44
+
45
+ // ── Pass 1: mean ──
46
+ float local_sum = 0.f;
47
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
48
+ __nv_bfloat162 v = x2[i];
49
+ local_sum += __bfloat162float(v.x) + __bfloat162float(v.y);
50
+ }
51
+ float val = local_sum;
52
+ for (int o = 16; o > 0; o >>= 1)
53
+ val += __shfl_xor_sync(0xffffffffu, val, o);
54
+ const int lane = threadIdx.x & 31;
55
+ const int wid = threadIdx.x >> 5;
56
+ if (!lane) shared[wid] = val;
57
+ __syncthreads();
58
+ if (!wid) {
59
+ val = (lane < (blockDim.x >> 5)) ? shared[lane] : 0.f;
60
+ for (int o = 16; o > 0; o >>= 1)
61
+ val += __shfl_xor_sync(0xffffffffu, val, o);
62
+ }
63
+ __syncthreads();
64
+ if (!threadIdx.x) shared[0] = val;
65
+ __syncthreads();
66
+ const float mean = shared[0] / static_cast<float>(dim);
67
+
68
+ // ── Pass 2: variance ──
69
+ float local_var = 0.f;
70
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
71
+ __nv_bfloat162 v = x2[i];
72
+ const float d0 = __bfloat162float(v.x) - mean;
73
+ const float d1 = __bfloat162float(v.y) - mean;
74
+ local_var += d0 * d0 + d1 * d1;
75
+ }
76
+ val = local_var;
77
+ for (int o = 16; o > 0; o >>= 1)
78
+ val += __shfl_xor_sync(0xffffffffu, val, o);
79
+ if (!lane) shared[wid] = val;
80
+ __syncthreads();
81
+ if (!wid) {
82
+ val = (lane < (blockDim.x >> 5)) ? shared[lane] : 0.f;
83
+ for (int o = 16; o > 0; o >>= 1)
84
+ val += __shfl_xor_sync(0xffffffffu, val, o);
85
+ }
86
+ __syncthreads();
87
+ if (!threadIdx.x) shared[0] = val;
88
+ __syncthreads();
89
+ const float inv_std = rsqrtf(shared[0] / static_cast<float>(dim) + eps);
90
+
91
+ // ── Pass 3: per-token ada_modulate + fp8 quantize ──
92
+ // Register-level round-through bf16 before fp8, matching the family's
93
+ // reference chain semantics (see ada_layer_norm_fp8.cu).
94
+ const float inv_a = 1.0f / *act_scale_ptr;
95
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
96
+ __nv_bfloat162 xv = x2[i], sv = sc2[i], hv = sh2[i];
97
+ const float n0 = (__bfloat162float(xv.x) - mean) * inv_std;
98
+ const float n1 = (__bfloat162float(xv.y) - mean) * inv_std;
99
+ const float v0_f32 = n0 * (1.0f + __bfloat162float(sv.x))
100
+ + __bfloat162float(hv.x);
101
+ const float v1_f32 = n1 * (1.0f + __bfloat162float(sv.y))
102
+ + __bfloat162float(hv.y);
103
+ const float v0 = __bfloat162float(__float2bfloat16(v0_f32));
104
+ const float v1 = __bfloat162float(__float2bfloat16(v1_f32));
105
+ float q0 = fminf(fmaxf(v0 * inv_a, -kFp8MaxPtok), kFp8MaxPtok);
106
+ float q1 = fminf(fmaxf(v1 * inv_a, -kFp8MaxPtok), kFp8MaxPtok);
107
+ out_row[2 * i] = __nv_fp8_e4m3(q0);
108
+ out_row[2 * i + 1] = __nv_fp8_e4m3(q1);
109
+ }
110
+ }
111
+
112
+ } // namespace
113
+
114
+ void ada_layer_norm_ptok_fp8(
115
+ const void* x_bf16,
116
+ const void* scale_bf16,
117
+ const void* shift_bf16,
118
+ void* out_fp8,
119
+ const float* act_scale,
120
+ int seq_len, int dim, float eps,
121
+ cudaStream_t stream)
122
+ {
123
+ if (seq_len <= 0 || dim <= 0) return;
124
+ ada_layer_norm_ptok_fp8_kernel<<<seq_len, 256, 256 * sizeof(float),
125
+ stream>>>(
126
+ reinterpret_cast<const __nv_bfloat16*>(x_bf16),
127
+ reinterpret_cast<const __nv_bfloat16*>(scale_bf16),
128
+ reinterpret_cast<const __nv_bfloat16*>(shift_bf16),
129
+ reinterpret_cast<__nv_fp8_e4m3*>(out_fp8),
130
+ act_scale,
131
+ dim, eps);
132
+ }
133
+
134
+ } // namespace quantize
135
+ } // namespace flash_rt
136
+
137
+ namespace flash_rt {
138
+ namespace quantize {
139
+
140
+ namespace {
141
+
142
+ __global__ void ada_layer_norm_ptok_table_fp8_kernel(
143
+ const __nv_bfloat16* __restrict__ x,
144
+ const __nv_bfloat16* __restrict__ temb, // [M, n_chunks, D]
145
+ const float* __restrict__ table, // [n_chunks, D]
146
+ __nv_fp8_e4m3* __restrict__ out,
147
+ const float* __restrict__ act_scale_ptr,
148
+ int dim, int n_chunks, int shift_idx, int scale_idx, float eps)
149
+ {
150
+ const int row = blockIdx.x;
151
+ const __nv_bfloat162* x2 =
152
+ reinterpret_cast<const __nv_bfloat162*>(x + (long long)row * dim);
153
+ const __nv_bfloat162* sc2 = reinterpret_cast<const __nv_bfloat162*>(
154
+ temb + ((long long)row * n_chunks + scale_idx) * dim);
155
+ const __nv_bfloat162* sh2 = reinterpret_cast<const __nv_bfloat162*>(
156
+ temb + ((long long)row * n_chunks + shift_idx) * dim);
157
+ const float2* tsc2 = reinterpret_cast<const float2*>(
158
+ table + (long long)scale_idx * dim);
159
+ const float2* tsh2 = reinterpret_cast<const float2*>(
160
+ table + (long long)shift_idx * dim);
161
+ __nv_fp8_e4m3* out_row = out + (long long)row * dim;
162
+ const int dim2 = dim >> 1;
163
+
164
+ extern __shared__ float shared[];
165
+
166
+ float local_sum = 0.f;
167
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
168
+ __nv_bfloat162 v = x2[i];
169
+ local_sum += __bfloat162float(v.x) + __bfloat162float(v.y);
170
+ }
171
+ float val = local_sum;
172
+ for (int o = 16; o > 0; o >>= 1)
173
+ val += __shfl_xor_sync(0xffffffffu, val, o);
174
+ const int lane = threadIdx.x & 31;
175
+ const int wid = threadIdx.x >> 5;
176
+ if (!lane) shared[wid] = val;
177
+ __syncthreads();
178
+ if (!wid) {
179
+ val = (lane < (blockDim.x >> 5)) ? shared[lane] : 0.f;
180
+ for (int o = 16; o > 0; o >>= 1)
181
+ val += __shfl_xor_sync(0xffffffffu, val, o);
182
+ }
183
+ __syncthreads();
184
+ if (!threadIdx.x) shared[0] = val;
185
+ __syncthreads();
186
+ const float mean = shared[0] / static_cast<float>(dim);
187
+
188
+ float local_var = 0.f;
189
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
190
+ __nv_bfloat162 v = x2[i];
191
+ const float d0 = __bfloat162float(v.x) - mean;
192
+ const float d1 = __bfloat162float(v.y) - mean;
193
+ local_var += d0 * d0 + d1 * d1;
194
+ }
195
+ val = local_var;
196
+ for (int o = 16; o > 0; o >>= 1)
197
+ val += __shfl_xor_sync(0xffffffffu, val, o);
198
+ if (!lane) shared[wid] = val;
199
+ __syncthreads();
200
+ if (!wid) {
201
+ val = (lane < (blockDim.x >> 5)) ? shared[lane] : 0.f;
202
+ for (int o = 16; o > 0; o >>= 1)
203
+ val += __shfl_xor_sync(0xffffffffu, val, o);
204
+ }
205
+ __syncthreads();
206
+ if (!threadIdx.x) shared[0] = val;
207
+ __syncthreads();
208
+ const float inv_std = rsqrtf(shared[0] / static_cast<float>(dim) + eps);
209
+
210
+ const float inv_a = 1.0f / *act_scale_ptr;
211
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
212
+ __nv_bfloat162 xv = x2[i], sv = sc2[i], hv = sh2[i];
213
+ const float2 ts = tsc2[i], th = tsh2[i];
214
+ const float s0 = ts.x + __bfloat162float(sv.x);
215
+ const float s1 = ts.y + __bfloat162float(sv.y);
216
+ const float h0 = th.x + __bfloat162float(hv.x);
217
+ const float h1 = th.y + __bfloat162float(hv.y);
218
+ const float n0 = (__bfloat162float(xv.x) - mean) * inv_std;
219
+ const float n1 = (__bfloat162float(xv.y) - mean) * inv_std;
220
+ const float v0 = __bfloat162float(
221
+ __float2bfloat16(n0 * (1.0f + s0) + h0));
222
+ const float v1 = __bfloat162float(
223
+ __float2bfloat16(n1 * (1.0f + s1) + h1));
224
+ float q0 = fminf(fmaxf(v0 * inv_a, -kFp8MaxPtok), kFp8MaxPtok);
225
+ float q1 = fminf(fmaxf(v1 * inv_a, -kFp8MaxPtok), kFp8MaxPtok);
226
+ out_row[2 * i] = __nv_fp8_e4m3(q0);
227
+ out_row[2 * i + 1] = __nv_fp8_e4m3(q1);
228
+ }
229
+ }
230
+
231
+ } // namespace
232
+
233
+ void ada_layer_norm_ptok_table_fp8(
234
+ const void* x_bf16,
235
+ const void* temb_bf16,
236
+ const float* table_f32,
237
+ void* out_fp8,
238
+ const float* act_scale,
239
+ int seq_len, int dim, int n_chunks, int shift_idx, int scale_idx,
240
+ float eps, cudaStream_t stream)
241
+ {
242
+ if (seq_len <= 0 || dim <= 0) return;
243
+ ada_layer_norm_ptok_table_fp8_kernel<<<seq_len, 256,
244
+ 256 * sizeof(float), stream>>>(
245
+ reinterpret_cast<const __nv_bfloat16*>(x_bf16),
246
+ reinterpret_cast<const __nv_bfloat16*>(temb_bf16),
247
+ table_f32,
248
+ reinterpret_cast<__nv_fp8_e4m3*>(out_fp8),
249
+ act_scale,
250
+ dim, n_chunks, shift_idx, scale_idx, eps);
251
+ }
252
+
253
+ } // namespace quantize
254
+ } // namespace flash_rt
csrc/adaln_modulation6.cu ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // SPDX-License-Identifier: Apache-2.0
2
+
3
+ #include "adaln_modulation6.cuh"
4
+
5
+ #include <cuda_bf16.h>
6
+
7
+ namespace flash_rt {
8
+ namespace adaln_producers {
9
+ namespace {
10
+
11
+ __global__ void adaln_modulation6_bf16_kernel(
12
+ const float* __restrict__ adaln_params,
13
+ const float* __restrict__ layer_modulation,
14
+ __nv_bfloat16* __restrict__ out0,
15
+ __nv_bfloat16* __restrict__ out1,
16
+ __nv_bfloat16* __restrict__ out2,
17
+ __nv_bfloat16* __restrict__ out3,
18
+ __nv_bfloat16* __restrict__ out4,
19
+ __nv_bfloat16* __restrict__ out5,
20
+ int dim,
21
+ long long elements) {
22
+ const long long index =
23
+ static_cast<long long>(blockIdx.x) * blockDim.x + threadIdx.x;
24
+ if (index >= elements) {
25
+ return;
26
+ }
27
+ const int d = static_cast<int>(index % dim);
28
+ const long long base = (index / dim) * 6LL * dim + d;
29
+ out0[index] = __float2bfloat16(
30
+ adaln_params[base] + layer_modulation[d]);
31
+ out1[index] = __float2bfloat16(
32
+ adaln_params[base + dim] + layer_modulation[dim + d]);
33
+ out2[index] = __float2bfloat16(
34
+ adaln_params[base + 2LL * dim] + layer_modulation[2LL * dim + d]);
35
+ out3[index] = __float2bfloat16(
36
+ adaln_params[base + 3LL * dim] + layer_modulation[3LL * dim + d]);
37
+ out4[index] = __float2bfloat16(
38
+ adaln_params[base + 4LL * dim] + layer_modulation[4LL * dim + d]);
39
+ out5[index] = __float2bfloat16(
40
+ adaln_params[base + 5LL * dim] + layer_modulation[5LL * dim + d]);
41
+ }
42
+
43
+ } // namespace
44
+
45
+ void adaln_modulation6_bf16(
46
+ const float* adaln_params,
47
+ const float* layer_modulation,
48
+ void* out0,
49
+ void* out1,
50
+ void* out2,
51
+ void* out3,
52
+ void* out4,
53
+ void* out5,
54
+ int batch,
55
+ int sequence,
56
+ int dim,
57
+ cudaStream_t stream) {
58
+ const long long elements =
59
+ static_cast<long long>(batch) * sequence * dim;
60
+ constexpr int threads = 256;
61
+ const unsigned blocks =
62
+ static_cast<unsigned>((elements + threads - 1) / threads);
63
+ adaln_modulation6_bf16_kernel<<<blocks, threads, 0, stream>>>(
64
+ adaln_params,
65
+ layer_modulation,
66
+ static_cast<__nv_bfloat16*>(out0),
67
+ static_cast<__nv_bfloat16*>(out1),
68
+ static_cast<__nv_bfloat16*>(out2),
69
+ static_cast<__nv_bfloat16*>(out3),
70
+ static_cast<__nv_bfloat16*>(out4),
71
+ static_cast<__nv_bfloat16*>(out5),
72
+ dim,
73
+ elements);
74
+ }
75
+
76
+ } // namespace adaln_producers
77
+ } // namespace flash_rt
csrc/adaln_modulation6.cuh ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // SPDX-License-Identifier: Apache-2.0
2
+
3
+ #pragma once
4
+
5
+ #include <cuda_runtime.h>
6
+
7
+ namespace flash_rt {
8
+ namespace adaln_producers {
9
+
10
+ void adaln_modulation6_bf16(
11
+ const float* adaln_params,
12
+ const float* layer_modulation,
13
+ void* out0,
14
+ void* out1,
15
+ void* out2,
16
+ void* out3,
17
+ void* out4,
18
+ void* out5,
19
+ int batch,
20
+ int sequence,
21
+ int dim,
22
+ cudaStream_t stream);
23
+
24
+ } // namespace adaln_producers
25
+ } // namespace flash_rt
csrc/dit_layer_norm_fp8.cu ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ //
3
+ // BF16 no-affine LayerNorm -> static FP8 producer.
4
+ // Ported from FlashRT csrc/kernels/dit_bf16.cu for Hub Tensor APIs.
5
+
6
+ #include "dit_layer_norm_fp8.cuh"
7
+
8
+ #include <cuda_bf16.h>
9
+ #include <cuda_fp8.h>
10
+ #include <cuda_runtime.h>
11
+ #include <cstdint>
12
+
13
+ namespace flash_rt {
14
+ namespace adaln_producers {
15
+ namespace {
16
+
17
+ __global__ void layer_norm_no_affine_fp8_static_bf16_kernel(
18
+ const __nv_bfloat16* __restrict__ x,
19
+ __nv_fp8_e4m3* __restrict__ out,
20
+ const float* __restrict__ d_scale,
21
+ int dim,
22
+ float eps) {
23
+ const int row = blockIdx.x;
24
+ const __nv_bfloat162* x2 =
25
+ reinterpret_cast<const __nv_bfloat162*>(x + static_cast<long long>(row) * dim);
26
+ __nv_fp8_e4m3* out_row = out + static_cast<long long>(row) * dim;
27
+ const int dim2 = dim >> 1;
28
+
29
+ extern __shared__ float shared[];
30
+ float local_sum = 0.0f;
31
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
32
+ const __nv_bfloat162 v = x2[i];
33
+ local_sum += __bfloat162float(v.x) + __bfloat162float(v.y);
34
+ }
35
+ float value = local_sum;
36
+ for (int offset = 16; offset > 0; offset >>= 1) {
37
+ value += __shfl_xor_sync(0xffffffffu, value, offset);
38
+ }
39
+ const int lane = threadIdx.x & 31;
40
+ const int wid = threadIdx.x >> 5;
41
+ if (lane == 0) {
42
+ shared[wid] = value;
43
+ }
44
+ __syncthreads();
45
+ if (wid == 0) {
46
+ value = (lane < (blockDim.x >> 5)) ? shared[lane] : 0.0f;
47
+ for (int offset = 16; offset > 0; offset >>= 1) {
48
+ value += __shfl_xor_sync(0xffffffffu, value, offset);
49
+ }
50
+ }
51
+ __syncthreads();
52
+ if (threadIdx.x == 0) {
53
+ shared[0] = value;
54
+ }
55
+ __syncthreads();
56
+ const float mean = shared[0] / static_cast<float>(dim);
57
+
58
+ float local_var = 0.0f;
59
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
60
+ const __nv_bfloat162 v = x2[i];
61
+ const float d0 = __bfloat162float(v.x) - mean;
62
+ const float d1 = __bfloat162float(v.y) - mean;
63
+ local_var += d0 * d0 + d1 * d1;
64
+ }
65
+ value = local_var;
66
+ for (int offset = 16; offset > 0; offset >>= 1) {
67
+ value += __shfl_xor_sync(0xffffffffu, value, offset);
68
+ }
69
+ if (lane == 0) {
70
+ shared[wid] = value;
71
+ }
72
+ __syncthreads();
73
+ if (wid == 0) {
74
+ value = (lane < (blockDim.x >> 5)) ? shared[lane] : 0.0f;
75
+ for (int offset = 16; offset > 0; offset >>= 1) {
76
+ value += __shfl_xor_sync(0xffffffffu, value, offset);
77
+ }
78
+ }
79
+ __syncthreads();
80
+ if (threadIdx.x == 0) {
81
+ shared[0] = value;
82
+ }
83
+ __syncthreads();
84
+ const float inv_std = rsqrtf(shared[0] / static_cast<float>(dim) + eps);
85
+ const float inv_scale = 1.0f / fmaxf(*d_scale, 1e-12f);
86
+
87
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
88
+ const __nv_bfloat162 xv = x2[i];
89
+ float v0 = (__bfloat162float(xv.x) - mean) * inv_std;
90
+ float v1 = (__bfloat162float(xv.y) - mean) * inv_std;
91
+ v0 = __bfloat162float(__float2bfloat16(v0)) * inv_scale;
92
+ v1 = __bfloat162float(__float2bfloat16(v1)) * inv_scale;
93
+ __nv_fp8_e4m3 pair[2];
94
+ pair[0] = __nv_fp8_e4m3(fminf(fmaxf(v0, -448.0f), 448.0f));
95
+ pair[1] = __nv_fp8_e4m3(fminf(fmaxf(v1, -448.0f), 448.0f));
96
+ *reinterpret_cast<uint16_t*>(out_row + 2 * i) =
97
+ *reinterpret_cast<uint16_t*>(pair);
98
+ }
99
+ }
100
+
101
+ } // namespace
102
+
103
+ void layer_norm_no_affine_fp8_static_bf16(
104
+ const void* x_bf16,
105
+ void* out_fp8,
106
+ const float* scale,
107
+ int rows,
108
+ int dim,
109
+ float eps,
110
+ cudaStream_t stream) {
111
+ if (rows <= 0 || dim <= 0) {
112
+ return;
113
+ }
114
+ layer_norm_no_affine_fp8_static_bf16_kernel
115
+ <<<rows, 256, 256 * sizeof(float), stream>>>(
116
+ reinterpret_cast<const __nv_bfloat16*>(x_bf16),
117
+ reinterpret_cast<__nv_fp8_e4m3*>(out_fp8),
118
+ scale,
119
+ dim,
120
+ eps);
121
+ }
122
+
123
+ } // namespace adaln_producers
124
+ } // namespace flash_rt
csrc/dit_layer_norm_fp8.cuh ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ #pragma once
3
+
4
+ #include <cuda_runtime.h>
5
+
6
+ namespace flash_rt {
7
+ namespace adaln_producers {
8
+
9
+ void layer_norm_no_affine_fp8_static_bf16(
10
+ const void* x_bf16,
11
+ void* out_fp8,
12
+ const float* scale,
13
+ int rows,
14
+ int dim,
15
+ float eps,
16
+ cudaStream_t stream);
17
+
18
+ } // namespace adaln_producers
19
+ } // namespace flash_rt
csrc/dit_norm_fp4_sfa.cu ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // ============================================================================
2
+ // Fused DiT norms (bf16) + NVFP4 quantize + SFA write. See header.
3
+ //
4
+ // Grid: (S,) one CTA per row, 128 threads. Row mean/var via the standard
5
+ // two-pass block reduction; 16-element quant blocks one per thread with
6
+ // 16-byte loads. Scale selection and e2m1 rounding are identical to
7
+ // quantize_fp4_dynamic_sfa_bf16_vec.
8
+ // ============================================================================
9
+ #include "dit_norm_fp4_sfa.cuh"
10
+
11
+ #include <cuda_bf16.h>
12
+ #include <cuda_fp8.h>
13
+
14
+ #if defined(CUTLASS_ARCH_MMA_SM100_SUPPORTED) || defined(__CUDA_ARCH__)
15
+ # include "cutlass/cutlass.h"
16
+ # include "cutlass/detail/sm100_blockscaled_layout.hpp"
17
+ # include "cute/tensor.hpp"
18
+ # define FV_HAVE_CUTLASS 1
19
+ #else
20
+ # define FV_HAVE_CUTLASS 0
21
+ #endif
22
+
23
+ namespace flash_rt {
24
+ namespace fused_fp4 {
25
+
26
+ #if FV_HAVE_CUTLASS
27
+
28
+ namespace {
29
+
30
+ using CfgDN = cutlass::detail::Sm1xxBlockScaledConfig<16>;
31
+
32
+ __device__ __forceinline__ uint8_t fp32_to_e2m1_dn(float x) {
33
+ uint8_t sign = (x < 0.f) ? 0x8u : 0x0u;
34
+ float ax = fabsf(x);
35
+ uint8_t mant;
36
+ if (ax <= 0.25f) mant = 0u;
37
+ else if (ax <= 0.75f) mant = 1u;
38
+ else if (ax <= 1.25f) mant = 2u;
39
+ else if (ax <= 1.75f) mant = 3u;
40
+ else if (ax <= 2.5f) mant = 4u;
41
+ else if (ax <= 3.5f) mant = 5u;
42
+ else if (ax <= 5.0f) mant = 6u;
43
+ else mant = 7u;
44
+ return sign | mant;
45
+ }
46
+
47
+ __device__ __forceinline__ float block_sum_dn(float v, float* sh) {
48
+ const int lane = threadIdx.x & 31;
49
+ const int warp = threadIdx.x >> 5;
50
+ #pragma unroll
51
+ for (int o = 16; o > 0; o >>= 1)
52
+ v += __shfl_xor_sync(0xffffffffu, v, o);
53
+ if (lane == 0) sh[warp] = v;
54
+ __syncthreads();
55
+ if (warp == 0) {
56
+ v = (lane < ((blockDim.x + 31) >> 5)) ? sh[lane] : 0.f;
57
+ #pragma unroll
58
+ for (int o = 16; o > 0; o >>= 1)
59
+ v += __shfl_xor_sync(0xffffffffu, v, o);
60
+ if (lane == 0) sh[0] = v;
61
+ }
62
+ __syncthreads();
63
+ const float r = sh[0];
64
+ __syncthreads();
65
+ return r;
66
+ }
67
+
68
+ // HAS_MOD=true: AdaLN (modulate with (1+scale), shift). false: plain LN.
69
+ template <bool HAS_MOD, class LayoutSF>
70
+ __global__ void dit_norm_fp4_sfa_kernel(
71
+ const __nv_bfloat16* __restrict__ x,
72
+ const __nv_bfloat16* __restrict__ scale, // [D] or nullptr
73
+ const __nv_bfloat16* __restrict__ shift, // [D] or nullptr
74
+ uint2* __restrict__ packed, // [S, D/16] 8-byte blocks
75
+ uint8_t* __restrict__ dst_sfa,
76
+ LayoutSF layout,
77
+ int D, float eps) {
78
+ const int r = blockIdx.x;
79
+ const __nv_bfloat162* row2 =
80
+ reinterpret_cast<const __nv_bfloat162*>(x + static_cast<long>(r) * D);
81
+ const int D2 = D >> 1;
82
+ __shared__ float sh[32];
83
+
84
+ float s = 0.f;
85
+ for (int i = threadIdx.x; i < D2; i += blockDim.x) {
86
+ const __nv_bfloat162 v = row2[i];
87
+ s += __bfloat162float(v.x) + __bfloat162float(v.y);
88
+ }
89
+ const float mean = block_sum_dn(s, sh) / D;
90
+
91
+ float var = 0.f;
92
+ for (int i = threadIdx.x; i < D2; i += blockDim.x) {
93
+ const __nv_bfloat162 v = row2[i];
94
+ const float d0 = __bfloat162float(v.x) - mean;
95
+ const float d1 = __bfloat162float(v.y) - mean;
96
+ var += d0 * d0 + d1 * d1;
97
+ }
98
+ const float rstd = rsqrtf(block_sum_dn(var, sh) / D + eps);
99
+
100
+ const int n_blocks = D >> 4;
101
+ const int4* x4 = reinterpret_cast<const int4*>(x + static_cast<long>(r) * D);
102
+ const int4* s4 = reinterpret_cast<const int4*>(scale);
103
+ const int4* h4 = reinterpret_cast<const int4*>(shift);
104
+ for (int blk = threadIdx.x; blk < n_blocks; blk += blockDim.x) {
105
+ const int4 xr[2] = {x4[2 * blk], x4[2 * blk + 1]};
106
+ const __nv_bfloat16* xh = reinterpret_cast<const __nv_bfloat16*>(xr);
107
+ int4 sr[2], hr[2];
108
+ const __nv_bfloat16* sc = nullptr;
109
+ const __nv_bfloat16* sf = nullptr;
110
+ if (HAS_MOD) {
111
+ sr[0] = s4[2 * blk]; sr[1] = s4[2 * blk + 1];
112
+ hr[0] = h4[2 * blk]; hr[1] = h4[2 * blk + 1];
113
+ sc = reinterpret_cast<const __nv_bfloat16*>(sr);
114
+ sf = reinterpret_cast<const __nv_bfloat16*>(hr);
115
+ }
116
+ float vals[16];
117
+ float amax = 0.f;
118
+ #pragma unroll
119
+ for (int i = 0; i < 16; ++i) {
120
+ float normed = (__bfloat162float(xh[i]) - mean) * rstd;
121
+ if (HAS_MOD)
122
+ normed = normed * (1.0f + __bfloat162float(sc[i])) +
123
+ __bfloat162float(sf[i]);
124
+ // bf16 rounding keeps this bit-identical to the two-step
125
+ // (bf16 norm kernel, then quantize) reference chain.
126
+ vals[i] = __bfloat162float(__float2bfloat16(normed));
127
+ const float a = fabsf(vals[i]);
128
+ if (a > amax) amax = a;
129
+ }
130
+ float desired = amax / 6.f;
131
+ if (desired < 1e-12f) desired = 1e-12f;
132
+ __nv_fp8_e4m3 bs_q = __nv_fp8_e4m3(fmaxf(desired, 0.f));
133
+ const float bs_dq = static_cast<float>(bs_q);
134
+ dst_sfa[layout(r, blk * 16, 0)] = *reinterpret_cast<uint8_t*>(&bs_q);
135
+ const float inv_bs = 1.f / bs_dq;
136
+ uint2 out;
137
+ uint8_t* ob = reinterpret_cast<uint8_t*>(&out);
138
+ #pragma unroll
139
+ for (int p = 0; p < 8; ++p) {
140
+ const uint8_t lo = fp32_to_e2m1_dn(vals[2 * p] * inv_bs);
141
+ const uint8_t hi = fp32_to_e2m1_dn(vals[2 * p + 1] * inv_bs);
142
+ ob[p] = static_cast<uint8_t>(lo | (hi << 4));
143
+ }
144
+ packed[static_cast<long>(r) * n_blocks + blk] = out;
145
+ }
146
+ }
147
+
148
+ } // namespace
149
+
150
+ #endif // FV_HAVE_CUTLASS
151
+
152
+ static int check_dn_args(const void* x, void* packed, int dim) {
153
+ if (dim % 16 != 0 || dim % 2 != 0) return -1;
154
+ if ((reinterpret_cast<uintptr_t>(x) & 15) ||
155
+ (reinterpret_cast<uintptr_t>(packed) & 7)) return -1;
156
+ return 0;
157
+ }
158
+
159
+ int ada_layer_norm_fp4_sfa_bf16(
160
+ const void* x, const void* scale, const void* shift,
161
+ void* packed, void* sfa,
162
+ int seq_len, int dim, float eps, cudaStream_t stream) {
163
+ #if FV_HAVE_CUTLASS
164
+ if (check_dn_args(x, packed, dim) != 0) return -1;
165
+ if ((reinterpret_cast<uintptr_t>(scale) & 15) ||
166
+ (reinterpret_cast<uintptr_t>(shift) & 15)) return -1;
167
+ auto shape = cute::make_shape(seq_len, 1, dim, 1);
168
+ auto layout = CfgDN::tile_atom_to_shape_SFA(shape);
169
+ dit_norm_fp4_sfa_kernel<true><<<seq_len, 128, 0, stream>>>(
170
+ reinterpret_cast<const __nv_bfloat16*>(x),
171
+ reinterpret_cast<const __nv_bfloat16*>(scale),
172
+ reinterpret_cast<const __nv_bfloat16*>(shift),
173
+ reinterpret_cast<uint2*>(packed),
174
+ reinterpret_cast<uint8_t*>(sfa),
175
+ layout, dim, eps);
176
+ const cudaError_t e = cudaGetLastError();
177
+ return (e == cudaSuccess) ? 0 : -static_cast<int>(e);
178
+ #else
179
+ (void)x; (void)scale; (void)shift; (void)packed; (void)sfa;
180
+ (void)seq_len; (void)dim; (void)eps; (void)stream;
181
+ return -2;
182
+ #endif
183
+ }
184
+
185
+ int layer_norm_no_affine_fp4_sfa_bf16(
186
+ const void* x, void* packed, void* sfa,
187
+ int seq_len, int dim, float eps, cudaStream_t stream) {
188
+ #if FV_HAVE_CUTLASS
189
+ if (check_dn_args(x, packed, dim) != 0) return -1;
190
+ auto shape = cute::make_shape(seq_len, 1, dim, 1);
191
+ auto layout = CfgDN::tile_atom_to_shape_SFA(shape);
192
+ dit_norm_fp4_sfa_kernel<false><<<seq_len, 128, 0, stream>>>(
193
+ reinterpret_cast<const __nv_bfloat16*>(x),
194
+ nullptr, nullptr,
195
+ reinterpret_cast<uint2*>(packed),
196
+ reinterpret_cast<uint8_t*>(sfa),
197
+ layout, dim, eps);
198
+ const cudaError_t e = cudaGetLastError();
199
+ return (e == cudaSuccess) ? 0 : -static_cast<int>(e);
200
+ #else
201
+ (void)x; (void)packed; (void)sfa;
202
+ (void)seq_len; (void)dim; (void)eps; (void)stream;
203
+ return -2;
204
+ #endif
205
+ }
206
+
207
+ } // namespace fused_fp4
208
+ } // namespace flash_rt
csrc/dit_norm_fp4_sfa.cuh ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // ============================================================================
2
+ // FlashRT — fused DiT norms (bf16 in) + NVFP4 quantize + SFA write.
3
+ //
4
+ // GR00T N1.7 DiT front-ends for NVFP4 GEMMs: the AdaLN-modulated norm1
5
+ // (QKV / cross-Q input) and the pre-FFN no-affine LayerNorm emit packed
6
+ // e2m1 + tile-interleaved UE4M3 scales directly, replacing a bf16 norm
7
+ // kernel followed by a separate quantize kernel. The normalized value is
8
+ // rounded through bf16 before quantization so the output is bit-identical
9
+ // to the two-step reference chain.
10
+ //
11
+ // Additive: new symbols only.
12
+ // ============================================================================
13
+ #pragma once
14
+
15
+ #include <cuda_runtime.h>
16
+
17
+ namespace flash_rt {
18
+ namespace fused_fp4 {
19
+
20
+ // packed/sfa = quantize(LN_no_affine(x[row]) * (1 + scale) + shift)
21
+ // x: bf16 [S, D]; scale/shift: bf16 [D] (per-layer AdaLN modulators).
22
+ int ada_layer_norm_fp4_sfa_bf16(
23
+ const void* x, const void* scale, const void* shift,
24
+ void* packed, void* sfa,
25
+ int seq_len, int dim, float eps, cudaStream_t stream);
26
+
27
+ // packed/sfa = quantize(LN_no_affine(x[row]))
28
+ int layer_norm_no_affine_fp4_sfa_bf16(
29
+ const void* x, void* packed, void* sfa,
30
+ int seq_len, int dim, float eps, cudaStream_t stream);
31
+
32
+ } // namespace fused_fp4
33
+ } // namespace flash_rt
csrc/sm110_fp4_dispatch.cu ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "sm110_fp4_dispatch.cuh"
2
+
3
+ #include "dit_norm_fp4_sfa.cuh"
4
+
5
+ namespace flash_rt::adaln_producers::hub {
6
+ namespace {
7
+
8
+ struct Registration {
9
+ Registration() {
10
+ ada_layer_norm_fp4_dispatch =
11
+ &flash_rt::fused_fp4::ada_layer_norm_fp4_sfa_bf16;
12
+ layer_norm_fp4_dispatch =
13
+ &flash_rt::fused_fp4::layer_norm_no_affine_fp4_sfa_bf16;
14
+ }
15
+ };
16
+
17
+ Registration registration;
18
+
19
+ } // namespace
20
+ } // namespace flash_rt::adaln_producers::hub
csrc/sm110_fp4_dispatch.cuh ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma once
2
+
3
+ #include <cuda_runtime_api.h>
4
+
5
+ namespace flash_rt::adaln_producers::hub {
6
+
7
+ using AdaLayerNormFp4Dispatch = int (*)(
8
+ const void* x, const void* scale, const void* shift,
9
+ void* packed, void* sfa, int rows, int dim, float eps,
10
+ cudaStream_t stream);
11
+
12
+ using LayerNormFp4Dispatch = int (*)(
13
+ const void* x, void* packed, void* sfa, int rows, int dim,
14
+ float eps, cudaStream_t stream);
15
+
16
+ extern AdaLayerNormFp4Dispatch ada_layer_norm_fp4_dispatch;
17
+ extern LayerNormFp4Dispatch layer_norm_fp4_dispatch;
18
+
19
+ } // namespace flash_rt::adaln_producers::hub
examples/README.md ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ # Examples
2
+
3
+ `basic_usage.py` shows the public Kernel Hub loading path:
4
+
5
+ ```bash
6
+ python adaptive-layernorm-producers/examples/basic_usage.py
7
+ ```
8
+
9
+ It allocates static output buffers for the FP8 path and uses the package helper
10
+ to allocate the NVFP4 packed activation and swizzled scale-factor buffers.
examples/basic_usage.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import torch
4
+ from kernels import get_kernel
5
+
6
+
7
+ def main() -> None:
8
+ ops = get_kernel("flashrt/adaptive-layernorm-producers", version=1, trust_remote_code=True)
9
+
10
+ rows, dim = 2520, 3072
11
+ x = torch.randn((rows, dim), device="cuda", dtype=torch.bfloat16)
12
+ scale = torch.zeros((dim,), device="cuda", dtype=torch.bfloat16)
13
+ shift = torch.zeros((dim,), device="cuda", dtype=torch.bfloat16)
14
+ act_scale = torch.tensor([0.025], device="cuda", dtype=torch.float32)
15
+
16
+ out = torch.empty_like(x, dtype=torch.float8_e4m3fn)
17
+ ops.ada_layer_norm_quant_fp8_bf16(x, scale, shift, act_scale, out=out)
18
+
19
+ packed, sf = ops.ada_layer_norm_quant_nvfp4_swizzled_bf16(x, scale, shift)
20
+ print(out.shape, out.dtype)
21
+ print(packed.shape, packed.dtype, sf.numel())
22
+
23
+
24
+ if __name__ == "__main__":
25
+ main()
flake.nix ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ description = "Flake for FlashRT adaptive LayerNorm producer kernels";
3
+
4
+ inputs = {
5
+ kernel-builder.url = "github:huggingface/kernels/870e825d881664e39f9287a27a74ef63ff3c545e";
6
+ };
7
+
8
+ outputs =
9
+ {
10
+ self,
11
+ kernel-builder,
12
+ }:
13
+ kernel-builder.lib.genKernelFlakeOutputs {
14
+ inherit self;
15
+ path = ./.;
16
+ };
17
+ }
tests/README.md ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Tests
2
+
3
+ Run correctness tests from the repository root:
4
+
5
+ ```bash
6
+ python adaptive-layernorm-producers/tests/test_adaptive_layernorm_producers.py --backend source --mode full
7
+ ```
8
+
9
+ After Kernel Hub build/publish, run installed-artifact validation:
10
+
11
+ ```bash
12
+ python adaptive-layernorm-producers/tests/test_adaptive_layernorm_producers.py --backend installed --mode full
13
+ ```
14
+
15
+ The source mode compiles the package locally with `torch.utils.cpp_extension`.
16
+ The installed mode imports the package exactly as exposed by Kernel Hub.
tests/native_reference/dit_bf16.cu ADDED
@@ -0,0 +1,315 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // DiT bf16 helpers — Phase 5a-2 (R0: pure additions, no edits to existing
2
+ // fp16 kernels). Mirrors layer_norm_no_affine_fp16 / ada_layer_norm_fp16 /
3
+ // add_bias_fp16 but with __nv_bfloat162 vectorized math, plus cast helpers
4
+ // for fp16 ↔ bf16 boundaries.
5
+
6
+ #include <cuda_runtime.h>
7
+ #include <cuda_fp16.h>
8
+ #include <cuda_bf16.h>
9
+ #include <cuda_fp8.h>
10
+ #include <cstdint>
11
+
12
+ // ────────────────────────────────────────────────────────────────────
13
+ // LayerNorm (no affine) — bf16
14
+ // ────────────────────────────────────────────────────────────────────
15
+ __global__ void layer_norm_no_affine_bf16_kernel(const __nv_bfloat16* __restrict__ x,
16
+ __nv_bfloat16* __restrict__ out,
17
+ int dim, float eps) {
18
+ int row = blockIdx.x;
19
+ const __nv_bfloat162* x2 = reinterpret_cast<const __nv_bfloat162*>(x + row * dim);
20
+ __nv_bfloat162* out2 = reinterpret_cast<__nv_bfloat162*>(out + row * dim);
21
+ int dim2 = dim >> 1;
22
+
23
+ extern __shared__ float shared[];
24
+ float local_sum = 0.0f;
25
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
26
+ __nv_bfloat162 val = x2[i];
27
+ local_sum += __bfloat162float(val.x) + __bfloat162float(val.y);
28
+ }
29
+ float val = local_sum;
30
+ for (int o = 16; o > 0; o >>= 1) val += __shfl_xor_sync(0xffffffff, val, o);
31
+ int lane = threadIdx.x & 31, wid = threadIdx.x >> 5;
32
+ if (!lane) shared[wid] = val;
33
+ __syncthreads();
34
+ if (!wid) { val = (lane < (blockDim.x >> 5)) ? shared[lane] : 0;
35
+ for (int o = 16; o > 0; o >>= 1) val += __shfl_xor_sync(0xffffffff, val, o); }
36
+ __syncthreads();
37
+ if (!threadIdx.x) shared[0] = val;
38
+ __syncthreads();
39
+ float mean = shared[0] / dim;
40
+
41
+ float local_var = 0.0f;
42
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
43
+ __nv_bfloat162 v = x2[i];
44
+ float d0 = __bfloat162float(v.x) - mean, d1 = __bfloat162float(v.y) - mean;
45
+ local_var += d0 * d0 + d1 * d1;
46
+ }
47
+ val = local_var;
48
+ for (int o = 16; o > 0; o >>= 1) val += __shfl_xor_sync(0xffffffff, val, o);
49
+ if (!lane) shared[wid] = val;
50
+ __syncthreads();
51
+ if (!wid) { val = (lane < (blockDim.x >> 5)) ? shared[lane] : 0;
52
+ for (int o = 16; o > 0; o >>= 1) val += __shfl_xor_sync(0xffffffff, val, o); }
53
+ __syncthreads();
54
+ if (!threadIdx.x) shared[0] = val;
55
+ __syncthreads();
56
+ float inv_std = rsqrtf(shared[0] / dim + eps);
57
+
58
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
59
+ __nv_bfloat162 xv = x2[i];
60
+ float v0 = (__bfloat162float(xv.x) - mean) * inv_std;
61
+ float v1 = (__bfloat162float(xv.y) - mean) * inv_std;
62
+ out2[i] = __floats2bfloat162_rn(v0, v1);
63
+ }
64
+ }
65
+
66
+ void layer_norm_no_affine_bf16(const __nv_bfloat16* x, __nv_bfloat16* out,
67
+ int seq_len, int dim, float eps,
68
+ cudaStream_t stream) {
69
+ layer_norm_no_affine_bf16_kernel<<<seq_len, 256, 256 * sizeof(float), stream>>>(
70
+ x, out, dim, eps);
71
+ }
72
+
73
+ __global__ void layer_norm_no_affine_fp8_static_bf16_kernel(
74
+ const __nv_bfloat16* __restrict__ x,
75
+ __nv_fp8_e4m3* __restrict__ out,
76
+ const float* __restrict__ d_scale,
77
+ int dim, float eps) {
78
+ int row = blockIdx.x;
79
+ const __nv_bfloat162* x2 =
80
+ reinterpret_cast<const __nv_bfloat162*>(x + (long long)row * dim);
81
+ __nv_fp8_e4m3* out_row = out + (long long)row * dim;
82
+ int dim2 = dim >> 1;
83
+
84
+ extern __shared__ float shared[];
85
+ float local_sum = 0.0f;
86
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
87
+ __nv_bfloat162 val = x2[i];
88
+ local_sum += __bfloat162float(val.x) + __bfloat162float(val.y);
89
+ }
90
+ float val = local_sum;
91
+ for (int o = 16; o > 0; o >>= 1) val += __shfl_xor_sync(0xffffffff, val, o);
92
+ int lane = threadIdx.x & 31, wid = threadIdx.x >> 5;
93
+ if (!lane) shared[wid] = val;
94
+ __syncthreads();
95
+ if (!wid) {
96
+ val = (lane < (blockDim.x >> 5)) ? shared[lane] : 0.0f;
97
+ for (int o = 16; o > 0; o >>= 1) val += __shfl_xor_sync(0xffffffff, val, o);
98
+ }
99
+ __syncthreads();
100
+ if (!threadIdx.x) shared[0] = val;
101
+ __syncthreads();
102
+ float mean = shared[0] / dim;
103
+
104
+ float local_var = 0.0f;
105
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
106
+ __nv_bfloat162 v = x2[i];
107
+ float d0 = __bfloat162float(v.x) - mean;
108
+ float d1 = __bfloat162float(v.y) - mean;
109
+ local_var += d0 * d0 + d1 * d1;
110
+ }
111
+ val = local_var;
112
+ for (int o = 16; o > 0; o >>= 1) val += __shfl_xor_sync(0xffffffff, val, o);
113
+ if (!lane) shared[wid] = val;
114
+ __syncthreads();
115
+ if (!wid) {
116
+ val = (lane < (blockDim.x >> 5)) ? shared[lane] : 0.0f;
117
+ for (int o = 16; o > 0; o >>= 1) val += __shfl_xor_sync(0xffffffff, val, o);
118
+ }
119
+ __syncthreads();
120
+ if (!threadIdx.x) shared[0] = val;
121
+ __syncthreads();
122
+ float inv_std = rsqrtf(shared[0] / dim + eps);
123
+ float inv_a = 1.0f / fmaxf(*d_scale, 1e-12f);
124
+
125
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
126
+ __nv_bfloat162 xv = x2[i];
127
+ float v0 = (__bfloat162float(xv.x) - mean) * inv_std;
128
+ float v1 = (__bfloat162float(xv.y) - mean) * inv_std;
129
+ v0 = __bfloat162float(__float2bfloat16(v0)) * inv_a;
130
+ v1 = __bfloat162float(__float2bfloat16(v1)) * inv_a;
131
+ __nv_fp8_e4m3 pair[2];
132
+ pair[0] = __nv_fp8_e4m3(fminf(fmaxf(v0, -448.0f), 448.0f));
133
+ pair[1] = __nv_fp8_e4m3(fminf(fmaxf(v1, -448.0f), 448.0f));
134
+ *reinterpret_cast<uint16_t*>(out_row + 2 * i) =
135
+ *reinterpret_cast<uint16_t*>(pair);
136
+ }
137
+ }
138
+
139
+ void layer_norm_no_affine_fp8_static_bf16(
140
+ const __nv_bfloat16* x, __nv_fp8_e4m3* out, const float* d_scale,
141
+ int seq_len, int dim, float eps, cudaStream_t stream) {
142
+ layer_norm_no_affine_fp8_static_bf16_kernel
143
+ <<<seq_len, 256, 256 * sizeof(float), stream>>>(
144
+ x, out, d_scale, dim, eps);
145
+ }
146
+
147
+ // ────────────────────────────────────────────────────────────────────
148
+ // AdaLayerNorm — bf16
149
+ // out = LN(x, no_affine) * (1 + scale) + shift
150
+ // ────────────────────────────────────────────────────────────────────
151
+ __global__ void ada_layer_norm_bf16_kernel(const __nv_bfloat16* __restrict__ x,
152
+ const __nv_bfloat16* __restrict__ scale,
153
+ const __nv_bfloat16* __restrict__ shift,
154
+ __nv_bfloat16* __restrict__ out,
155
+ int dim, float eps) {
156
+ int row = blockIdx.x;
157
+ const __nv_bfloat162* x2 = reinterpret_cast<const __nv_bfloat162*>(x + row * dim);
158
+ const __nv_bfloat162* sc2 = reinterpret_cast<const __nv_bfloat162*>(scale);
159
+ const __nv_bfloat162* sh2 = reinterpret_cast<const __nv_bfloat162*>(shift);
160
+ __nv_bfloat162* out2 = reinterpret_cast<__nv_bfloat162*>(out + row * dim);
161
+ int dim2 = dim >> 1;
162
+
163
+ extern __shared__ float shared[];
164
+ float local_sum = 0.0f;
165
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
166
+ __nv_bfloat162 val = x2[i];
167
+ local_sum += __bfloat162float(val.x) + __bfloat162float(val.y);
168
+ }
169
+ float val = local_sum;
170
+ for (int o = 16; o > 0; o >>= 1) val += __shfl_xor_sync(0xffffffff, val, o);
171
+ int lane = threadIdx.x & 31, wid = threadIdx.x >> 5;
172
+ if (!lane) shared[wid] = val;
173
+ __syncthreads();
174
+ if (!wid) { val = (lane < (blockDim.x >> 5)) ? shared[lane] : 0;
175
+ for (int o = 16; o > 0; o >>= 1) val += __shfl_xor_sync(0xffffffff, val, o); }
176
+ __syncthreads(); if (!threadIdx.x) shared[0] = val; __syncthreads();
177
+ float mean = shared[0] / dim;
178
+
179
+ float local_var = 0.0f;
180
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
181
+ __nv_bfloat162 v = x2[i];
182
+ float d0 = __bfloat162float(v.x) - mean, d1 = __bfloat162float(v.y) - mean;
183
+ local_var += d0 * d0 + d1 * d1;
184
+ }
185
+ val = local_var;
186
+ for (int o = 16; o > 0; o >>= 1) val += __shfl_xor_sync(0xffffffff, val, o);
187
+ if (!lane) shared[wid] = val;
188
+ __syncthreads();
189
+ if (!wid) { val = (lane < (blockDim.x >> 5)) ? shared[lane] : 0;
190
+ for (int o = 16; o > 0; o >>= 1) val += __shfl_xor_sync(0xffffffff, val, o); }
191
+ __syncthreads(); if (!threadIdx.x) shared[0] = val; __syncthreads();
192
+ float inv_std = rsqrtf(shared[0] / dim + eps);
193
+
194
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
195
+ __nv_bfloat162 xv = x2[i], sv = sc2[i], hv = sh2[i];
196
+ float n0 = (__bfloat162float(xv.x) - mean) * inv_std;
197
+ float n1 = (__bfloat162float(xv.y) - mean) * inv_std;
198
+ float v0 = n0 * (1.0f + __bfloat162float(sv.x)) + __bfloat162float(hv.x);
199
+ float v1 = n1 * (1.0f + __bfloat162float(sv.y)) + __bfloat162float(hv.y);
200
+ out2[i] = __floats2bfloat162_rn(v0, v1);
201
+ }
202
+ }
203
+
204
+ void ada_layer_norm_bf16(const __nv_bfloat16* x,
205
+ const __nv_bfloat16* scale, const __nv_bfloat16* shift,
206
+ __nv_bfloat16* out, int seq_len, int dim, float eps,
207
+ cudaStream_t stream) {
208
+ ada_layer_norm_bf16_kernel<<<seq_len, 256, 256 * sizeof(float), stream>>>(
209
+ x, scale, shift, out, dim, eps);
210
+ }
211
+
212
+ // Per-row AdaLayerNorm — bf16
213
+ // out[row] = LN(x[row], no_affine) * (1 + scale[row]) + shift[row]
214
+ __global__ void ada_layer_norm_bf16_per_token_kernel(
215
+ const __nv_bfloat16* __restrict__ x,
216
+ const __nv_bfloat16* __restrict__ scale,
217
+ const __nv_bfloat16* __restrict__ shift,
218
+ __nv_bfloat16* __restrict__ out,
219
+ int dim, float eps) {
220
+ int row = blockIdx.x;
221
+ const __nv_bfloat162* x2 = reinterpret_cast<const __nv_bfloat162*>(x + row * dim);
222
+ const __nv_bfloat162* sc2 = reinterpret_cast<const __nv_bfloat162*>(scale + row * dim);
223
+ const __nv_bfloat162* sh2 = reinterpret_cast<const __nv_bfloat162*>(shift + row * dim);
224
+ __nv_bfloat162* out2 = reinterpret_cast<__nv_bfloat162*>(out + row * dim);
225
+ int dim2 = dim >> 1;
226
+
227
+ extern __shared__ float shared[];
228
+ float local_sum = 0.0f;
229
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
230
+ __nv_bfloat162 val = x2[i];
231
+ local_sum += __bfloat162float(val.x) + __bfloat162float(val.y);
232
+ }
233
+ float val = local_sum;
234
+ for (int o = 16; o > 0; o >>= 1) val += __shfl_xor_sync(0xffffffff, val, o);
235
+ int lane = threadIdx.x & 31, wid = threadIdx.x >> 5;
236
+ if (!lane) shared[wid] = val;
237
+ __syncthreads();
238
+ if (!wid) { val = (lane < (blockDim.x >> 5)) ? shared[lane] : 0;
239
+ for (int o = 16; o > 0; o >>= 1) val += __shfl_xor_sync(0xffffffff, val, o); }
240
+ __syncthreads(); if (!threadIdx.x) shared[0] = val; __syncthreads();
241
+ float mean = shared[0] / dim;
242
+
243
+ float local_var = 0.0f;
244
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
245
+ __nv_bfloat162 v = x2[i];
246
+ float d0 = __bfloat162float(v.x) - mean, d1 = __bfloat162float(v.y) - mean;
247
+ local_var += d0 * d0 + d1 * d1;
248
+ }
249
+ val = local_var;
250
+ for (int o = 16; o > 0; o >>= 1) val += __shfl_xor_sync(0xffffffff, val, o);
251
+ if (!lane) shared[wid] = val;
252
+ __syncthreads();
253
+ if (!wid) { val = (lane < (blockDim.x >> 5)) ? shared[lane] : 0;
254
+ for (int o = 16; o > 0; o >>= 1) val += __shfl_xor_sync(0xffffffff, val, o); }
255
+ __syncthreads(); if (!threadIdx.x) shared[0] = val; __syncthreads();
256
+ float inv_std = rsqrtf(shared[0] / dim + eps);
257
+
258
+ for (int i = threadIdx.x; i < dim2; i += blockDim.x) {
259
+ __nv_bfloat162 xv = x2[i], sv = sc2[i], hv = sh2[i];
260
+ float n0 = (__bfloat162float(xv.x) - mean) * inv_std;
261
+ float n1 = (__bfloat162float(xv.y) - mean) * inv_std;
262
+ float v0 = n0 * (1.0f + __bfloat162float(sv.x)) + __bfloat162float(hv.x);
263
+ float v1 = n1 * (1.0f + __bfloat162float(sv.y)) + __bfloat162float(hv.y);
264
+ out2[i] = __floats2bfloat162_rn(v0, v1);
265
+ }
266
+ }
267
+
268
+ void ada_layer_norm_bf16_per_token(
269
+ const __nv_bfloat16* x,
270
+ const __nv_bfloat16* scale, const __nv_bfloat16* shift,
271
+ __nv_bfloat16* out, int seq_len, int dim, float eps,
272
+ cudaStream_t stream) {
273
+ ada_layer_norm_bf16_per_token_kernel
274
+ <<<seq_len, 256, 256 * sizeof(float), stream>>>(
275
+ x, scale, shift, out, dim, eps);
276
+ }
277
+
278
+ // ────────────────────────────────────────────────────────────────────
279
+ // Bias add: x[i] += b[i % D] — bf16
280
+ // ────────────────────────────────────────────────────────────────────
281
+ __global__ void add_bias_bf16_kernel(__nv_bfloat16* x, const __nv_bfloat16* b,
282
+ int S, int D) {
283
+ int i = blockIdx.x * blockDim.x + threadIdx.x;
284
+ if (i < S * D) {
285
+ x[i] = __float2bfloat16(__bfloat162float(x[i]) + __bfloat162float(b[i % D]));
286
+ }
287
+ }
288
+
289
+ void add_bias_bf16(__nv_bfloat16* x, const __nv_bfloat16* b,
290
+ int S, int D, cudaStream_t stream) {
291
+ add_bias_bf16_kernel<<<(S * D + 255) / 256, 256, 0, stream>>>(x, b, S, D);
292
+ }
293
+
294
+ // ────────────────────────────────────────────────────────────────────
295
+ // Cast fp16 ↔ bf16 (DiT input/output boundary)
296
+ // ────────────────────────────────────────────────────────────────────
297
+ __global__ void cast_fp16_to_bf16_kernel(const __half* in, __nv_bfloat16* out, int n) {
298
+ int i = blockIdx.x * blockDim.x + threadIdx.x;
299
+ if (i < n) out[i] = __float2bfloat16(__half2float(in[i]));
300
+ }
301
+
302
+ void cast_fp16_to_bf16(const __half* in, __nv_bfloat16* out, int n,
303
+ cudaStream_t stream) {
304
+ cast_fp16_to_bf16_kernel<<<(n + 255) / 256, 256, 0, stream>>>(in, out, n);
305
+ }
306
+
307
+ __global__ void cast_bf16_to_fp16_kernel(const __nv_bfloat16* in, __half* out, int n) {
308
+ int i = blockIdx.x * blockDim.x + threadIdx.x;
309
+ if (i < n) out[i] = __float2half(__bfloat162float(in[i]));
310
+ }
311
+
312
+ void cast_bf16_to_fp16(const __nv_bfloat16* in, __half* out, int n,
313
+ cudaStream_t stream) {
314
+ cast_bf16_to_fp16_kernel<<<(n + 255) / 256, 256, 0, stream>>>(in, out, n);
315
+ }
tests/sm110_reference_binding.cpp ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include <torch/all.h>
2
+ #include <torch/library.h>
3
+
4
+ #include <ATen/cuda/CUDAContext.h>
5
+ #include <c10/cuda/CUDAGuard.h>
6
+ #include <cuda_bf16.h>
7
+
8
+ #include "quantize_fp4_sfa_bf16.cuh"
9
+
10
+ void ada_layer_norm_bf16(
11
+ const __nv_bfloat16* x, const __nv_bfloat16* scale,
12
+ const __nv_bfloat16* shift, __nv_bfloat16* out,
13
+ int seq_len, int dim, float eps, cudaStream_t stream);
14
+ void layer_norm_no_affine_bf16(
15
+ const __nv_bfloat16* x, __nv_bfloat16* out, int seq_len, int dim, float eps,
16
+ cudaStream_t stream);
17
+
18
+ namespace {
19
+
20
+ void reference_adaln_fp4(
21
+ const torch::Tensor& x, const torch::Tensor& scale,
22
+ const torch::Tensor& shift, double eps, torch::Tensor& packed,
23
+ torch::Tensor& sf) {
24
+ c10::cuda::CUDAGuard guard(x.device());
25
+ auto stream = at::cuda::getCurrentCUDAStream(x.get_device()).stream();
26
+ auto norm = torch::empty_like(x);
27
+ ada_layer_norm_bf16(
28
+ static_cast<const __nv_bfloat16*>(x.data_ptr()),
29
+ static_cast<const __nv_bfloat16*>(scale.data_ptr()),
30
+ static_cast<const __nv_bfloat16*>(shift.data_ptr()),
31
+ static_cast<__nv_bfloat16*>(norm.data_ptr()),
32
+ static_cast<int>(x.size(0)), static_cast<int>(x.size(1)),
33
+ static_cast<float>(eps), stream);
34
+ const int rc = flash_rt::fp4::quantize_fp4_dynamic_sfa_bf16_vec(
35
+ norm.data_ptr(), packed.data_ptr(), sf.data_ptr(),
36
+ static_cast<int>(x.size(0)), static_cast<int>(x.size(1)), false, stream);
37
+ TORCH_CHECK(rc == 0, "SM110 staged AdaLN-FP4 reference failed: rc=", rc);
38
+ }
39
+
40
+ void reference_ln_fp4(
41
+ const torch::Tensor& x, double eps, torch::Tensor& packed,
42
+ torch::Tensor& sf) {
43
+ c10::cuda::CUDAGuard guard(x.device());
44
+ auto stream = at::cuda::getCurrentCUDAStream(x.get_device()).stream();
45
+ auto norm = torch::empty_like(x);
46
+ layer_norm_no_affine_bf16(
47
+ static_cast<const __nv_bfloat16*>(x.data_ptr()),
48
+ static_cast<__nv_bfloat16*>(norm.data_ptr()),
49
+ static_cast<int>(x.size(0)),
50
+ static_cast<int>(x.size(1)), static_cast<float>(eps), stream);
51
+ const int rc = flash_rt::fp4::quantize_fp4_dynamic_sfa_bf16_vec(
52
+ norm.data_ptr(), packed.data_ptr(), sf.data_ptr(),
53
+ static_cast<int>(x.size(0)), static_cast<int>(x.size(1)), false, stream);
54
+ TORCH_CHECK(rc == 0, "SM110 staged LayerNorm-FP4 reference failed: rc=", rc);
55
+ }
56
+
57
+ } // namespace
58
+
59
+ TORCH_LIBRARY_FRAGMENT(adaptive_layernorm_producers_test, ops) {
60
+ ops.def("_reference_adaln_fp4(Tensor x, Tensor scale, Tensor shift, float eps, Tensor! packed, Tensor! sf) -> ()");
61
+ ops.def("_reference_ln_fp4(Tensor x, float eps, Tensor! packed, Tensor! sf) -> ()");
62
+ ops.impl("_reference_adaln_fp4", torch::kCUDA, &reference_adaln_fp4);
63
+ ops.impl("_reference_ln_fp4", torch::kCUDA, &reference_ln_fp4);
64
+ }
tests/test_adaptive_layernorm_producers.py ADDED
@@ -0,0 +1,597 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Correctness tests for adaptive-layernorm-producers."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import ctypes
8
+ import ctypes.util
9
+ import importlib
10
+ import math
11
+ import os
12
+ import sys
13
+ from pathlib import Path
14
+
15
+ import torch
16
+
17
+
18
+ ROOT = Path(__file__).resolve().parents[2]
19
+ PACKAGE = ROOT / "adaptive-layernorm-producers"
20
+ DEFAULT_CUTLASS_INCLUDE = ROOT.parent / "official" / "FlashRT" / "third_party" / "cutlass" / "include"
21
+ REGISTRATION_INCLUDE = (
22
+ ROOT.parent
23
+ / "kernels"
24
+ / "kernel-builder"
25
+ / "src"
26
+ / "pyproject"
27
+ / "templates"
28
+ / "torch"
29
+ )
30
+ FP8_MAX = 448.0
31
+
32
+
33
+ class SourceOps:
34
+ def __init__(self, namespace: str) -> None:
35
+ self._ops = getattr(torch.ops, namespace)
36
+
37
+ def ada_layer_norm_quant_fp8_bf16(self, x, scale, shift, act_scale, eps=1e-5, out=None):
38
+ out = torch.empty_like(x, dtype=torch.float8_e4m3fn) if out is None else out
39
+ self._ops.ada_layer_norm_quant_fp8_bf16(x, scale, shift, act_scale, float(eps), out)
40
+ return out
41
+
42
+ def ada_layer_norm_quant_fp8_ptok_bf16(self, x, scale, shift, act_scale, eps=1e-5, out=None):
43
+ out = torch.empty_like(x, dtype=torch.float8_e4m3fn) if out is None else out
44
+ self._ops.ada_layer_norm_quant_fp8_ptok_bf16(x, scale, shift, act_scale, float(eps), out)
45
+ return out
46
+
47
+ def ada_layer_norm_quant_fp8_ptok_table_bf16(
48
+ self, x, temb, table, act_scale, shift_idx, scale_idx, eps=1e-5, out=None
49
+ ):
50
+ out = torch.empty_like(x, dtype=torch.float8_e4m3fn) if out is None else out
51
+ self._ops.ada_layer_norm_quant_fp8_ptok_table_bf16(
52
+ x, temb, table, act_scale, int(shift_idx), int(scale_idx), float(eps), out
53
+ )
54
+ return out
55
+
56
+ def ada_layer_norm_quant_fp8_modfp8_bf16(
57
+ self, x, scale_fp8, shift_fp8, scale_deq, shift_deq, act_scale, eps=1e-5, out=None
58
+ ):
59
+ out = torch.empty_like(x, dtype=torch.float8_e4m3fn) if out is None else out
60
+ self._ops.ada_layer_norm_quant_fp8_modfp8_bf16(
61
+ x, scale_fp8, shift_fp8, scale_deq, shift_deq, act_scale, float(eps), out
62
+ )
63
+ return out
64
+
65
+ def awq_ada_layer_norm_quant_fp8_bf16(self, x, scale, shift, inv_s, act_scale, eps=1e-5, out=None):
66
+ out = torch.empty_like(x, dtype=torch.float8_e4m3fn) if out is None else out
67
+ self._ops.awq_ada_layer_norm_quant_fp8_bf16(x, scale, shift, inv_s, act_scale, float(eps), out)
68
+ return out
69
+
70
+ def ada_layer_norm_quant_nvfp4_swizzled_bf16(self, x, scale, shift, eps=1e-5, packed=None, sf_swizzled=None):
71
+ packed, sf_swizzled = _nvfp4_out(x, packed, sf_swizzled)
72
+ self._ops.ada_layer_norm_quant_nvfp4_swizzled_bf16(x, scale, shift, float(eps), packed, sf_swizzled)
73
+ return packed, sf_swizzled
74
+
75
+ def ada_layer_norm_quant_nvfp4_swizzled_modfp8_bf16(
76
+ self, x, scale_fp8, shift_fp8, scale_deq, shift_deq, eps=1e-5, packed=None, sf_swizzled=None
77
+ ):
78
+ packed, sf_swizzled = _nvfp4_out(x, packed, sf_swizzled)
79
+ self._ops.ada_layer_norm_quant_nvfp4_swizzled_modfp8_bf16(
80
+ x, scale_fp8, shift_fp8, scale_deq, shift_deq, float(eps), packed, sf_swizzled
81
+ )
82
+ return packed, sf_swizzled
83
+
84
+ def layer_norm_no_affine_quant_fp8_static_bf16(self, x, act_scale, eps=1e-5, out=None):
85
+ out = torch.empty_like(x, dtype=torch.float8_e4m3fn) if out is None else out
86
+ self._ops.layer_norm_no_affine_quant_fp8_static_bf16(x, act_scale, float(eps), out)
87
+ return out
88
+
89
+ def layer_norm_no_affine_quant_nvfp4_swizzled_bf16(
90
+ self, x, eps=1e-5, packed=None, sf_swizzled=None
91
+ ):
92
+ packed, sf_swizzled = _nvfp4_out(x, packed, sf_swizzled)
93
+ self._ops.layer_norm_no_affine_quant_nvfp4_swizzled_bf16(
94
+ x, float(eps), packed, sf_swizzled
95
+ )
96
+ return packed, sf_swizzled
97
+
98
+ def adaln_modulation6_bf16(self, adaln_params, layer_modulation, out=None):
99
+ expected = (
100
+ adaln_params.shape[0],
101
+ adaln_params.shape[1],
102
+ adaln_params.shape[3],
103
+ )
104
+ if out is None:
105
+ out = tuple(
106
+ torch.empty(expected, device=adaln_params.device, dtype=torch.bfloat16)
107
+ for _ in range(6)
108
+ )
109
+ self._ops.adaln_modulation6_bf16(
110
+ adaln_params, layer_modulation, *out
111
+ )
112
+ return out
113
+
114
+ def reference_adaln_fp4(self, x, scale, shift, eps, packed, sf):
115
+ self._ops._reference_adaln_fp4(x, scale, shift, float(eps), packed, sf)
116
+ return packed, sf
117
+
118
+ def reference_ln_fp4(self, x, eps, packed, sf):
119
+ self._ops._reference_ln_fp4(x, float(eps), packed, sf)
120
+ return packed, sf
121
+
122
+
123
+ def _preload_cublaslt() -> None:
124
+ for parent in Path(torch.__file__).resolve().parents:
125
+ candidate = parent / "nvidia" / "cublas" / "lib" / "libcublasLt.so.12"
126
+ if candidate.exists():
127
+ ctypes.CDLL(str(candidate), mode=ctypes.RTLD_GLOBAL)
128
+ return
129
+ library = ctypes.util.find_library("cublasLt")
130
+ if library:
131
+ ctypes.CDLL(library, mode=ctypes.RTLD_GLOBAL)
132
+
133
+
134
+ def _current_arch_list() -> str:
135
+ major, minor = torch.cuda.get_device_capability(0)
136
+ if (major, minor) == (11, 0):
137
+ return "11.0a"
138
+ return f"{major}.{minor}"
139
+
140
+
141
+ def load_source_ops() -> SourceOps:
142
+ from torch.utils.cpp_extension import load
143
+
144
+ if not REGISTRATION_INCLUDE.is_dir():
145
+ raise RuntimeError(f"missing kernel-builder registration include: {REGISTRATION_INCLUDE}")
146
+ cutlass_include = Path(
147
+ os.environ.get("FLASHRT_CUTLASS_INCLUDE", str(DEFAULT_CUTLASS_INCLUDE))
148
+ )
149
+ if not cutlass_include.is_dir():
150
+ raise RuntimeError(f"missing CUTLASS include path: {cutlass_include}")
151
+ _preload_cublaslt()
152
+ os.environ.setdefault("TORCH_CUDA_ARCH_LIST", _current_arch_list())
153
+ namespace = "adaptive_layernorm_producers_test"
154
+ sm110_sources = []
155
+ if torch.cuda.get_device_capability(0) == (11, 0):
156
+ sm110_sources = [
157
+ str(PACKAGE / "csrc" / "dit_norm_fp4_sfa.cu"),
158
+ str(PACKAGE / "csrc" / "sm110_fp4_dispatch.cu"),
159
+ str(PACKAGE / "tests" / "native_reference" / "dit_bf16.cu"),
160
+ str(ROOT / "fp4-gemm" / "csrc" / "quantize" / "quantize_fp4_sfa_bf16.cu"),
161
+ str(PACKAGE / "tests" / "sm110_reference_binding.cpp"),
162
+ ]
163
+ load(
164
+ name=namespace,
165
+ sources=[
166
+ str(PACKAGE / "torch-ext" / "torch_binding.cpp"),
167
+ str(PACKAGE / "csrc" / "ada_layer_norm_fp8.cu"),
168
+ str(PACKAGE / "csrc" / "ada_layer_norm_fp8_ptok.cu"),
169
+ str(PACKAGE / "csrc" / "dit_layer_norm_fp8.cu"),
170
+ str(PACKAGE / "csrc" / "adaln_modulation6.cu"),
171
+ *sm110_sources,
172
+ ],
173
+ extra_include_paths=[
174
+ str(PACKAGE / "csrc"), str(cutlass_include),
175
+ str(ROOT / "fp4-gemm" / "csrc" / "quantize"),
176
+ str(REGISTRATION_INCLUDE),
177
+ ],
178
+ extra_cflags=["-O3", "-DCUDA_KERNEL"],
179
+ extra_cuda_cflags=[
180
+ "-O3", "--expt-relaxed-constexpr", "-DCUDA_KERNEL",
181
+ "-DCUTLASS_ARCH_MMA_SM100_SUPPORTED=1",
182
+ ],
183
+ verbose=False,
184
+ )
185
+ return SourceOps(namespace)
186
+
187
+
188
+ def load_sm110_reference_ops() -> SourceOps:
189
+ """Load the package-local staged native oracle for installed tests."""
190
+ from torch.utils.cpp_extension import load
191
+
192
+ cutlass_include = Path(
193
+ os.environ.get("FLASHRT_CUTLASS_INCLUDE", str(DEFAULT_CUTLASS_INCLUDE))
194
+ )
195
+ if not cutlass_include.is_dir():
196
+ raise RuntimeError(f"missing CUTLASS include path: {cutlass_include}")
197
+ os.environ.setdefault("TORCH_CUDA_ARCH_LIST", _current_arch_list())
198
+ load(
199
+ name="adaptive_layernorm_producers_reference",
200
+ sources=[
201
+ str(PACKAGE / "tests" / "native_reference" / "dit_bf16.cu"),
202
+ str(ROOT / "fp4-gemm" / "csrc" / "quantize" / "quantize_fp4_sfa_bf16.cu"),
203
+ str(PACKAGE / "tests" / "sm110_reference_binding.cpp"),
204
+ ],
205
+ extra_include_paths=[
206
+ str(ROOT / "fp4-gemm" / "csrc" / "quantize"),
207
+ str(REGISTRATION_INCLUDE),
208
+ str(cutlass_include),
209
+ ],
210
+ extra_cflags=["-O3", "-DCUDA_KERNEL"],
211
+ extra_cuda_cflags=[
212
+ "-O3", "--expt-relaxed-constexpr", "--expt-extended-lambda",
213
+ "-DCUDA_KERNEL", "-DCUTLASS_ARCH_MMA_SM100_SUPPORTED=1",
214
+ ],
215
+ is_python_module=False,
216
+ verbose=False,
217
+ )
218
+ return SourceOps("adaptive_layernorm_producers_test")
219
+
220
+
221
+ def load_installed_ops(artifact: str | None):
222
+ if artifact:
223
+ sys.path.insert(0, artifact)
224
+ try:
225
+ return importlib.import_module("adaptive_layernorm_producers")
226
+ finally:
227
+ if artifact:
228
+ sys.path.remove(artifact)
229
+
230
+
231
+ def swizzled_sf_size(rows: int, dim: int) -> int:
232
+ n_blocks = dim // 16
233
+ return ((rows + 127) // 128) * ((n_blocks + 3) // 4) * 128 * 64
234
+
235
+
236
+ def _nvfp4_out(x: torch.Tensor, packed=None, sf_swizzled=None):
237
+ if packed is None:
238
+ packed = torch.empty((x.shape[0], x.shape[1] // 2), device=x.device, dtype=torch.uint8)
239
+ if sf_swizzled is None:
240
+ sf_swizzled = torch.zeros((swizzled_sf_size(x.shape[0], x.shape[1]),), device=x.device, dtype=torch.uint8)
241
+ return packed, sf_swizzled
242
+
243
+
244
+ def make_case(rows: int, dim: int):
245
+ x = (torch.randn((rows, dim), device="cuda", dtype=torch.float32) * 0.75).to(torch.bfloat16).contiguous()
246
+ scale = (torch.randn((dim,), device="cuda", dtype=torch.float32) * 0.08).to(torch.bfloat16).contiguous()
247
+ shift = (torch.randn((dim,), device="cuda", dtype=torch.float32) * 0.08).to(torch.bfloat16).contiguous()
248
+ inv_s = (1.0 + torch.rand((dim,), device="cuda", dtype=torch.float32) * 0.2).to(torch.bfloat16).contiguous()
249
+ act_scale = torch.tensor([0.025], device="cuda", dtype=torch.float32)
250
+ scale_deq = torch.tensor([0.0075], device="cuda", dtype=torch.float32)
251
+ shift_deq = torch.tensor([0.0075], device="cuda", dtype=torch.float32)
252
+ scale_fp8 = torch.clamp(scale.float() / scale_deq, -FP8_MAX, FP8_MAX).to(torch.float8_e4m3fn).contiguous()
253
+ shift_fp8 = torch.clamp(shift.float() / shift_deq, -FP8_MAX, FP8_MAX).to(torch.float8_e4m3fn).contiguous()
254
+ return x, scale, shift, inv_s, act_scale, scale_fp8, shift_fp8, scale_deq, shift_deq
255
+
256
+
257
+ def ref_layer_norm_no_affine(x: torch.Tensor, eps: float) -> torch.Tensor:
258
+ return ref_layer_norm_no_affine_f32(x, eps).to(torch.bfloat16)
259
+
260
+
261
+ def ref_layer_norm_no_affine_f32(x: torch.Tensor, eps: float) -> torch.Tensor:
262
+ xf = x.float()
263
+ mean = xf.mean(dim=-1, keepdim=True)
264
+ var = ((xf - mean) * (xf - mean)).mean(dim=-1, keepdim=True)
265
+ return (xf - mean) * torch.rsqrt(var + eps)
266
+
267
+
268
+ def ref_adaln(x: torch.Tensor, scale: torch.Tensor, shift: torch.Tensor, eps: float) -> torch.Tensor:
269
+ norm = ref_layer_norm_no_affine_f32(x, eps)
270
+ return (norm * (1.0 + scale.float()) + shift.float()).to(torch.bfloat16)
271
+
272
+
273
+ def ref_adaln_float_mod(x: torch.Tensor, scale: torch.Tensor, shift: torch.Tensor, eps: float) -> torch.Tensor:
274
+ norm = ref_layer_norm_no_affine_f32(x, eps)
275
+ return (norm * (1.0 + scale.float()) + shift.float()).to(torch.bfloat16)
276
+
277
+
278
+ def quant_fp8(x: torch.Tensor, scale: torch.Tensor) -> torch.Tensor:
279
+ return torch.clamp(x.float() / scale.float().reshape(()), -FP8_MAX, FP8_MAX).to(torch.float8_e4m3fn)
280
+
281
+
282
+ def f32_to_fp4_e2m1(x: float) -> int:
283
+ if x == 0.0:
284
+ return 0
285
+ sign = 0x8 if x < 0 else 0
286
+ ax = abs(x)
287
+ if ax < 0.25:
288
+ return sign
289
+ if ax < 0.75:
290
+ return sign | 0x1
291
+ if ax < 1.5:
292
+ return sign | 0x2
293
+ if ax < 3.0:
294
+ return sign | 0x3
295
+ if ax < 5.0:
296
+ return sign | 0x6
297
+ return sign | 0x7
298
+
299
+
300
+ def f32_to_fp4_e2m1_sm110(x: float) -> int:
301
+ """Match #163's native SM110 FP4 producer bucket boundaries."""
302
+ sign = 0x8 if x < 0 else 0
303
+ ax = abs(x)
304
+ if ax <= 0.25:
305
+ mantissa = 0
306
+ elif ax <= 0.75:
307
+ mantissa = 1
308
+ elif ax <= 1.25:
309
+ mantissa = 2
310
+ elif ax <= 1.75:
311
+ mantissa = 3
312
+ elif ax <= 2.5:
313
+ mantissa = 4
314
+ elif ax <= 3.5:
315
+ mantissa = 5
316
+ elif ax <= 5.0:
317
+ mantissa = 6
318
+ else:
319
+ mantissa = 7
320
+ return sign | mantissa
321
+
322
+
323
+ def f32_to_ue4m3_ceil(x: float) -> int:
324
+ if x <= 0.0:
325
+ return 0
326
+ if x < 0.0009765625:
327
+ return 1
328
+ mant, exp = math.frexp(x)
329
+ exp -= 1
330
+ frac = mant * 2.0 - 1.0
331
+ mantissa = math.ceil(frac * 8.0)
332
+ if mantissa >= 8:
333
+ mantissa = 0
334
+ exp += 1
335
+ biased_exp = exp + 7
336
+ if biased_exp <= 0:
337
+ return 1
338
+ if biased_exp >= 15:
339
+ return 0x7F
340
+ return (biased_exp << 3) | mantissa
341
+
342
+
343
+ def ue4m3_to_f32(v: int) -> float:
344
+ if v == 0:
345
+ return 0.0
346
+ exp = ((v >> 3) & 0xF) - 7
347
+ mant = v & 0x7
348
+ return math.ldexp(1.0 + mant / 8.0, exp)
349
+
350
+
351
+ def ref_nvfp4(
352
+ modulated: torch.Tensor, *, sm110_contract: bool = False
353
+ ) -> tuple[torch.Tensor, torch.Tensor]:
354
+ rows, dim = modulated.shape
355
+ assert dim % 16 == 0
356
+ packed = torch.zeros((rows, dim // 2), dtype=torch.uint8)
357
+ sf = torch.zeros((swizzled_sf_size(rows, dim),), dtype=torch.uint8)
358
+ cpu = modulated.float().cpu()
359
+ n_blocks = dim // 16
360
+ n_col_blocks = (n_blocks + 3) // 4
361
+ for row in range(rows):
362
+ block_scales: list[float] = []
363
+ for block in range(n_blocks):
364
+ amax = float(cpu[row, block * 16 : (block + 1) * 16].abs().max().item())
365
+ desired = max(amax / 6.0, 1e-12)
366
+ if sm110_contract:
367
+ ue = int(
368
+ torch.tensor(desired, dtype=torch.float32)
369
+ .to(torch.float8_e4m3fn)
370
+ .view(torch.uint8)
371
+ .item()
372
+ )
373
+ else:
374
+ ue = f32_to_ue4m3_ceil(desired)
375
+ rb = row // 128
376
+ ri = row % 128
377
+ cb = block // 4
378
+ ci = block % 4
379
+ out_idx = (rb * n_col_blocks + cb) * 512 + (ri % 32) * 16 + (ri // 32) * 4 + ci
380
+ sf[out_idx] = ue
381
+ block_scales.append(ue4m3_to_f32(ue))
382
+ for p in range(dim // 2):
383
+ i = p * 2
384
+ s0 = block_scales[i // 16]
385
+ s1 = block_scales[(i + 1) // 16]
386
+ convert = f32_to_fp4_e2m1_sm110 if sm110_contract else f32_to_fp4_e2m1
387
+ lo = convert(float(cpu[row, i].item()) / s0 if s0 > 0 else 0.0)
388
+ hi = convert(float(cpu[row, i + 1].item()) / s1 if s1 > 0 else 0.0)
389
+ packed[row, p] = (hi << 4) | (lo & 0x0F)
390
+ return packed, sf
391
+
392
+
393
+ def assert_exact(name: str, got: torch.Tensor, expected: torch.Tensor) -> None:
394
+ got_cpu = got.detach().cpu()
395
+ exp_cpu = expected.detach().cpu()
396
+ if not torch.equal(got_cpu, exp_cpu):
397
+ diff = (got_cpu.to(torch.int16) - exp_cpu.to(torch.int16)).abs()
398
+ raise AssertionError(f"{name} mismatch: nonzero={int((diff != 0).sum())} max={int(diff.max())}")
399
+ print(f"PASS {name}: exact")
400
+
401
+
402
+ def assert_fp8_contract(name: str, got: torch.Tensor, expected: torch.Tensor) -> None:
403
+ diff = (got.float() - expected.float()).abs()
404
+ nonzero = int((diff != 0).sum().item())
405
+ max_abs = float(diff.max().item())
406
+ sorted_diff = diff.flatten().sort().values
407
+ p99_abs = float(sorted_diff[min(sorted_diff.numel() - 1, math.ceil(0.99 * sorted_diff.numel()) - 1)].item())
408
+ cosine = float(torch.nn.functional.cosine_similarity(got.float().flatten(), expected.float().flatten(), dim=0).item())
409
+ max_nonzero = max(8, diff.numel() // 100000)
410
+ if p99_abs != 0.0 or nonzero > max_nonzero:
411
+ raise AssertionError(
412
+ f"{name} mismatch: nonzero={nonzero}/{diff.numel()} max_abs={max_abs} "
413
+ f"p99_abs={p99_abs} cosine={cosine}"
414
+ )
415
+ status = "exact" if nonzero == 0 else "fp8-boundary"
416
+ print(
417
+ f"PASS {name}: {status} nonzero={nonzero}/{diff.numel()} "
418
+ f"max_abs={max_abs:.6f} p99_abs={p99_abs:.6f} cosine={cosine:.8f}"
419
+ )
420
+
421
+
422
+ def run_shape(ops, label: str, rows: int, dim: int, eps: float, reference_ops=None) -> None:
423
+ x, scale, shift, inv_s, act_scale, scale_fp8, shift_fp8, scale_deq, shift_deq = make_case(rows, dim)
424
+
425
+ mod = ref_adaln(x, scale, shift, eps)
426
+ got_fp8 = ops.ada_layer_norm_quant_fp8_bf16(x, scale, shift, act_scale, eps)
427
+ assert_fp8_contract(f"{label}/ada_fp8", got_fp8, quant_fp8(mod, act_scale))
428
+
429
+ # per-token form: one modulation row per activation row; the reference
430
+ # is the same adaln math, broadcasting replaced by row alignment
431
+ scale_pt = (0.1 * torch.randn(rows, dim, device=x.device)).to(torch.bfloat16)
432
+ shift_pt = (0.1 * torch.randn(rows, dim, device=x.device)).to(torch.bfloat16)
433
+ mod_pt = ref_adaln(x, scale_pt, shift_pt, eps)
434
+ got_ptok = ops.ada_layer_norm_quant_fp8_ptok_bf16(x, scale_pt, shift_pt, act_scale, eps)
435
+ assert_fp8_contract(f"{label}/ada_fp8_ptok", got_ptok, quant_fp8(mod_pt, act_scale))
436
+
437
+ # table form: the block's [n_chunks, dim] fp32 table is added to a
438
+ # [rows, n_chunks, dim] bf16 per-token embedding inside the kernel;
439
+ # the reference materializes the chunks the way a host block would
440
+ n_chunks, s_idx, c_idx = 6, 0, 1
441
+ temb_pt = (0.1 * torch.randn(rows, n_chunks, dim, device=x.device)).to(torch.bfloat16)
442
+ table_pt = (torch.randn(n_chunks, dim, device=x.device) / dim**0.5).float()
443
+ shift_tab = (table_pt[s_idx] + temb_pt[:, s_idx].float())
444
+ scale_tab = (table_pt[c_idx] + temb_pt[:, c_idx].float())
445
+ mod_tab = ref_adaln_float_mod(x, scale_tab, shift_tab, eps)
446
+ got_tab = ops.ada_layer_norm_quant_fp8_ptok_table_bf16(
447
+ x, temb_pt, table_pt, act_scale, s_idx, c_idx, eps
448
+ )
449
+ assert_fp8_contract(f"{label}/ada_fp8_ptok_table", got_tab, quant_fp8(mod_tab, act_scale))
450
+
451
+ scale_mod = scale_fp8.float() * scale_deq
452
+ shift_mod = shift_fp8.float() * shift_deq
453
+ mod_fp8 = ref_adaln_float_mod(x, scale_mod, shift_mod, eps)
454
+ got_modfp8 = ops.ada_layer_norm_quant_fp8_modfp8_bf16(
455
+ x, scale_fp8, shift_fp8, scale_deq, shift_deq, act_scale, eps
456
+ )
457
+ assert_fp8_contract(f"{label}/ada_modfp8_fp8", got_modfp8, quant_fp8(mod_fp8, act_scale))
458
+
459
+ awq_ref = mod.float() * inv_s.float()
460
+ got_awq = ops.awq_ada_layer_norm_quant_fp8_bf16(x, scale, shift, inv_s, act_scale, eps)
461
+ assert_fp8_contract(f"{label}/awq_ada_fp8", got_awq, quant_fp8(awq_ref, act_scale))
462
+
463
+ got_noaffine = ops.layer_norm_no_affine_quant_fp8_static_bf16(x, act_scale, eps)
464
+ assert_fp8_contract(f"{label}/no_affine_fp8", got_noaffine, quant_fp8(ref_layer_norm_no_affine(x, eps), act_scale))
465
+
466
+ if dim % 16 == 0 and rows <= 260:
467
+ packed = torch.empty((rows, dim // 2), device=x.device, dtype=torch.uint8)
468
+ sf = torch.zeros((swizzled_sf_size(rows, dim),), device=x.device, dtype=torch.uint8)
469
+ got_packed, got_sf = ops.ada_layer_norm_quant_nvfp4_swizzled_bf16(
470
+ x, scale, shift, eps, packed=packed, sf_swizzled=sf
471
+ )
472
+ sm110_contract = torch.cuda.get_device_capability(0) == (11, 0)
473
+ oracle = reference_ops or ops
474
+ if sm110_contract and hasattr(oracle, "reference_adaln_fp4"):
475
+ exp_packed = torch.empty_like(packed)
476
+ exp_sf = torch.zeros_like(sf)
477
+ oracle.reference_adaln_fp4(
478
+ x, scale, shift, eps, exp_packed, exp_sf
479
+ )
480
+ else:
481
+ exp_packed, exp_sf = ref_nvfp4(
482
+ mod, sm110_contract=sm110_contract
483
+ )
484
+ assert_exact(f"{label}/nvfp4_packed", got_packed, exp_packed)
485
+ assert_exact(f"{label}/nvfp4_sf", got_sf, exp_sf)
486
+
487
+ if torch.cuda.get_device_capability(0) == (11, 0):
488
+ packed.zero_()
489
+ sf.zero_()
490
+ got_ln_packed, got_ln_sf = (
491
+ ops.layer_norm_no_affine_quant_nvfp4_swizzled_bf16(
492
+ x, eps, packed=packed, sf_swizzled=sf
493
+ )
494
+ )
495
+ if hasattr(oracle, "reference_ln_fp4"):
496
+ exp_ln_packed = torch.empty_like(packed)
497
+ exp_ln_sf = torch.zeros_like(sf)
498
+ oracle.reference_ln_fp4(
499
+ x, eps, exp_ln_packed, exp_ln_sf
500
+ )
501
+ else:
502
+ exp_ln_packed, exp_ln_sf = ref_nvfp4(
503
+ ref_layer_norm_no_affine(x, eps), sm110_contract=True
504
+ )
505
+ assert_exact(
506
+ f"{label}/no_affine_nvfp4_packed", got_ln_packed,
507
+ exp_ln_packed,
508
+ )
509
+ assert_exact(
510
+ f"{label}/no_affine_nvfp4_sf", got_ln_sf, exp_ln_sf
511
+ )
512
+
513
+ packed.zero_()
514
+ sf.zero_()
515
+ got_packed2, got_sf2 = ops.ada_layer_norm_quant_nvfp4_swizzled_modfp8_bf16(
516
+ x, scale_fp8, shift_fp8, scale_deq, shift_deq, eps, packed=packed, sf_swizzled=sf
517
+ )
518
+ exp_packed2, exp_sf2 = ref_nvfp4(mod_fp8)
519
+ assert_exact(f"{label}/nvfp4_modfp8_packed", got_packed2, exp_packed2)
520
+ assert_exact(f"{label}/nvfp4_modfp8_sf", got_sf2, exp_sf2)
521
+
522
+
523
+ def run(args) -> None:
524
+ if not torch.cuda.is_available():
525
+ raise SystemExit("CUDA is required")
526
+ torch.manual_seed(2026)
527
+ ops = load_source_ops() if args.backend == "source" else load_installed_ops(args.artifact)
528
+ reference_ops = None
529
+ if args.backend == "installed" and torch.cuda.get_device_capability(0) == (11, 0):
530
+ reference_ops = load_sm110_reference_ops()
531
+ shapes = {
532
+ "decode_action": (16, 2048),
533
+ "wan_video_short": (64, 3072),
534
+ "wan_video_ctx": (256, 3072),
535
+ "wan_video_2k": (2520, 3072),
536
+ "wan_video_4k": (4096, 3072),
537
+ }
538
+ if args.mode == "smoke":
539
+ shapes = {"wan_video_short": shapes["wan_video_short"]}
540
+ for label, (rows, dim) in shapes.items():
541
+ run_shape(ops, label, rows, dim, args.eps, reference_ops)
542
+
543
+ modulation_shapes = {
544
+ "boundary": (1, 1, 48),
545
+ "groot_n17_dit": (1, 41, 1536),
546
+ "groot_legacy_dit": (1, 51, 1536),
547
+ "motus": (1, 360, 3072),
548
+ "video_long": (2, 2520, 3072),
549
+ }
550
+ if args.mode == "smoke":
551
+ modulation_shapes = {"boundary": modulation_shapes["boundary"]}
552
+ for label, (batch, sequence, dim) in modulation_shapes.items():
553
+ params = torch.randn(
554
+ (batch, sequence, 6, dim), device="cuda", dtype=torch.float32
555
+ )
556
+ modulation = torch.randn(
557
+ (6, dim), device="cuda", dtype=torch.float32
558
+ )
559
+ expected = tuple(
560
+ (params[:, :, index, :] + modulation[index]).to(torch.bfloat16)
561
+ for index in range(6)
562
+ )
563
+ out = ops.adaln_modulation6_bf16(params, modulation)
564
+ for index, (got, ref) in enumerate(zip(out, expected, strict=True)):
565
+ if not torch.equal(got, ref):
566
+ diff = (got.float() - ref.float()).abs()
567
+ raise AssertionError(
568
+ f"{label}/adaln_modulation6/out{index}: "
569
+ f"max_abs={diff.max().item()}"
570
+ )
571
+ compiled = torch.compile(
572
+ lambda p, m: ops.adaln_modulation6_bf16(p, m),
573
+ fullgraph=True,
574
+ )
575
+ compiled_out = compiled(params, modulation)
576
+ for index, (got, ref) in enumerate(
577
+ zip(compiled_out, expected, strict=True)
578
+ ):
579
+ if not torch.equal(got, ref):
580
+ raise AssertionError(
581
+ f"{label}/adaln_modulation6_compile/out{index} mismatch"
582
+ )
583
+ print(f"PASS {label}/adaln_modulation6: exact six-output parity")
584
+
585
+
586
+ def main() -> None:
587
+ parser = argparse.ArgumentParser()
588
+ parser.add_argument("--backend", choices=["source", "installed"], default="source")
589
+ parser.add_argument("--artifact", default=None)
590
+ parser.add_argument("--mode", choices=["smoke", "full"], default="full")
591
+ parser.add_argument("--eps", type=float, default=1e-5)
592
+ args = parser.parse_args()
593
+ run(args)
594
+
595
+
596
+ if __name__ == "__main__":
597
+ main()
torch-ext/adaptive_layernorm_producers/__init__.py ADDED
@@ -0,0 +1,455 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """FlashRT adaptive LayerNorm producer kernels for DiT/Wan-style blocks."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import torch
6
+
7
+ from ._ops import add_op_namespace_prefix, ops
8
+
9
+
10
+ def _check_x(x: torch.Tensor) -> None:
11
+ if x.dim() != 2:
12
+ raise RuntimeError("x must have shape (rows, dim)")
13
+ if x.shape[1] % 2 != 0:
14
+ raise RuntimeError("x.shape[1] must be even")
15
+
16
+
17
+ def _check_mod(x: torch.Tensor, scale: torch.Tensor, shift: torch.Tensor) -> None:
18
+ _check_x(x)
19
+ dim = x.shape[1]
20
+ if scale.shape != (dim,) or shift.shape != (dim,):
21
+ raise RuntimeError("scale and shift must have shape (dim,)")
22
+
23
+
24
+ def _check_scalar(scale: torch.Tensor, name: str) -> None:
25
+ if scale.numel() != 1:
26
+ raise RuntimeError(f"{name} must be a scalar tensor")
27
+
28
+
29
+ def swizzled_sf_size(rows: int, dim: int) -> int:
30
+ """Return bytes required by the FlashRT/CUTLASS NVFP4 swizzled scale layout."""
31
+
32
+ if dim % 16 != 0:
33
+ raise RuntimeError("dim must be divisible by 16 for NVFP4 swizzled output")
34
+ n_blocks = dim // 16
35
+ n_row_super = (rows + 127) // 128
36
+ n_col_super = (n_blocks + 3) // 4
37
+ return n_row_super * n_col_super * 128 * 64
38
+
39
+
40
+ def _alloc_fp8(x: torch.Tensor) -> torch.Tensor:
41
+ return torch.empty_like(x, dtype=torch.float8_e4m3fn)
42
+
43
+
44
+ def _alloc_nvfp4(x: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
45
+ rows, dim = x.shape
46
+ packed = torch.empty((rows, dim // 2), device=x.device, dtype=torch.uint8)
47
+ sf = torch.zeros((swizzled_sf_size(rows, dim),), device=x.device, dtype=torch.uint8)
48
+ return packed, sf
49
+
50
+
51
+ @torch.library.register_fake(add_op_namespace_prefix("ada_layer_norm_quant_fp8_bf16"))
52
+ def _ada_layer_norm_quant_fp8_bf16_fake(
53
+ x: torch.Tensor,
54
+ scale: torch.Tensor,
55
+ shift: torch.Tensor,
56
+ act_scale: torch.Tensor,
57
+ eps: float,
58
+ out: torch.Tensor,
59
+ ) -> None:
60
+ _check_mod(x, scale, shift)
61
+ _check_scalar(act_scale, "act_scale")
62
+ if out.shape != x.shape:
63
+ raise RuntimeError("out must have the same shape as x")
64
+ return None
65
+
66
+
67
+ @torch.library.register_fake(add_op_namespace_prefix("ada_layer_norm_quant_fp8_ptok_bf16"))
68
+ def _ada_layer_norm_quant_fp8_ptok_bf16_fake(
69
+ x: torch.Tensor,
70
+ scale: torch.Tensor,
71
+ shift: torch.Tensor,
72
+ act_scale: torch.Tensor,
73
+ eps: float,
74
+ out: torch.Tensor,
75
+ ) -> None:
76
+ _check_x(x)
77
+ if scale.shape != x.shape or shift.shape != x.shape:
78
+ raise RuntimeError(
79
+ "per-token scale and shift must have shape (seq_len, dim)")
80
+ _check_scalar(act_scale, "act_scale")
81
+ if out.shape != x.shape:
82
+ raise RuntimeError("out must have the same shape as x")
83
+ return None
84
+
85
+
86
+ @torch.library.register_fake(add_op_namespace_prefix("ada_layer_norm_quant_fp8_ptok_table_bf16"))
87
+ def _ada_layer_norm_quant_fp8_ptok_table_bf16_fake(
88
+ x: torch.Tensor,
89
+ temb: torch.Tensor,
90
+ table: torch.Tensor,
91
+ act_scale: torch.Tensor,
92
+ shift_idx: int,
93
+ scale_idx: int,
94
+ eps: float,
95
+ out: torch.Tensor,
96
+ ) -> None:
97
+ _check_x(x)
98
+ if temb.dim() != 3 or temb.shape[0] != x.shape[0] or temb.shape[2] != x.shape[1]:
99
+ raise RuntimeError("temb must have shape (seq_len, n_chunks, dim)")
100
+ if table.dim() != 2 or table.shape[0] != temb.shape[1] or table.shape[1] != x.shape[1]:
101
+ raise RuntimeError("table must have shape (n_chunks, dim)")
102
+ _check_scalar(act_scale, "act_scale")
103
+ if out.shape != x.shape:
104
+ raise RuntimeError("out must have the same shape as x")
105
+ return None
106
+
107
+
108
+ @torch.library.register_fake(add_op_namespace_prefix("ada_layer_norm_quant_fp8_modfp8_bf16"))
109
+ def _ada_layer_norm_quant_fp8_modfp8_bf16_fake(
110
+ x: torch.Tensor,
111
+ scale_fp8: torch.Tensor,
112
+ shift_fp8: torch.Tensor,
113
+ scale_deq: torch.Tensor,
114
+ shift_deq: torch.Tensor,
115
+ act_scale: torch.Tensor,
116
+ eps: float,
117
+ out: torch.Tensor,
118
+ ) -> None:
119
+ _check_mod(x, scale_fp8, shift_fp8)
120
+ _check_scalar(scale_deq, "scale_deq")
121
+ _check_scalar(shift_deq, "shift_deq")
122
+ _check_scalar(act_scale, "act_scale")
123
+ if out.shape != x.shape:
124
+ raise RuntimeError("out must have the same shape as x")
125
+ return None
126
+
127
+
128
+ @torch.library.register_fake(add_op_namespace_prefix("awq_ada_layer_norm_quant_fp8_bf16"))
129
+ def _awq_ada_layer_norm_quant_fp8_bf16_fake(
130
+ x: torch.Tensor,
131
+ scale: torch.Tensor,
132
+ shift: torch.Tensor,
133
+ inv_s: torch.Tensor,
134
+ act_scale: torch.Tensor,
135
+ eps: float,
136
+ out: torch.Tensor,
137
+ ) -> None:
138
+ _check_mod(x, scale, shift)
139
+ if inv_s.shape != (x.shape[1],):
140
+ raise RuntimeError("inv_s must have shape (dim,)")
141
+ _check_scalar(act_scale, "act_scale")
142
+ if out.shape != x.shape:
143
+ raise RuntimeError("out must have the same shape as x")
144
+ return None
145
+
146
+
147
+ @torch.library.register_fake(add_op_namespace_prefix("ada_layer_norm_quant_nvfp4_swizzled_bf16"))
148
+ def _ada_layer_norm_quant_nvfp4_swizzled_bf16_fake(
149
+ x: torch.Tensor,
150
+ scale: torch.Tensor,
151
+ shift: torch.Tensor,
152
+ eps: float,
153
+ packed: torch.Tensor,
154
+ sf_swizzled: torch.Tensor,
155
+ ) -> None:
156
+ _check_mod(x, scale, shift)
157
+ rows, dim = x.shape
158
+ if packed.shape != (rows, dim // 2):
159
+ raise RuntimeError("packed must have shape (rows, dim // 2)")
160
+ if sf_swizzled.numel() < swizzled_sf_size(rows, dim):
161
+ raise RuntimeError("sf_swizzled is too small")
162
+ return None
163
+
164
+
165
+ @torch.library.register_fake(add_op_namespace_prefix("ada_layer_norm_quant_nvfp4_swizzled_modfp8_bf16"))
166
+ def _ada_layer_norm_quant_nvfp4_swizzled_modfp8_bf16_fake(
167
+ x: torch.Tensor,
168
+ scale_fp8: torch.Tensor,
169
+ shift_fp8: torch.Tensor,
170
+ scale_deq: torch.Tensor,
171
+ shift_deq: torch.Tensor,
172
+ eps: float,
173
+ packed: torch.Tensor,
174
+ sf_swizzled: torch.Tensor,
175
+ ) -> None:
176
+ _check_mod(x, scale_fp8, shift_fp8)
177
+ _check_scalar(scale_deq, "scale_deq")
178
+ _check_scalar(shift_deq, "shift_deq")
179
+ rows, dim = x.shape
180
+ if packed.shape != (rows, dim // 2):
181
+ raise RuntimeError("packed must have shape (rows, dim // 2)")
182
+ if sf_swizzled.numel() < swizzled_sf_size(rows, dim):
183
+ raise RuntimeError("sf_swizzled is too small")
184
+ return None
185
+
186
+
187
+ @torch.library.register_fake(add_op_namespace_prefix("layer_norm_no_affine_quant_fp8_static_bf16"))
188
+ def _layer_norm_no_affine_quant_fp8_static_bf16_fake(
189
+ x: torch.Tensor,
190
+ act_scale: torch.Tensor,
191
+ eps: float,
192
+ out: torch.Tensor,
193
+ ) -> None:
194
+ _check_x(x)
195
+ _check_scalar(act_scale, "act_scale")
196
+ if out.shape != x.shape:
197
+ raise RuntimeError("out must have the same shape as x")
198
+ return None
199
+
200
+
201
+ @torch.library.register_fake(add_op_namespace_prefix("layer_norm_no_affine_quant_nvfp4_swizzled_bf16"))
202
+ def _layer_norm_no_affine_quant_nvfp4_swizzled_bf16_fake(
203
+ x: torch.Tensor,
204
+ eps: float,
205
+ packed: torch.Tensor,
206
+ sf_swizzled: torch.Tensor,
207
+ ) -> None:
208
+ _check_x(x)
209
+ rows, dim = x.shape
210
+ if packed.shape != (rows, dim // 2):
211
+ raise RuntimeError("packed must have shape (rows, dim // 2)")
212
+ if sf_swizzled.numel() < swizzled_sf_size(rows, dim):
213
+ raise RuntimeError("sf_swizzled is too small")
214
+ return None
215
+
216
+
217
+ def ada_layer_norm_quant_fp8_bf16(
218
+ x: torch.Tensor,
219
+ scale: torch.Tensor,
220
+ shift: torch.Tensor,
221
+ act_scale: torch.Tensor,
222
+ eps: float = 1e-5,
223
+ out: torch.Tensor | None = None,
224
+ ) -> torch.Tensor:
225
+ """Fused no-affine LayerNorm + AdaLN scale/shift + static FP8 quantize."""
226
+
227
+ if out is None:
228
+ out = _alloc_fp8(x)
229
+ ops.ada_layer_norm_quant_fp8_bf16(x, scale, shift, act_scale, float(eps), out)
230
+ return out
231
+
232
+
233
+ def ada_layer_norm_quant_fp8_ptok_bf16(
234
+ x: torch.Tensor,
235
+ scale: torch.Tensor,
236
+ shift: torch.Tensor,
237
+ act_scale: torch.Tensor,
238
+ eps: float = 1e-5,
239
+ out: torch.Tensor | None = None,
240
+ ) -> torch.Tensor:
241
+ """Per-token AdaLN producer: no-affine LayerNorm + [M, D] scale/shift
242
+ modulation + static FP8 quantize, one pass.
243
+
244
+ The per-token form serves hosts whose timestep embedding carries one
245
+ modulation vector per activation row (video DiTs with [B, S, 6, D]
246
+ tables); the broadcast form above cannot express that seam.
247
+ """
248
+
249
+ if out is None:
250
+ out = _alloc_fp8(x)
251
+ ops.ada_layer_norm_quant_fp8_ptok_bf16(
252
+ x, scale, shift, act_scale, float(eps), out)
253
+ return out
254
+
255
+
256
+ def ada_layer_norm_quant_fp8_ptok_table_bf16(
257
+ x: torch.Tensor,
258
+ temb: torch.Tensor,
259
+ table: torch.Tensor,
260
+ act_scale: torch.Tensor,
261
+ shift_idx: int,
262
+ scale_idx: int,
263
+ eps: float = 1e-5,
264
+ out: torch.Tensor | None = None,
265
+ ) -> torch.Tensor:
266
+ """Per-token AdaLN producer, table form.
267
+
268
+ ``temb`` is the host's per-token modulation embedding
269
+ ``[seq_len, n_chunks, dim]`` (cast to BF16 once per call) and
270
+ ``table`` the block's own ``[n_chunks, dim]`` FP32 modulation
271
+ parameter. The table add, chunk selection, no-affine LayerNorm,
272
+ modulation and static FP8 quantize all happen in one pass — the
273
+ per-block six-chunk materialization the host would otherwise pay
274
+ never exists.
275
+ """
276
+
277
+ if out is None:
278
+ out = _alloc_fp8(x)
279
+ ops.ada_layer_norm_quant_fp8_ptok_table_bf16(
280
+ x, temb, table, act_scale, int(shift_idx), int(scale_idx),
281
+ float(eps), out)
282
+ return out
283
+
284
+
285
+ def ada_layer_norm_quant_fp8_modfp8_bf16(
286
+ x: torch.Tensor,
287
+ scale_fp8: torch.Tensor,
288
+ shift_fp8: torch.Tensor,
289
+ scale_deq: torch.Tensor,
290
+ shift_deq: torch.Tensor,
291
+ act_scale: torch.Tensor,
292
+ eps: float = 1e-5,
293
+ out: torch.Tensor | None = None,
294
+ ) -> torch.Tensor:
295
+ """Fused AdaLN producer when modulation vectors are stored in FP8."""
296
+
297
+ if out is None:
298
+ out = _alloc_fp8(x)
299
+ ops.ada_layer_norm_quant_fp8_modfp8_bf16(
300
+ x, scale_fp8, shift_fp8, scale_deq, shift_deq, act_scale, float(eps), out
301
+ )
302
+ return out
303
+
304
+
305
+ def awq_ada_layer_norm_quant_fp8_bf16(
306
+ x: torch.Tensor,
307
+ scale: torch.Tensor,
308
+ shift: torch.Tensor,
309
+ inv_s: torch.Tensor,
310
+ act_scale: torch.Tensor,
311
+ eps: float = 1e-5,
312
+ out: torch.Tensor | None = None,
313
+ ) -> torch.Tensor:
314
+ """Fused AdaLN producer with AWQ/SmoothQuant per-channel activation scale."""
315
+
316
+ if out is None:
317
+ out = _alloc_fp8(x)
318
+ ops.awq_ada_layer_norm_quant_fp8_bf16(x, scale, shift, inv_s, act_scale, float(eps), out)
319
+ return out
320
+
321
+
322
+ def ada_layer_norm_quant_nvfp4_swizzled_bf16(
323
+ x: torch.Tensor,
324
+ scale: torch.Tensor,
325
+ shift: torch.Tensor,
326
+ eps: float = 1e-5,
327
+ packed: torch.Tensor | None = None,
328
+ sf_swizzled: torch.Tensor | None = None,
329
+ ) -> tuple[torch.Tensor, torch.Tensor]:
330
+ """Fused AdaLN producer to NVFP4 packed activations and swizzled scale factors."""
331
+
332
+ if packed is None or sf_swizzled is None:
333
+ packed, sf_swizzled = _alloc_nvfp4(x)
334
+ ops.ada_layer_norm_quant_nvfp4_swizzled_bf16(x, scale, shift, float(eps), packed, sf_swizzled)
335
+ return packed, sf_swizzled
336
+
337
+
338
+ def ada_layer_norm_quant_nvfp4_swizzled_modfp8_bf16(
339
+ x: torch.Tensor,
340
+ scale_fp8: torch.Tensor,
341
+ shift_fp8: torch.Tensor,
342
+ scale_deq: torch.Tensor,
343
+ shift_deq: torch.Tensor,
344
+ eps: float = 1e-5,
345
+ packed: torch.Tensor | None = None,
346
+ sf_swizzled: torch.Tensor | None = None,
347
+ ) -> tuple[torch.Tensor, torch.Tensor]:
348
+ """Fused FP8-modulated AdaLN producer to NVFP4 packed activations."""
349
+
350
+ if packed is None or sf_swizzled is None:
351
+ packed, sf_swizzled = _alloc_nvfp4(x)
352
+ ops.ada_layer_norm_quant_nvfp4_swizzled_modfp8_bf16(
353
+ x, scale_fp8, shift_fp8, scale_deq, shift_deq, float(eps), packed, sf_swizzled
354
+ )
355
+ return packed, sf_swizzled
356
+
357
+
358
+ def layer_norm_no_affine_quant_fp8_static_bf16(
359
+ x: torch.Tensor,
360
+ act_scale: torch.Tensor,
361
+ eps: float = 1e-5,
362
+ out: torch.Tensor | None = None,
363
+ ) -> torch.Tensor:
364
+ """Fused no-affine LayerNorm + static FP8 quantize."""
365
+
366
+ if out is None:
367
+ out = _alloc_fp8(x)
368
+ ops.layer_norm_no_affine_quant_fp8_static_bf16(x, act_scale, float(eps), out)
369
+ return out
370
+
371
+
372
+ def layer_norm_no_affine_quant_nvfp4_swizzled_bf16(
373
+ x: torch.Tensor,
374
+ eps: float = 1e-5,
375
+ packed: torch.Tensor | None = None,
376
+ sf_swizzled: torch.Tensor | None = None,
377
+ ) -> tuple[torch.Tensor, torch.Tensor]:
378
+ """SM110 no-affine LayerNorm producing NVFP4 and CUTLASS SFA."""
379
+ if packed is None or sf_swizzled is None:
380
+ packed, sf_swizzled = _alloc_nvfp4(x)
381
+ ops.layer_norm_no_affine_quant_nvfp4_swizzled_bf16(
382
+ x, float(eps), packed, sf_swizzled
383
+ )
384
+ return packed, sf_swizzled
385
+
386
+
387
+ @torch.library.register_fake(add_op_namespace_prefix("adaln_modulation6_bf16"))
388
+ def _adaln_modulation6_bf16_fake(
389
+ adaln_params: torch.Tensor,
390
+ layer_modulation: torch.Tensor,
391
+ out0: torch.Tensor,
392
+ out1: torch.Tensor,
393
+ out2: torch.Tensor,
394
+ out3: torch.Tensor,
395
+ out4: torch.Tensor,
396
+ out5: torch.Tensor,
397
+ ) -> None:
398
+ if adaln_params.dim() != 4 or adaln_params.shape[2] != 6:
399
+ raise RuntimeError(
400
+ "adaln_params must have shape (batch, sequence, 6, dim)"
401
+ )
402
+ expected = (
403
+ adaln_params.shape[0],
404
+ adaln_params.shape[1],
405
+ adaln_params.shape[3],
406
+ )
407
+ if layer_modulation.shape != (6, expected[2]):
408
+ raise RuntimeError("layer_modulation must have shape (6, dim)")
409
+ for output in (out0, out1, out2, out3, out4, out5):
410
+ if output.shape != expected:
411
+ raise RuntimeError(
412
+ "each output must have shape (batch, sequence, dim)"
413
+ )
414
+ return None
415
+
416
+
417
+ def adaln_modulation6_bf16(
418
+ adaln_params: torch.Tensor,
419
+ layer_modulation: torch.Tensor,
420
+ *,
421
+ out: tuple[torch.Tensor, ...] | None = None,
422
+ ) -> tuple[torch.Tensor, ...]:
423
+ """Add six FP32 AdaLN modulation vectors and return six BF16 tensors."""
424
+
425
+ batch, sequence, _, dim = adaln_params.shape
426
+ if out is None:
427
+ out = tuple(
428
+ torch.empty(
429
+ (batch, sequence, dim),
430
+ device=adaln_params.device,
431
+ dtype=torch.bfloat16,
432
+ )
433
+ for _ in range(6)
434
+ )
435
+ if len(out) != 6:
436
+ raise RuntimeError("out must contain six tensors")
437
+ ops.adaln_modulation6_bf16(
438
+ adaln_params, layer_modulation, *out
439
+ )
440
+ return out
441
+
442
+
443
+ __all__ = [
444
+ "ada_layer_norm_quant_fp8_bf16",
445
+ "ada_layer_norm_quant_fp8_ptok_bf16",
446
+ "ada_layer_norm_quant_fp8_ptok_table_bf16",
447
+ "ada_layer_norm_quant_fp8_modfp8_bf16",
448
+ "awq_ada_layer_norm_quant_fp8_bf16",
449
+ "ada_layer_norm_quant_nvfp4_swizzled_bf16",
450
+ "ada_layer_norm_quant_nvfp4_swizzled_modfp8_bf16",
451
+ "layer_norm_no_affine_quant_fp8_static_bf16",
452
+ "layer_norm_no_affine_quant_nvfp4_swizzled_bf16",
453
+ "adaln_modulation6_bf16",
454
+ "swizzled_sf_size",
455
+ ]
torch-ext/torch_binding.cpp ADDED
@@ -0,0 +1,586 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // SPDX-License-Identifier: Apache-2.0
2
+
3
+ #include <torch/all.h>
4
+ #include <torch/library.h>
5
+
6
+ #if defined(CUDA_KERNEL)
7
+ #include <ATen/cuda/CUDAContext.h>
8
+ #include <c10/cuda/CUDAGuard.h>
9
+ #endif
10
+
11
+ #include "ada_layer_norm_fp8.cuh"
12
+ #include "adaln_modulation6.cuh"
13
+ #include "dit_layer_norm_fp8.cuh"
14
+ #include "registration.h"
15
+ #include "sm110_fp4_dispatch.cuh"
16
+
17
+ flash_rt::adaln_producers::hub::AdaLayerNormFp4Dispatch
18
+ flash_rt::adaln_producers::hub::ada_layer_norm_fp4_dispatch = nullptr;
19
+ flash_rt::adaln_producers::hub::LayerNormFp4Dispatch
20
+ flash_rt::adaln_producers::hub::layer_norm_fp4_dispatch = nullptr;
21
+
22
+ namespace {
23
+
24
+ void check_cuda_contiguous(torch::Tensor const& tensor, const char* name) {
25
+ TORCH_CHECK(tensor.is_cuda(), name, " must be a CUDA tensor");
26
+ TORCH_CHECK(tensor.is_contiguous(), name, " must be contiguous");
27
+ }
28
+
29
+ void check_bf16(torch::Tensor const& tensor, const char* name) {
30
+ check_cuda_contiguous(tensor, name);
31
+ TORCH_CHECK(tensor.scalar_type() == torch::kBFloat16,
32
+ name, " must have dtype torch.bfloat16");
33
+ }
34
+
35
+ void check_fp32(torch::Tensor const& tensor, const char* name) {
36
+ check_cuda_contiguous(tensor, name);
37
+ TORCH_CHECK(tensor.scalar_type() == torch::kFloat32,
38
+ name, " must have dtype torch.float32");
39
+ }
40
+
41
+ void check_fp8(torch::Tensor const& tensor, const char* name) {
42
+ check_cuda_contiguous(tensor, name);
43
+ TORCH_CHECK(tensor.scalar_type() == torch::kFloat8_e4m3fn,
44
+ name, " must have dtype torch.float8_e4m3fn");
45
+ }
46
+
47
+ void check_u8(torch::Tensor const& tensor, const char* name) {
48
+ check_cuda_contiguous(tensor, name);
49
+ TORCH_CHECK(tensor.scalar_type() == torch::kUInt8,
50
+ name, " must have dtype torch.uint8");
51
+ }
52
+
53
+ void check_same_device(torch::Tensor const& a,
54
+ torch::Tensor const& b,
55
+ const char* a_name,
56
+ const char* b_name) {
57
+ TORCH_CHECK(a.get_device() == b.get_device(),
58
+ a_name, " and ", b_name, " must be on the same CUDA device");
59
+ }
60
+
61
+ void check_x(torch::Tensor const& x) {
62
+ check_bf16(x, "x");
63
+ TORCH_CHECK(x.dim() == 2, "x must have shape (rows, dim)");
64
+ TORCH_CHECK(x.size(0) > 0 && x.size(1) > 0,
65
+ "x rows and dim must be positive");
66
+ TORCH_CHECK((x.size(1) % 2) == 0, "x.shape[1] must be even");
67
+ }
68
+
69
+ void check_bf16_mod(torch::Tensor const& x,
70
+ torch::Tensor const& scale,
71
+ torch::Tensor const& shift) {
72
+ check_bf16(scale, "scale");
73
+ check_bf16(shift, "shift");
74
+ TORCH_CHECK(scale.dim() == 1 && scale.size(0) == x.size(1),
75
+ "scale must have shape (dim,)");
76
+ TORCH_CHECK(shift.dim() == 1 && shift.size(0) == x.size(1),
77
+ "shift must have shape (dim,)");
78
+ check_same_device(x, scale, "x", "scale");
79
+ check_same_device(x, shift, "x", "shift");
80
+ }
81
+
82
+ void check_fp8_mod(torch::Tensor const& x,
83
+ torch::Tensor const& scale,
84
+ torch::Tensor const& shift,
85
+ torch::Tensor const& scale_deq,
86
+ torch::Tensor const& shift_deq) {
87
+ check_fp8(scale, "scale_fp8");
88
+ check_fp8(shift, "shift_fp8");
89
+ check_fp32(scale_deq, "scale_deq");
90
+ check_fp32(shift_deq, "shift_deq");
91
+ TORCH_CHECK(scale.dim() == 1 && scale.size(0) == x.size(1),
92
+ "scale_fp8 must have shape (dim,)");
93
+ TORCH_CHECK(shift.dim() == 1 && shift.size(0) == x.size(1),
94
+ "shift_fp8 must have shape (dim,)");
95
+ TORCH_CHECK(scale_deq.numel() == 1, "scale_deq must be a scalar tensor");
96
+ TORCH_CHECK(shift_deq.numel() == 1, "shift_deq must be a scalar tensor");
97
+ check_same_device(x, scale, "x", "scale_fp8");
98
+ check_same_device(x, shift, "x", "shift_fp8");
99
+ check_same_device(x, scale_deq, "x", "scale_deq");
100
+ check_same_device(x, shift_deq, "x", "shift_deq");
101
+ }
102
+
103
+ void check_act_scale(torch::Tensor const& x, torch::Tensor const& act_scale) {
104
+ check_fp32(act_scale, "act_scale");
105
+ TORCH_CHECK(act_scale.numel() == 1, "act_scale must be a scalar tensor");
106
+ check_same_device(x, act_scale, "x", "act_scale");
107
+ }
108
+
109
+ int64_t swizzled_sf_bytes(int64_t rows, int64_t dim) {
110
+ TORCH_CHECK((dim % 16) == 0, "dim must be divisible by 16 for NVFP4 swizzled output");
111
+ const int64_t blocks = dim / 16;
112
+ const int64_t row_super = (rows + 127) / 128;
113
+ const int64_t col_super = (blocks + 3) / 4;
114
+ return row_super * col_super * 128 * 64;
115
+ }
116
+
117
+ void check_fp8_out(torch::Tensor const& x, torch::Tensor const& out) {
118
+ check_fp8(out, "out");
119
+ TORCH_CHECK(out.sizes() == x.sizes(), "out must have the same shape as x");
120
+ check_same_device(x, out, "x", "out");
121
+ }
122
+
123
+ void check_nvfp4_out(torch::Tensor const& x,
124
+ torch::Tensor const& packed,
125
+ torch::Tensor const& sf_swizzled) {
126
+ check_u8(packed, "packed");
127
+ check_u8(sf_swizzled, "sf_swizzled");
128
+ TORCH_CHECK((x.size(1) % 16) == 0, "x.shape[1] must be divisible by 16");
129
+ TORCH_CHECK(packed.dim() == 2 && packed.size(0) == x.size(0) &&
130
+ packed.size(1) == x.size(1) / 2,
131
+ "packed must have shape (rows, dim // 2)");
132
+ TORCH_CHECK(sf_swizzled.numel() >= swizzled_sf_bytes(x.size(0), x.size(1)),
133
+ "sf_swizzled is too small for the swizzled NVFP4 scale layout");
134
+ check_same_device(x, packed, "x", "packed");
135
+ check_same_device(x, sf_swizzled, "x", "sf_swizzled");
136
+ }
137
+
138
+ } // namespace
139
+
140
+ void ada_layer_norm_quant_fp8_bf16(
141
+ torch::Tensor const& x,
142
+ torch::Tensor const& scale,
143
+ torch::Tensor const& shift,
144
+ torch::Tensor const& act_scale,
145
+ double eps,
146
+ torch::Tensor& out) {
147
+ check_x(x);
148
+ check_bf16_mod(x, scale, shift);
149
+ check_act_scale(x, act_scale);
150
+ check_fp8_out(x, out);
151
+
152
+ #if defined(CUDA_KERNEL)
153
+ at::cuda::CUDAGuard device_guard(x.device());
154
+ auto stream = at::cuda::getCurrentCUDAStream(x.get_device()).stream();
155
+ flash_rt::quantize::ada_layer_norm_fp8(
156
+ x.data_ptr(),
157
+ scale.data_ptr(),
158
+ shift.data_ptr(),
159
+ out.data_ptr(),
160
+ static_cast<const float*>(act_scale.data_ptr()),
161
+ static_cast<int>(x.size(0)),
162
+ static_cast<int>(x.size(1)),
163
+ static_cast<float>(eps),
164
+ stream);
165
+ #else
166
+ TORCH_CHECK(false, "adaptive-layernorm-producers was not built with CUDA support");
167
+ #endif
168
+ }
169
+
170
+ void check_bf16_mod_ptok(torch::Tensor const& x,
171
+ torch::Tensor const& scale,
172
+ torch::Tensor const& shift) {
173
+ check_bf16(scale, "scale");
174
+ check_bf16(shift, "shift");
175
+ TORCH_CHECK(scale.sizes() == x.sizes(),
176
+ "per-token scale must have shape (seq_len, dim)");
177
+ TORCH_CHECK(shift.sizes() == x.sizes(),
178
+ "per-token shift must have shape (seq_len, dim)");
179
+ check_same_device(x, scale, "x", "scale");
180
+ check_same_device(x, shift, "x", "shift");
181
+ }
182
+
183
+ void ada_layer_norm_quant_fp8_ptok_bf16(
184
+ torch::Tensor const& x,
185
+ torch::Tensor const& scale,
186
+ torch::Tensor const& shift,
187
+ torch::Tensor const& act_scale,
188
+ double eps,
189
+ torch::Tensor& out) {
190
+ check_x(x);
191
+ check_bf16_mod_ptok(x, scale, shift);
192
+ check_act_scale(x, act_scale);
193
+ check_fp8_out(x, out);
194
+
195
+ #if defined(CUDA_KERNEL)
196
+ at::cuda::CUDAGuard device_guard(x.device());
197
+ auto stream = at::cuda::getCurrentCUDAStream(x.get_device()).stream();
198
+ flash_rt::quantize::ada_layer_norm_ptok_fp8(
199
+ x.data_ptr(),
200
+ scale.data_ptr(),
201
+ shift.data_ptr(),
202
+ out.data_ptr(),
203
+ static_cast<const float*>(act_scale.data_ptr()),
204
+ static_cast<int>(x.size(0)),
205
+ static_cast<int>(x.size(1)),
206
+ static_cast<float>(eps),
207
+ stream);
208
+ #else
209
+ TORCH_CHECK(false, "adaptive-layernorm-producers was not built with CUDA support");
210
+ #endif
211
+ }
212
+
213
+ void ada_layer_norm_quant_fp8_ptok_table_bf16(
214
+ torch::Tensor const& x,
215
+ torch::Tensor const& temb,
216
+ torch::Tensor const& table,
217
+ torch::Tensor const& act_scale,
218
+ int64_t shift_idx,
219
+ int64_t scale_idx,
220
+ double eps,
221
+ torch::Tensor& out) {
222
+ check_x(x);
223
+ check_bf16(temb, "temb");
224
+ check_cuda_contiguous(temb, "temb");
225
+ check_fp32(table, "table");
226
+ check_cuda_contiguous(table, "table");
227
+ TORCH_CHECK(temb.dim() == 3 && temb.size(0) == x.size(0) &&
228
+ temb.size(2) == x.size(1),
229
+ "temb must have shape (seq_len, n_chunks, dim)");
230
+ const int64_t n_chunks = temb.size(1);
231
+ TORCH_CHECK(table.dim() == 2 && table.size(0) == n_chunks &&
232
+ table.size(1) == x.size(1),
233
+ "table must have shape (n_chunks, dim)");
234
+ TORCH_CHECK(shift_idx >= 0 && shift_idx < n_chunks &&
235
+ scale_idx >= 0 && scale_idx < n_chunks,
236
+ "chunk indices must lie in [0, n_chunks)");
237
+ check_act_scale(x, act_scale);
238
+ check_fp8_out(x, out);
239
+
240
+ #if defined(CUDA_KERNEL)
241
+ at::cuda::CUDAGuard device_guard(x.device());
242
+ auto stream = at::cuda::getCurrentCUDAStream(x.get_device()).stream();
243
+ flash_rt::quantize::ada_layer_norm_ptok_table_fp8(
244
+ x.data_ptr(),
245
+ temb.data_ptr(),
246
+ static_cast<const float*>(table.data_ptr()),
247
+ out.data_ptr(),
248
+ static_cast<const float*>(act_scale.data_ptr()),
249
+ static_cast<int>(x.size(0)),
250
+ static_cast<int>(x.size(1)),
251
+ static_cast<int>(n_chunks),
252
+ static_cast<int>(shift_idx),
253
+ static_cast<int>(scale_idx),
254
+ static_cast<float>(eps),
255
+ stream);
256
+ #else
257
+ TORCH_CHECK(false, "adaptive-layernorm-producers was not built with CUDA support");
258
+ #endif
259
+ }
260
+
261
+ void ada_layer_norm_quant_fp8_modfp8_bf16(
262
+ torch::Tensor const& x,
263
+ torch::Tensor const& scale_fp8,
264
+ torch::Tensor const& shift_fp8,
265
+ torch::Tensor const& scale_deq,
266
+ torch::Tensor const& shift_deq,
267
+ torch::Tensor const& act_scale,
268
+ double eps,
269
+ torch::Tensor& out) {
270
+ check_x(x);
271
+ check_fp8_mod(x, scale_fp8, shift_fp8, scale_deq, shift_deq);
272
+ check_act_scale(x, act_scale);
273
+ check_fp8_out(x, out);
274
+
275
+ #if defined(CUDA_KERNEL)
276
+ at::cuda::CUDAGuard device_guard(x.device());
277
+ auto stream = at::cuda::getCurrentCUDAStream(x.get_device()).stream();
278
+ flash_rt::quantize::ada_layer_norm_fp8_modfp8(
279
+ x.data_ptr(),
280
+ scale_fp8.data_ptr(),
281
+ shift_fp8.data_ptr(),
282
+ static_cast<const float*>(scale_deq.data_ptr()),
283
+ static_cast<const float*>(shift_deq.data_ptr()),
284
+ out.data_ptr(),
285
+ static_cast<const float*>(act_scale.data_ptr()),
286
+ static_cast<int>(x.size(0)),
287
+ static_cast<int>(x.size(1)),
288
+ static_cast<float>(eps),
289
+ stream);
290
+ #else
291
+ TORCH_CHECK(false, "adaptive-layernorm-producers was not built with CUDA support");
292
+ #endif
293
+ }
294
+
295
+ void awq_ada_layer_norm_quant_fp8_bf16(
296
+ torch::Tensor const& x,
297
+ torch::Tensor const& scale,
298
+ torch::Tensor const& shift,
299
+ torch::Tensor const& inv_s,
300
+ torch::Tensor const& act_scale,
301
+ double eps,
302
+ torch::Tensor& out) {
303
+ check_x(x);
304
+ check_bf16_mod(x, scale, shift);
305
+ check_bf16(inv_s, "inv_s");
306
+ TORCH_CHECK(inv_s.dim() == 1 && inv_s.size(0) == x.size(1),
307
+ "inv_s must have shape (dim,)");
308
+ check_same_device(x, inv_s, "x", "inv_s");
309
+ check_act_scale(x, act_scale);
310
+ check_fp8_out(x, out);
311
+
312
+ #if defined(CUDA_KERNEL)
313
+ at::cuda::CUDAGuard device_guard(x.device());
314
+ auto stream = at::cuda::getCurrentCUDAStream(x.get_device()).stream();
315
+ flash_rt::quantize::awq_ada_layer_norm_fp8(
316
+ x.data_ptr(),
317
+ scale.data_ptr(),
318
+ shift.data_ptr(),
319
+ inv_s.data_ptr(),
320
+ out.data_ptr(),
321
+ static_cast<const float*>(act_scale.data_ptr()),
322
+ static_cast<int>(x.size(0)),
323
+ static_cast<int>(x.size(1)),
324
+ static_cast<float>(eps),
325
+ stream);
326
+ #else
327
+ TORCH_CHECK(false, "adaptive-layernorm-producers was not built with CUDA support");
328
+ #endif
329
+ }
330
+
331
+ void ada_layer_norm_quant_nvfp4_swizzled_bf16(
332
+ torch::Tensor const& x,
333
+ torch::Tensor const& scale,
334
+ torch::Tensor const& shift,
335
+ double eps,
336
+ torch::Tensor& packed,
337
+ torch::Tensor& sf_swizzled) {
338
+ check_x(x);
339
+ check_bf16_mod(x, scale, shift);
340
+ check_nvfp4_out(x, packed, sf_swizzled);
341
+
342
+ #if defined(CUDA_KERNEL)
343
+ at::cuda::CUDAGuard device_guard(x.device());
344
+ auto stream = at::cuda::getCurrentCUDAStream(x.get_device()).stream();
345
+ auto const* props = at::cuda::getDeviceProperties(x.get_device());
346
+ if (props->major == 11 && props->minor == 0) {
347
+ TORCH_CHECK(
348
+ flash_rt::adaln_producers::hub::ada_layer_norm_fp4_dispatch != nullptr,
349
+ "SM110 AdaLayerNorm-to-FP4 source is not present in this build");
350
+ const int rc =
351
+ flash_rt::adaln_producers::hub::ada_layer_norm_fp4_dispatch(
352
+ x.data_ptr(), scale.data_ptr(), shift.data_ptr(),
353
+ packed.data_ptr(), sf_swizzled.data_ptr(),
354
+ static_cast<int>(x.size(0)), static_cast<int>(x.size(1)),
355
+ static_cast<float>(eps), stream);
356
+ TORCH_CHECK(rc == 0,
357
+ "ada_layer_norm_quant_nvfp4_swizzled_bf16 failed with rc=",
358
+ rc);
359
+ return;
360
+ }
361
+ flash_rt::quantize::ada_layer_norm_nvfp4_swizzled(
362
+ x.data_ptr(),
363
+ scale.data_ptr(),
364
+ shift.data_ptr(),
365
+ packed.data_ptr(),
366
+ sf_swizzled.data_ptr(),
367
+ static_cast<int>(x.size(0)),
368
+ static_cast<int>(x.size(1)),
369
+ static_cast<float>(eps),
370
+ stream);
371
+ #else
372
+ TORCH_CHECK(false, "adaptive-layernorm-producers was not built with CUDA support");
373
+ #endif
374
+ }
375
+
376
+ void layer_norm_no_affine_quant_nvfp4_swizzled_bf16(
377
+ torch::Tensor const& x,
378
+ double eps,
379
+ torch::Tensor& packed,
380
+ torch::Tensor& sf_swizzled) {
381
+ check_x(x);
382
+ check_nvfp4_out(x, packed, sf_swizzled);
383
+
384
+ #if defined(CUDA_KERNEL)
385
+ at::cuda::CUDAGuard device_guard(x.device());
386
+ auto const* props = at::cuda::getDeviceProperties(x.get_device());
387
+ TORCH_CHECK(props->major == 11 && props->minor == 0,
388
+ "layer_norm_no_affine_quant_nvfp4_swizzled_bf16 currently "
389
+ "requires SM110; got SM", props->major, props->minor);
390
+ TORCH_CHECK(
391
+ flash_rt::adaln_producers::hub::layer_norm_fp4_dispatch != nullptr,
392
+ "SM110 LayerNorm-to-FP4 source is not present in this build");
393
+ auto stream = at::cuda::getCurrentCUDAStream(x.get_device()).stream();
394
+ const int rc = flash_rt::adaln_producers::hub::layer_norm_fp4_dispatch(
395
+ x.data_ptr(), packed.data_ptr(), sf_swizzled.data_ptr(),
396
+ static_cast<int>(x.size(0)), static_cast<int>(x.size(1)),
397
+ static_cast<float>(eps), stream);
398
+ TORCH_CHECK(
399
+ rc == 0,
400
+ "layer_norm_no_affine_quant_nvfp4_swizzled_bf16 failed with rc=", rc);
401
+ #else
402
+ TORCH_CHECK(false,
403
+ "adaptive-layernorm-producers was not built with CUDA support");
404
+ #endif
405
+ }
406
+
407
+ void ada_layer_norm_quant_nvfp4_swizzled_modfp8_bf16(
408
+ torch::Tensor const& x,
409
+ torch::Tensor const& scale_fp8,
410
+ torch::Tensor const& shift_fp8,
411
+ torch::Tensor const& scale_deq,
412
+ torch::Tensor const& shift_deq,
413
+ double eps,
414
+ torch::Tensor& packed,
415
+ torch::Tensor& sf_swizzled) {
416
+ check_x(x);
417
+ check_fp8_mod(x, scale_fp8, shift_fp8, scale_deq, shift_deq);
418
+ check_nvfp4_out(x, packed, sf_swizzled);
419
+
420
+ #if defined(CUDA_KERNEL)
421
+ at::cuda::CUDAGuard device_guard(x.device());
422
+ auto stream = at::cuda::getCurrentCUDAStream(x.get_device()).stream();
423
+ flash_rt::quantize::ada_layer_norm_nvfp4_swizzled_modfp8(
424
+ x.data_ptr(),
425
+ scale_fp8.data_ptr(),
426
+ shift_fp8.data_ptr(),
427
+ static_cast<const float*>(scale_deq.data_ptr()),
428
+ static_cast<const float*>(shift_deq.data_ptr()),
429
+ packed.data_ptr(),
430
+ sf_swizzled.data_ptr(),
431
+ static_cast<int>(x.size(0)),
432
+ static_cast<int>(x.size(1)),
433
+ static_cast<float>(eps),
434
+ stream);
435
+ #else
436
+ TORCH_CHECK(false, "adaptive-layernorm-producers was not built with CUDA support");
437
+ #endif
438
+ }
439
+
440
+ void layer_norm_no_affine_quant_fp8_static_bf16(
441
+ torch::Tensor const& x,
442
+ torch::Tensor const& act_scale,
443
+ double eps,
444
+ torch::Tensor& out) {
445
+ check_x(x);
446
+ check_act_scale(x, act_scale);
447
+ check_fp8_out(x, out);
448
+
449
+ #if defined(CUDA_KERNEL)
450
+ at::cuda::CUDAGuard device_guard(x.device());
451
+ auto stream = at::cuda::getCurrentCUDAStream(x.get_device()).stream();
452
+ flash_rt::adaln_producers::layer_norm_no_affine_fp8_static_bf16(
453
+ x.data_ptr(),
454
+ out.data_ptr(),
455
+ static_cast<const float*>(act_scale.data_ptr()),
456
+ static_cast<int>(x.size(0)),
457
+ static_cast<int>(x.size(1)),
458
+ static_cast<float>(eps),
459
+ stream);
460
+ #else
461
+ TORCH_CHECK(false, "adaptive-layernorm-producers was not built with CUDA support");
462
+ #endif
463
+ }
464
+
465
+ void adaln_modulation6_bf16(
466
+ torch::Tensor const& adaln_params,
467
+ torch::Tensor const& layer_modulation,
468
+ torch::Tensor& out0,
469
+ torch::Tensor& out1,
470
+ torch::Tensor& out2,
471
+ torch::Tensor& out3,
472
+ torch::Tensor& out4,
473
+ torch::Tensor& out5) {
474
+ check_fp32(adaln_params, "adaln_params");
475
+ check_fp32(layer_modulation, "layer_modulation");
476
+ TORCH_CHECK(
477
+ adaln_params.dim() == 4 && adaln_params.size(2) == 6,
478
+ "adaln_params must have shape (batch, sequence, 6, dim)");
479
+ const auto batch = adaln_params.size(0);
480
+ const auto sequence = adaln_params.size(1);
481
+ const auto dim = adaln_params.size(3);
482
+ TORCH_CHECK(batch > 0 && sequence > 0 && dim > 0,
483
+ "batch, sequence and dim must be positive");
484
+ TORCH_CHECK(layer_modulation.dim() == 2 &&
485
+ layer_modulation.size(0) == 6 &&
486
+ layer_modulation.size(1) == dim,
487
+ "layer_modulation must have shape (6, dim)");
488
+ check_same_device(
489
+ adaln_params, layer_modulation, "adaln_params", "layer_modulation");
490
+ torch::Tensor* outputs[] = {&out0, &out1, &out2, &out3, &out4, &out5};
491
+ for (int index = 0; index < 6; ++index) {
492
+ const std::string name = "out" + std::to_string(index);
493
+ check_bf16(*outputs[index], name.c_str());
494
+ TORCH_CHECK(
495
+ outputs[index]->dim() == 3 &&
496
+ outputs[index]->size(0) == batch &&
497
+ outputs[index]->size(1) == sequence &&
498
+ outputs[index]->size(2) == dim,
499
+ name, " must have shape (batch, sequence, dim)");
500
+ check_same_device(
501
+ adaln_params, *outputs[index], "adaln_params", name.c_str());
502
+ }
503
+
504
+ #if defined(CUDA_KERNEL)
505
+ at::cuda::CUDAGuard device_guard(adaln_params.device());
506
+ auto stream =
507
+ at::cuda::getCurrentCUDAStream(adaln_params.get_device()).stream();
508
+ flash_rt::adaln_producers::adaln_modulation6_bf16(
509
+ adaln_params.data_ptr<float>(),
510
+ layer_modulation.data_ptr<float>(),
511
+ out0.data_ptr(),
512
+ out1.data_ptr(),
513
+ out2.data_ptr(),
514
+ out3.data_ptr(),
515
+ out4.data_ptr(),
516
+ out5.data_ptr(),
517
+ static_cast<int>(batch),
518
+ static_cast<int>(sequence),
519
+ static_cast<int>(dim),
520
+ stream);
521
+ #else
522
+ TORCH_CHECK(false, "adaptive-layernorm-producers was not built with CUDA support");
523
+ #endif
524
+ }
525
+
526
+ TORCH_LIBRARY_EXPAND(TORCH_EXTENSION_NAME, ops) {
527
+ ops.def("ada_layer_norm_quant_fp8_bf16("
528
+ "Tensor x, Tensor scale, Tensor shift, Tensor act_scale, float eps, Tensor! out) -> ()");
529
+ ops.def("ada_layer_norm_quant_fp8_ptok_bf16("
530
+ "Tensor x, Tensor scale, Tensor shift, Tensor act_scale, float eps, Tensor! out) -> ()");
531
+ ops.def("ada_layer_norm_quant_fp8_ptok_table_bf16("
532
+ "Tensor x, Tensor temb, Tensor table, Tensor act_scale, "
533
+ "int shift_idx, int scale_idx, float eps, Tensor! out) -> ()");
534
+ ops.def("ada_layer_norm_quant_fp8_modfp8_bf16("
535
+ "Tensor x, Tensor scale_fp8, Tensor shift_fp8, Tensor scale_deq, Tensor shift_deq, "
536
+ "Tensor act_scale, float eps, Tensor! out) -> ()");
537
+ ops.def("awq_ada_layer_norm_quant_fp8_bf16("
538
+ "Tensor x, Tensor scale, Tensor shift, Tensor inv_s, Tensor act_scale, float eps, Tensor! out) -> ()");
539
+ ops.def("ada_layer_norm_quant_nvfp4_swizzled_bf16("
540
+ "Tensor x, Tensor scale, Tensor shift, float eps, Tensor! packed, Tensor! sf_swizzled) -> ()");
541
+ ops.def("ada_layer_norm_quant_nvfp4_swizzled_modfp8_bf16("
542
+ "Tensor x, Tensor scale_fp8, Tensor shift_fp8, Tensor scale_deq, Tensor shift_deq, "
543
+ "float eps, Tensor! packed, Tensor! sf_swizzled) -> ()");
544
+ ops.def("layer_norm_no_affine_quant_nvfp4_swizzled_bf16("
545
+ "Tensor x, float eps, Tensor! packed, Tensor! sf_swizzled) -> ()");
546
+ ops.def("layer_norm_no_affine_quant_fp8_static_bf16("
547
+ "Tensor x, Tensor act_scale, float eps, Tensor! out) -> ()");
548
+ ops.def("adaln_modulation6_bf16("
549
+ "Tensor adaln_params, Tensor layer_modulation, "
550
+ "Tensor! out0, Tensor! out1, Tensor! out2, "
551
+ "Tensor! out3, Tensor! out4, Tensor! out5) -> ()");
552
+ #if defined(CUDA_KERNEL)
553
+ ops.impl("ada_layer_norm_quant_fp8_bf16",
554
+ torch::kCUDA,
555
+ &ada_layer_norm_quant_fp8_bf16);
556
+ ops.impl("ada_layer_norm_quant_fp8_ptok_bf16",
557
+ torch::kCUDA,
558
+ &ada_layer_norm_quant_fp8_ptok_bf16);
559
+ ops.impl("ada_layer_norm_quant_fp8_ptok_table_bf16",
560
+ torch::kCUDA,
561
+ &ada_layer_norm_quant_fp8_ptok_table_bf16);
562
+ ops.impl("ada_layer_norm_quant_fp8_modfp8_bf16",
563
+ torch::kCUDA,
564
+ &ada_layer_norm_quant_fp8_modfp8_bf16);
565
+ ops.impl("awq_ada_layer_norm_quant_fp8_bf16",
566
+ torch::kCUDA,
567
+ &awq_ada_layer_norm_quant_fp8_bf16);
568
+ ops.impl("ada_layer_norm_quant_nvfp4_swizzled_bf16",
569
+ torch::kCUDA,
570
+ &ada_layer_norm_quant_nvfp4_swizzled_bf16);
571
+ ops.impl("ada_layer_norm_quant_nvfp4_swizzled_modfp8_bf16",
572
+ torch::kCUDA,
573
+ &ada_layer_norm_quant_nvfp4_swizzled_modfp8_bf16);
574
+ ops.impl("layer_norm_no_affine_quant_nvfp4_swizzled_bf16",
575
+ torch::kCUDA,
576
+ &layer_norm_no_affine_quant_nvfp4_swizzled_bf16);
577
+ ops.impl("layer_norm_no_affine_quant_fp8_static_bf16",
578
+ torch::kCUDA,
579
+ &layer_norm_no_affine_quant_fp8_static_bf16);
580
+ ops.impl("adaln_modulation6_bf16",
581
+ torch::kCUDA,
582
+ &adaln_modulation6_bf16);
583
+ #endif
584
+ }
585
+
586
+ REGISTER_EXTENSION(TORCH_EXTENSION_NAME)