File size: 6,032 Bytes
9022070
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# fp8-gemm

FlashRT native CUDA FP8 GEMV/GEMM kernels for low-latency transformer and
diffuser linear layers on NVIDIA Ada SM89 and Blackwell SM110/SM120 GPUs.

This package exposes the hand-tuned FP8 E4M3 decode and small-M kernels as
Tensor APIs for Hugging Face Kernel Hub. It is intended for model runtimes that
already hold activations and weights in FP8 and want a low-overhead BF16 output
linear path.

## Available Functions

- `fp8_linear_bf16(input, weight, alpha=1.0, out=None, variant=0)`
- `fp8_linear_residual_bf16(input, weight, residual, alpha=1.0, variant=0)`
- `fp8_linear_bias_bf16(input, weight, bias, alpha=1.0, out=None)`
- `fp8_linear_bias_residual_bf16(input, weight, bias, residual, alpha=1.0)`
- `fp8_linear_bias_gelu_bf16(input, weight, bias, alpha=1.0, out=None)`
- `fp8_blockwise_linear_bf16(input, weight, input_scale, weight_scale, out=None)`
- `fp8_blockwise_swiglu_quantize_fp8(input, gate_up_weight, input_scale, gate_up_weight_scale, output=None, output_scale=None)`
- `select_fp8_linear_tile(m, n, k, variant=0)`

Tensor contract:

- `input`: `torch.float8_e4m3fn`, shape `(M, K)`, contiguous CUDA tensor.
- `weight`: `torch.float8_e4m3fn`, shape `(N, K)`, contiguous CUDA tensor.
- `out`: `torch.bfloat16`, shape `(M, N)`.
- `residual`: `torch.bfloat16`, shape `(1, N)` or `(N,)`, only supported for
  the `M=1` decode GEMV path.
- `K % 16 == 0`; SM120 additionally requires `K % 32 == 0`.
- On SM120, `M == 1` uses dedicated GEMV and `2 <= M <= 64` uses small-M
  GEMM tiles.
- On SM110 (Jetson AGX Thor), the per-tensor API uses the production FlashRT
  CUTLASS Sq/T1/Wide family and supports the validated model-shape matrix from
  decode through large vision/backbone rows. The large-M production band is
  validated from `M=65` through `M=1024`, including PI0.5 prefill QKV, O,
  gate/up, and down projections at `M=712..970`. `N` and `K` must be divisible
  by 16.
- The three BF16 bias APIs are SM110-only. They accept BF16 `(N,)` bias and
  preserve the same row-major FP8 `(M,K)` input and `(N,K)` weight contract.
  The residual API updates a BF16 `(M,N)` tensor in place. The GELU API uses
  the tanh approximation.
- SM110 `variant=0` is the production auto dispatcher. Diagnostic variants are
  `1=Sq`, `2=T1`, and `3=Wide`; they are correctness-tested but should not be
  pinned by model integrations without a shape-specific benchmark.
- The per-tensor kernels use Blackwell FP8 MMA instructions and are not valid
  for SM89. SM89 support is provided by the blockwise API below.
- `alpha` is a host float. For per-tensor FP8 quantization, pass
  `float(input_scale * weight_scale)` from your static calibration metadata.

The blockwise API uses a separate contract:

- `input`: FP8 E4M3 `(M, K)`.
- `weight`: FP8 E4M3 `(N, K)`.
- `input_scale`: FP32 `(M, K / 128)`.
- `weight_scale`: FP32 `(N / 128, K / 128)`.
- `N` and `K` must be divisible by 128; `M` is unrestricted.
- Output is BF16 `(M, N)`.
- On SM89, the blockwise API dispatches to the production FlashRT native
  `mma.sync.aligned.m16n8k32` GEMM/GEMV implementation.
- On SM120, it dispatches to the production FlashRT CUTLASS block-scaled
  implementation.
- SM110 is intentionally not claimed by the blockwise API; use the per-tensor
  static-scale path there. Other architectures are rejected explicitly.

The fused SM89 producer accepts FP8 `(M,K)` input, FP8 `(2*N,K)` gate/up
weight, block-128 FP32 scales, and returns FP8 `(M,N)` plus FP32 `(M,N/128)`
output scales. Its public range is `1 <= M <= 256` with `N` and `K` divisible
by 128. It is rejected explicitly on non-SM89 GPUs.

## Minimal Usage

```python
from kernels import get_kernel
import torch

ops = get_kernel("flashrt/fp8-gemm", version=1, trust_remote_code=True)

x = torch.randn((16, 4096), device="cuda", dtype=torch.bfloat16).to(torch.float8_e4m3fn)
w = torch.randn((8192, 4096), device="cuda", dtype=torch.bfloat16).to(torch.float8_e4m3fn)

y = ops.fp8_linear_bf16(x, w, alpha=1.0)
```

SM110 bias epilogues:

```python
bias = torch.randn((8192,), device="cuda", dtype=torch.bfloat16)
residual = torch.randn((16, 8192), device="cuda", dtype=torch.bfloat16)

y = ops.fp8_linear_bias_bf16(x, w, bias, alpha=1.0)
ops.fp8_linear_bias_residual_bf16(x, w, bias, residual, alpha=1.0)
y_gelu = ops.fp8_linear_bias_gelu_bf16(x, w, bias, alpha=1.0)
```

Warm each distinct SM110 bias shape once before CUDA Graph capture. The
cuBLASLt fallback lazily creates and caches its descriptor, algorithm, and
workspace on the first call; replay itself performs no allocation.

Decode residual path:

```python
x = torch.randn((1, 4096), device="cuda", dtype=torch.bfloat16).to(torch.float8_e4m3fn)
w = torch.randn((4096, 4096), device="cuda", dtype=torch.bfloat16).to(torch.float8_e4m3fn)
residual = torch.zeros((1, 4096), device="cuda", dtype=torch.bfloat16)

ops.fp8_linear_residual_bf16(x, w, residual, alpha=1.0)
```

Block-128 scaling:

```python
m, k, n = 51, 1536, 1536
x = torch.randn((m, k), device="cuda").to(torch.float8_e4m3fn)
w = torch.randn((n, k), device="cuda").to(torch.float8_e4m3fn)
x_scale = torch.ones((m, k // 128), device="cuda", dtype=torch.float32)
w_scale = torch.ones((n // 128, k // 128), device="cuda", dtype=torch.float32)

y = ops.fp8_blockwise_linear_bf16(x, w, x_scale, w_scale)
```

## Validation

```bash
python fp8-gemm/tests/test_fp8_gemm.py --backend source --mode full
python fp8-gemm/benchmarks/benchmark.py --backend source --mode headline
python fp8-gemm/benchmarks/benchmark.py --backend source --mode pi05-prefill
python fp8-gemm/benchmarks/benchmark_bias.py --backend source
```

The SM110 full sweep covers PI0.5, GROOT N1.6/N1.7, Cosmos Edge, and LingBot
VLA projection families, plus decode, generic small-M, the `M=65` large-M
boundary, and the three SigLIP bias epilogues. Public
benchmark tables are only updated after source correctness, installed artifact
correctness, shape/tile sweeps, `torch.compile(fullgraph=True)`, CUDA Graph
replay, and parity against the original FlashRT native pointer entry pass.