Promote latest kernel artifacts to main
Browse files- CARD.md +65 -0
- README.md +148 -6
- SYNC.md +19 -0
- benchmarks/README.md +17 -0
- benchmarks/native_binding.cpp +22 -0
- build.toml +50 -0
- build/torch211-cxx11-cu130-aarch64-linux/__init__.py +32 -0
- build/torch211-cxx11-cu130-aarch64-linux/{_adaptive_layernorm_producers_cuda_7781728.abi3.so → _adaptive_layernorm_producers_cuda_8a66d8b.abi3.so} +2 -2
- build/torch211-cxx11-cu130-aarch64-linux/_ops.py +3 -3
- build/torch211-cxx11-cu130-aarch64-linux/metadata.json +5 -10
- csrc/ada_layer_norm_fp8.cu +666 -0
- csrc/ada_layer_norm_fp8.cuh +102 -0
- csrc/ada_layer_norm_fp8_ptok.cu +254 -0
- csrc/adaln_modulation6.cu +77 -0
- csrc/adaln_modulation6.cuh +25 -0
- csrc/dit_layer_norm_fp8.cu +124 -0
- csrc/dit_layer_norm_fp8.cuh +19 -0
- csrc/dit_norm_fp4_sfa.cu +208 -0
- csrc/dit_norm_fp4_sfa.cuh +33 -0
- csrc/sm110_fp4_dispatch.cu +20 -0
- csrc/sm110_fp4_dispatch.cuh +19 -0
- examples/README.md +10 -0
- examples/basic_usage.py +25 -0
- flake.nix +17 -0
- tests/README.md +16 -0
- tests/native_reference/dit_bf16.cu +315 -0
- tests/sm110_reference_binding.cpp +64 -0
- tests/test_adaptive_layernorm_producers.py +597 -0
- torch-ext/adaptive_layernorm_producers/__init__.py +455 -0
- torch-ext/torch_binding.cpp +586 -0
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 |
-
#
|
| 2 |
|
| 3 |
-
|
| 4 |
-
|
| 5 |
|
| 6 |
-
|
| 7 |
|
| 8 |
-
|
| 9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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:
|
| 3 |
-
size
|
|
|
|
| 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
|
| 3 |
-
ops = torch.ops.
|
| 4 |
|
| 5 |
def add_op_namespace_prefix(op_name: str):
|
| 6 |
-
return f"
|
|
|
|
| 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": "
|
| 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": "
|
| 18 |
-
"
|
| 19 |
-
"_ops.py": "
|
| 20 |
"adaptive_layernorm_producers/__init__.py": "v6p5XMfQzddhi1fLSAw4HX9CyS0rQsidvu9VsT01xi4="
|
| 21 |
}
|
| 22 |
},
|
| 23 |
"provenance": {
|
| 24 |
"kernel": {
|
| 25 |
-
"sha": "
|
| 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)
|