liangsu9988 commited on
Commit
22d2bed
·
verified ·
1 Parent(s): f9aec85

Promote latest kernel artifacts to main

Browse files
README.md CHANGED
@@ -1,9 +1,135 @@
1
- # flashrt/fp8-gemm
2
 
3
- This repository is a compatibility mirror for older `kernels` clients
4
- that resolve repositories through the default Hugging Face model repo API.
5
 
6
- Canonical Kernel Hub repo: https://huggingface.co/kernels/flashrt/fp8-gemm
 
 
 
7
 
8
- Do not edit this mirror by hand. It is generated from the Kernel Hub
9
- `vN` branches and contains the same `build/**` artifacts.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # fp8-gemm
2
 
3
+ FlashRT native CUDA FP8 GEMV/GEMM kernels for low-latency transformer and
4
+ diffuser linear layers on NVIDIA Ada SM89 and Blackwell SM110/SM120 GPUs.
5
 
6
+ This package exposes the hand-tuned FP8 E4M3 decode and small-M kernels as
7
+ Tensor APIs for Hugging Face Kernel Hub. It is intended for model runtimes that
8
+ already hold activations and weights in FP8 and want a low-overhead BF16 output
9
+ linear path.
10
 
11
+ ## Available Functions
12
+
13
+ - `fp8_linear_bf16(input, weight, alpha=1.0, out=None, variant=0)`
14
+ - `fp8_linear_residual_bf16(input, weight, residual, alpha=1.0, variant=0)`
15
+ - `fp8_linear_bias_bf16(input, weight, bias, alpha=1.0, out=None)`
16
+ - `fp8_linear_bias_residual_bf16(input, weight, bias, residual, alpha=1.0)`
17
+ - `fp8_linear_bias_gelu_bf16(input, weight, bias, alpha=1.0, out=None)`
18
+ - `fp8_blockwise_linear_bf16(input, weight, input_scale, weight_scale, out=None)`
19
+ - `fp8_blockwise_swiglu_quantize_fp8(input, gate_up_weight, input_scale, gate_up_weight_scale, output=None, output_scale=None)`
20
+ - `select_fp8_linear_tile(m, n, k, variant=0)`
21
+
22
+ Tensor contract:
23
+
24
+ - `input`: `torch.float8_e4m3fn`, shape `(M, K)`, contiguous CUDA tensor.
25
+ - `weight`: `torch.float8_e4m3fn`, shape `(N, K)`, contiguous CUDA tensor.
26
+ - `out`: `torch.bfloat16`, shape `(M, N)`.
27
+ - `residual`: `torch.bfloat16`, shape `(1, N)` or `(N,)`, only supported for
28
+ the `M=1` decode GEMV path.
29
+ - `K % 16 == 0`; SM120 additionally requires `K % 32 == 0`.
30
+ - On SM120, `M == 1` uses dedicated GEMV and `2 <= M <= 64` uses small-M
31
+ GEMM tiles.
32
+ - On SM110 (Jetson AGX Thor), the per-tensor API uses the production FlashRT
33
+ CUTLASS Sq/T1/Wide family and supports the validated model-shape matrix from
34
+ decode through large vision/backbone rows. The large-M production band is
35
+ validated from `M=65` through `M=1024`, including PI0.5 prefill QKV, O,
36
+ gate/up, and down projections at `M=712..970`. `N` and `K` must be divisible
37
+ by 16.
38
+ - The three BF16 bias APIs are SM110-only. They accept BF16 `(N,)` bias and
39
+ preserve the same row-major FP8 `(M,K)` input and `(N,K)` weight contract.
40
+ The residual API updates a BF16 `(M,N)` tensor in place. The GELU API uses
41
+ the tanh approximation.
42
+ - SM110 `variant=0` is the production auto dispatcher. Diagnostic variants are
43
+ `1=Sq`, `2=T1`, and `3=Wide`; they are correctness-tested but should not be
44
+ pinned by model integrations without a shape-specific benchmark.
45
+ - The per-tensor kernels use Blackwell FP8 MMA instructions and are not valid
46
+ for SM89. SM89 support is provided by the blockwise API below.
47
+ - `alpha` is a host float. For per-tensor FP8 quantization, pass
48
+ `float(input_scale * weight_scale)` from your static calibration metadata.
49
+
50
+ The blockwise API uses a separate contract:
51
+
52
+ - `input`: FP8 E4M3 `(M, K)`.
53
+ - `weight`: FP8 E4M3 `(N, K)`.
54
+ - `input_scale`: FP32 `(M, K / 128)`.
55
+ - `weight_scale`: FP32 `(N / 128, K / 128)`.
56
+ - `N` and `K` must be divisible by 128; `M` is unrestricted.
57
+ - Output is BF16 `(M, N)`.
58
+ - On SM89, the blockwise API dispatches to the production FlashRT native
59
+ `mma.sync.aligned.m16n8k32` GEMM/GEMV implementation.
60
+ - On SM120, it dispatches to the production FlashRT CUTLASS block-scaled
61
+ implementation.
62
+ - SM110 is intentionally not claimed by the blockwise API; use the per-tensor
63
+ static-scale path there. Other architectures are rejected explicitly.
64
+
65
+ The fused SM89 producer accepts FP8 `(M,K)` input, FP8 `(2*N,K)` gate/up
66
+ weight, block-128 FP32 scales, and returns FP8 `(M,N)` plus FP32 `(M,N/128)`
67
+ output scales. Its public range is `1 <= M <= 256` with `N` and `K` divisible
68
+ by 128. It is rejected explicitly on non-SM89 GPUs.
69
+
70
+ ## Minimal Usage
71
+
72
+ ```python
73
+ from kernels import get_kernel
74
+ import torch
75
+
76
+ ops = get_kernel("flashrt/fp8-gemm", version=1, trust_remote_code=True)
77
+
78
+ x = torch.randn((16, 4096), device="cuda", dtype=torch.bfloat16).to(torch.float8_e4m3fn)
79
+ w = torch.randn((8192, 4096), device="cuda", dtype=torch.bfloat16).to(torch.float8_e4m3fn)
80
+
81
+ y = ops.fp8_linear_bf16(x, w, alpha=1.0)
82
+ ```
83
+
84
+ SM110 bias epilogues:
85
+
86
+ ```python
87
+ bias = torch.randn((8192,), device="cuda", dtype=torch.bfloat16)
88
+ residual = torch.randn((16, 8192), device="cuda", dtype=torch.bfloat16)
89
+
90
+ y = ops.fp8_linear_bias_bf16(x, w, bias, alpha=1.0)
91
+ ops.fp8_linear_bias_residual_bf16(x, w, bias, residual, alpha=1.0)
92
+ y_gelu = ops.fp8_linear_bias_gelu_bf16(x, w, bias, alpha=1.0)
93
+ ```
94
+
95
+ Warm each distinct SM110 bias shape once before CUDA Graph capture. The
96
+ cuBLASLt fallback lazily creates and caches its descriptor, algorithm, and
97
+ workspace on the first call; replay itself performs no allocation.
98
+
99
+ Decode residual path:
100
+
101
+ ```python
102
+ x = torch.randn((1, 4096), device="cuda", dtype=torch.bfloat16).to(torch.float8_e4m3fn)
103
+ w = torch.randn((4096, 4096), device="cuda", dtype=torch.bfloat16).to(torch.float8_e4m3fn)
104
+ residual = torch.zeros((1, 4096), device="cuda", dtype=torch.bfloat16)
105
+
106
+ ops.fp8_linear_residual_bf16(x, w, residual, alpha=1.0)
107
+ ```
108
+
109
+ Block-128 scaling:
110
+
111
+ ```python
112
+ m, k, n = 51, 1536, 1536
113
+ x = torch.randn((m, k), device="cuda").to(torch.float8_e4m3fn)
114
+ w = torch.randn((n, k), device="cuda").to(torch.float8_e4m3fn)
115
+ x_scale = torch.ones((m, k // 128), device="cuda", dtype=torch.float32)
116
+ w_scale = torch.ones((n // 128, k // 128), device="cuda", dtype=torch.float32)
117
+
118
+ y = ops.fp8_blockwise_linear_bf16(x, w, x_scale, w_scale)
119
+ ```
120
+
121
+ ## Validation
122
+
123
+ ```bash
124
+ python fp8-gemm/tests/test_fp8_gemm.py --backend source --mode full
125
+ python fp8-gemm/benchmarks/benchmark.py --backend source --mode headline
126
+ python fp8-gemm/benchmarks/benchmark.py --backend source --mode pi05-prefill
127
+ python fp8-gemm/benchmarks/benchmark_bias.py --backend source
128
+ ```
129
+
130
+ The SM110 full sweep covers PI0.5, GROOT N1.6/N1.7, Cosmos Edge, and LingBot
131
+ VLA projection families, plus decode, generic small-M, the `M=65` large-M
132
+ boundary, and the three SigLIP bias epilogues. Public
133
+ benchmark tables are only updated after source correctness, installed artifact
134
+ correctness, shape/tile sweeps, `torch.compile(fullgraph=True)`, CUDA Graph
135
+ replay, and parity against the original FlashRT native pointer entry pass.
benchmarks/benchmark.py CHANGED
@@ -149,13 +149,20 @@ def load_source_ops() -> SourceOps:
149
  str(cutlass_include.parent / "tools" / "util" / "include"),
150
  ]
151
  else:
 
 
152
  cuda_sources = [
153
  str(PACKAGE / "csrc" / "fp8_gemv_m1_sm120.cu"),
154
  str(PACKAGE / "csrc" / "fp8_smallM_handtuned_sm120.cu"),
155
  str(PACKAGE / "csrc" / "fp8_smallM_handtuned_ldmatrix_sm120.cu"),
 
 
156
  ]
157
  source_define = "-DFLASHRT_FP8_GEMM_SOURCE_SM120_ONLY"
158
- extra_includes = []
 
 
 
159
  load(
160
  name=namespace,
161
  sources=[str(PACKAGE / "torch-ext" / "torch_binding.cpp"), *cuda_sources],
@@ -250,7 +257,7 @@ def select_tile(m: int, n: int, k: int, variant: int = 0) -> str:
250
  if n % 128 == 0:
251
  return "ld_fp8_gemm_64x128x128_w4"
252
  return "ld_fp8_gemm_64x64x128_w4"
253
- raise RuntimeError("unsupported M")
254
 
255
 
256
  def make_inputs(m: int, k: int, n: int, seed: int):
 
149
  str(cutlass_include.parent / "tools" / "util" / "include"),
150
  ]
151
  else:
152
+ if not (cutlass_include / "cutlass" / "cutlass.h").is_file():
153
+ raise RuntimeError("set CUTLASS_INCLUDE for the SM120 source benchmark")
154
  cuda_sources = [
155
  str(PACKAGE / "csrc" / "fp8_gemv_m1_sm120.cu"),
156
  str(PACKAGE / "csrc" / "fp8_smallM_handtuned_sm120.cu"),
157
  str(PACKAGE / "csrc" / "fp8_smallM_handtuned_ldmatrix_sm120.cu"),
158
+ str(PACKAGE / "csrc" / "cutlass_sm120_block128_fp8_gemm.cu"),
159
+ str(PACKAGE / "csrc" / "cublaslt_fp8_bias_sm110.cu"),
160
  ]
161
  source_define = "-DFLASHRT_FP8_GEMM_SOURCE_SM120_ONLY"
162
+ extra_includes = [
163
+ str(cutlass_include),
164
+ str(cutlass_include.parent / "tools" / "util" / "include"),
165
+ ]
166
  load(
167
  name=namespace,
168
  sources=[str(PACKAGE / "torch-ext" / "torch_binding.cpp"), *cuda_sources],
 
257
  if n % 128 == 0:
258
  return "ld_fp8_gemm_64x128x128_w4"
259
  return "ld_fp8_gemm_64x64x128_w4"
260
+ return "cublaslt_fp8_large_m"
261
 
262
 
263
  def make_inputs(m: int, k: int, n: int, seed: int):
benchmarks/benchmark_bias.py CHANGED
@@ -1,5 +1,5 @@
1
  #!/usr/bin/env python3
2
- """Benchmark SM110 BF16-output FP8 GEMM epilogues."""
3
 
4
  from __future__ import annotations
5
 
@@ -66,29 +66,59 @@ class SourceOps:
66
  def load_source_ops() -> SourceOps:
67
  from torch.utils.cpp_extension import load
68
 
69
- cutlass = Path(os.environ["CUTLASS_INCLUDE"])
70
- os.environ.setdefault("TORCH_CUDA_ARCH_LIST", "11.0a")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  namespace = "fp8_gemm_bias_source_bench"
72
  load(
73
  name=namespace,
74
  sources=[
75
  str(PACKAGE / "torch-ext" / "torch_binding.cpp"),
76
- str(PACKAGE / "csrc" / "cutlass_sm110_fp8_gemm.cu"),
77
- str(PACKAGE / "csrc" / "cublaslt_fp8_bias_sm110.cu"),
78
  ],
79
  extra_include_paths=[
80
  str(PACKAGE / "csrc"),
81
  str(REGISTRATION_INCLUDE),
82
- str(cutlass),
83
- str(cutlass.parent / "tools" / "util" / "include"),
84
  ],
85
  extra_cflags=[
86
  "-O3", "-DNDEBUG", "-DCUDA_KERNEL",
87
- "-DFLASHRT_FP8_GEMM_SOURCE_SM110_ONLY",
88
  ],
89
  extra_cuda_cflags=[
90
  "-O3", "-DNDEBUG", "--expt-relaxed-constexpr", "--use_fast_math",
91
- "-DCUDA_KERNEL", "-DFLASHRT_FP8_GEMM_SOURCE_SM110_ONLY",
 
 
 
 
92
  ],
93
  verbose=False,
94
  )
@@ -154,8 +184,9 @@ def main() -> int:
154
  parser.add_argument("--iterations", type=int, default=64)
155
  parser.add_argument("--json-out", default=None)
156
  args = parser.parse_args()
157
- if torch.cuda.get_device_capability() != (11, 0):
158
- raise SystemExit("SM110 is required")
 
159
  ops = load_source_ops() if args.backend == "source" else load_installed_ops(args.artifact)
160
  native = load_native()
161
  native_stream = int(torch.cuda.current_stream().cuda_stream)
 
1
  #!/usr/bin/env python3
2
+ """Benchmark SM110/SM120 BF16-output FP8 GEMM epilogues."""
3
 
4
  from __future__ import annotations
5
 
 
66
  def load_source_ops() -> SourceOps:
67
  from torch.utils.cpp_extension import load
68
 
69
+ capability = torch.cuda.get_device_capability()
70
+ if capability == (11, 0):
71
+ cutlass = Path(os.environ["CUTLASS_INCLUDE"])
72
+ os.environ.setdefault("TORCH_CUDA_ARCH_LIST", "11.0a")
73
+ cuda_sources = [
74
+ str(PACKAGE / "csrc" / "cutlass_sm110_fp8_gemm.cu"),
75
+ str(PACKAGE / "csrc" / "cublaslt_fp8_bias_sm110.cu"),
76
+ ]
77
+ source_define = "-DFLASHRT_FP8_GEMM_SOURCE_SM110_ONLY"
78
+ extra_includes = [
79
+ str(cutlass),
80
+ str(cutlass.parent / "tools" / "util" / "include"),
81
+ ]
82
+ elif capability[0] >= 12:
83
+ cutlass = Path(os.environ["CUTLASS_INCLUDE"])
84
+ os.environ.setdefault("TORCH_CUDA_ARCH_LIST", "12.0a")
85
+ cuda_sources = [
86
+ str(PACKAGE / "csrc" / "fp8_gemv_m1_sm120.cu"),
87
+ str(PACKAGE / "csrc" / "fp8_smallM_handtuned_sm120.cu"),
88
+ str(PACKAGE / "csrc" / "fp8_smallM_handtuned_ldmatrix_sm120.cu"),
89
+ str(PACKAGE / "csrc" / "cutlass_sm120_block128_fp8_gemm.cu"),
90
+ str(PACKAGE / "csrc" / "cublaslt_fp8_bias_sm110.cu"),
91
+ ]
92
+ source_define = "-DFLASHRT_FP8_GEMM_SOURCE_SM120_ONLY"
93
+ extra_includes = [
94
+ str(cutlass),
95
+ str(cutlass.parent / "tools" / "util" / "include"),
96
+ ]
97
+ else:
98
+ raise RuntimeError(f"SM110 or SM120 is required, got {capability}")
99
  namespace = "fp8_gemm_bias_source_bench"
100
  load(
101
  name=namespace,
102
  sources=[
103
  str(PACKAGE / "torch-ext" / "torch_binding.cpp"),
104
+ *cuda_sources,
 
105
  ],
106
  extra_include_paths=[
107
  str(PACKAGE / "csrc"),
108
  str(REGISTRATION_INCLUDE),
109
+ *extra_includes,
 
110
  ],
111
  extra_cflags=[
112
  "-O3", "-DNDEBUG", "-DCUDA_KERNEL",
113
+ source_define,
114
  ],
115
  extra_cuda_cflags=[
116
  "-O3", "-DNDEBUG", "--expt-relaxed-constexpr", "--use_fast_math",
117
+ "-U__CUDA_NO_HALF_OPERATORS__",
118
+ "-U__CUDA_NO_HALF_CONVERSIONS__",
119
+ "-U__CUDA_NO_BFLOAT16_CONVERSIONS__",
120
+ "-U__CUDA_NO_HALF2_OPERATORS__",
121
+ "-DCUDA_KERNEL", source_define,
122
  ],
123
  verbose=False,
124
  )
 
184
  parser.add_argument("--iterations", type=int, default=64)
185
  parser.add_argument("--json-out", default=None)
186
  args = parser.parse_args()
187
+ capability = torch.cuda.get_device_capability()
188
+ if capability != (11, 0) and capability[0] < 12:
189
+ raise SystemExit(f"SM110 or SM120 is required, got {capability}")
190
  ops = load_source_ops() if args.backend == "source" else load_installed_ops(args.artifact)
191
  native = load_native()
192
  native_stream = int(torch.cuda.current_stream().cuda_stream)
build/torch212-cxx11-cu130-x86_64-linux/__init__.py CHANGED
@@ -37,6 +37,34 @@ def _fp8_linear_residual_bf16_fake(
37
  return None
38
 
39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  @torch.library.register_fake(add_op_namespace_prefix("fp8_blockwise_linear_bf16"))
41
  def _fp8_blockwise_linear_bf16_fake(
42
  input: torch.Tensor,
@@ -95,8 +123,8 @@ def select_fp8_linear_tile(m: int, n: int, k: int, variant: int = 0) -> str:
95
  variant = int(variant)
96
  if m <= 0 or n <= 0 or k <= 0:
97
  raise RuntimeError("m, n, and k must be positive")
98
- if k % 32 != 0:
99
- raise RuntimeError("k must be divisible by 32")
100
  capability = torch.cuda.get_device_capability() if torch.cuda.is_available() else None
101
  if capability == (11, 0):
102
  forced = {1: "sm110_sq_bf16", 2: "sm110_t1_bf16", 3: "sm110_wide_bf16"}
@@ -106,6 +134,12 @@ def select_fp8_linear_tile(m: int, n: int, k: int, variant: int = 0) -> str:
106
  raise RuntimeError("SM110 requires n and k divisible by 16")
107
  if variant:
108
  return forced[variant]
 
 
 
 
 
 
109
  if n >= 8 * k:
110
  return "sm110_wide_bf16"
111
  if m >= 128 and k >= 4 * n:
@@ -116,6 +150,8 @@ def select_fp8_linear_tile(m: int, n: int, k: int, variant: int = 0) -> str:
116
  return "sm110_wide_bf16"
117
  return "sm110_t1_bf16"
118
  if m == 1:
 
 
119
  if variant == 4:
120
  return "gemv_fp8_m1_w4"
121
  if variant == 8:
@@ -131,6 +167,8 @@ def select_fp8_linear_tile(m: int, n: int, k: int, variant: int = 0) -> str:
131
  return "gemv_fp8_m1_w16"
132
  if variant != 0:
133
  raise RuntimeError("small-M dispatcher currently supports variant=0 only")
 
 
134
  if m <= 16:
135
  if k % 256 == 0:
136
  return "ld_fp8_gemm_16x128x256_w4" if n % 128 == 0 else "ld_fp8_gemm_16x64x256_w4"
@@ -197,6 +235,56 @@ def fp8_linear_residual_bf16(
197
  return residual
198
 
199
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  def fp8_blockwise_linear_bf16(
201
  input: torch.Tensor,
202
  weight: torch.Tensor,
@@ -248,6 +336,9 @@ def fp8_blockwise_swiglu_quantize_fp8(
248
  __all__ = [
249
  "fp8_linear_bf16",
250
  "fp8_linear_residual_bf16",
 
 
 
251
  "fp8_blockwise_linear_bf16",
252
  "fp8_blockwise_swiglu_quantize_fp8",
253
  "select_fp8_linear_tile",
 
37
  return None
38
 
39
 
40
+ def _check_bias_linear_shapes(input, weight, bias, out) -> None:
41
+ if input.dim() != 2 or weight.dim() != 2:
42
+ raise RuntimeError("input and weight must be rank-2 tensors")
43
+ if input.shape[1] != weight.shape[1]:
44
+ raise RuntimeError("input and weight K dimensions must match")
45
+ if bias.shape != (weight.shape[0],):
46
+ raise RuntimeError("bias must have shape (weight.shape[0],)")
47
+ if out.shape != (input.shape[0], weight.shape[0]):
48
+ raise RuntimeError("out must have shape (input.shape[0], weight.shape[0])")
49
+
50
+
51
+ @torch.library.register_fake(add_op_namespace_prefix("fp8_linear_bias_bf16"))
52
+ def _fp8_linear_bias_bf16_fake(input, weight, bias, alpha: float, out) -> None:
53
+ _check_bias_linear_shapes(input, weight, bias, out)
54
+
55
+
56
+ @torch.library.register_fake(add_op_namespace_prefix("fp8_linear_bias_residual_bf16"))
57
+ def _fp8_linear_bias_residual_bf16_fake(
58
+ input, weight, bias, alpha: float, residual
59
+ ) -> None:
60
+ _check_bias_linear_shapes(input, weight, bias, residual)
61
+
62
+
63
+ @torch.library.register_fake(add_op_namespace_prefix("fp8_linear_bias_gelu_bf16"))
64
+ def _fp8_linear_bias_gelu_bf16_fake(input, weight, bias, alpha: float, out) -> None:
65
+ _check_bias_linear_shapes(input, weight, bias, out)
66
+
67
+
68
  @torch.library.register_fake(add_op_namespace_prefix("fp8_blockwise_linear_bf16"))
69
  def _fp8_blockwise_linear_bf16_fake(
70
  input: torch.Tensor,
 
123
  variant = int(variant)
124
  if m <= 0 or n <= 0 or k <= 0:
125
  raise RuntimeError("m, n, and k must be positive")
126
+ if k % 16 != 0:
127
+ raise RuntimeError("k must be divisible by 16")
128
  capability = torch.cuda.get_device_capability() if torch.cuda.is_available() else None
129
  if capability == (11, 0):
130
  forced = {1: "sm110_sq_bf16", 2: "sm110_t1_bf16", 3: "sm110_wide_bf16"}
 
134
  raise RuntimeError("SM110 requires n and k divisible by 16")
135
  if variant:
136
  return forced[variant]
137
+ if m >= 512 and k == 2048 and 2048 <= n <= 2560:
138
+ return "sm110_sq_bf16"
139
+ if m >= 512 and n >= 16 * k:
140
+ return "sm110_t1_bf16"
141
+ if m >= 512 and k >= 4 * n:
142
+ return "sm110_wide_bf16"
143
  if n >= 8 * k:
144
  return "sm110_wide_bf16"
145
  if m >= 128 and k >= 4 * n:
 
150
  return "sm110_wide_bf16"
151
  return "sm110_t1_bf16"
152
  if m == 1:
153
+ if k % 32:
154
+ raise RuntimeError("SM120 requires k divisible by 32")
155
  if variant == 4:
156
  return "gemv_fp8_m1_w4"
157
  if variant == 8:
 
167
  return "gemv_fp8_m1_w16"
168
  if variant != 0:
169
  raise RuntimeError("small-M dispatcher currently supports variant=0 only")
170
+ if k % 32:
171
+ raise RuntimeError("SM120 requires k divisible by 32")
172
  if m <= 16:
173
  if k % 256 == 0:
174
  return "ld_fp8_gemm_16x128x256_w4" if n % 128 == 0 else "ld_fp8_gemm_16x64x256_w4"
 
235
  return residual
236
 
237
 
238
+ def fp8_linear_bias_bf16(
239
+ input: torch.Tensor,
240
+ weight: torch.Tensor,
241
+ bias: torch.Tensor,
242
+ alpha: float = 1.0,
243
+ out: torch.Tensor | None = None,
244
+ ) -> torch.Tensor:
245
+ """SM110 FP8 linear with fused BF16 bias and BF16 output."""
246
+ if out is None:
247
+ out = torch.empty(
248
+ (input.shape[0], weight.shape[0]),
249
+ device=input.device,
250
+ dtype=torch.bfloat16,
251
+ )
252
+ ops.fp8_linear_bias_bf16(input, weight, bias, float(alpha), out)
253
+ return out
254
+
255
+
256
+ def fp8_linear_bias_residual_bf16(
257
+ input: torch.Tensor,
258
+ weight: torch.Tensor,
259
+ bias: torch.Tensor,
260
+ residual: torch.Tensor,
261
+ alpha: float = 1.0,
262
+ ) -> torch.Tensor:
263
+ """SM110 fused ``residual += alpha * input @ weight.T + bias``."""
264
+ ops.fp8_linear_bias_residual_bf16(
265
+ input, weight, bias, float(alpha), residual
266
+ )
267
+ return residual
268
+
269
+
270
+ def fp8_linear_bias_gelu_bf16(
271
+ input: torch.Tensor,
272
+ weight: torch.Tensor,
273
+ bias: torch.Tensor,
274
+ alpha: float = 1.0,
275
+ out: torch.Tensor | None = None,
276
+ ) -> torch.Tensor:
277
+ """SM110 FP8 linear with fused BF16 bias and GELU epilogue."""
278
+ if out is None:
279
+ out = torch.empty(
280
+ (input.shape[0], weight.shape[0]),
281
+ device=input.device,
282
+ dtype=torch.bfloat16,
283
+ )
284
+ ops.fp8_linear_bias_gelu_bf16(input, weight, bias, float(alpha), out)
285
+ return out
286
+
287
+
288
  def fp8_blockwise_linear_bf16(
289
  input: torch.Tensor,
290
  weight: torch.Tensor,
 
336
  __all__ = [
337
  "fp8_linear_bf16",
338
  "fp8_linear_residual_bf16",
339
+ "fp8_linear_bias_bf16",
340
+ "fp8_linear_bias_residual_bf16",
341
+ "fp8_linear_bias_gelu_bf16",
342
  "fp8_blockwise_linear_bf16",
343
  "fp8_blockwise_swiglu_quantize_fp8",
344
  "select_fp8_linear_tile",
build/torch212-cxx11-cu130-x86_64-linux/{_fp8_gemm_cuda_bf15968.abi3.so → _fp8_gemm_cuda_8fba1d7.abi3.so} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:d8c90f60cb56efb79b25a6db2abe5f58336c7327902a0bcddfb7e4d3bde41dbb
3
- size 5390512
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3341b44bcf4bcbc602b01c1e0f409d63b8a3b4b0ef97ff5a9bccbc1b97bd74da
3
+ size 5665360
build/torch212-cxx11-cu130-x86_64-linux/_ops.py CHANGED
@@ -1,9 +1,9 @@
1
  import torch
2
- from . import _fp8_gemm_cuda_bf15968
3
- ops = torch.ops._fp8_gemm_cuda_bf15968
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
- return f"_fp8_gemm_cuda_bf15968::{op_name}"
 
1
  import torch
2
+ from . import _fp8_gemm_cuda_8fba1d7
3
+ ops = torch.ops._fp8_gemm_cuda_8fba1d7
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
+ return f"_fp8_gemm_cuda_8fba1d7::{op_name}"
build/torch212-cxx11-cu130-x86_64-linux/metadata.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "name": "fp8-gemm",
3
- "id": "_fp8_gemm_cuda_bf15968",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
@@ -15,9 +15,9 @@
15
  "digest": {
16
  "algorithm": "sha256",
17
  "files": {
18
- "__init__.py": "hKsdFER2ZmYz36/zz9LYE7ddsK/R1dprHJFx+9yBzks=",
19
- "_fp8_gemm_cuda_bf15968.abi3.so": "2MkPYMtW77ebJabbKr5fWDNscyeQKgvN37fk073kHbs=",
20
- "_ops.py": "wDFSPD8vh2K2qjj/9mdUYv6LrXuGz6MQCb2B/e8nqWs="
21
  }
22
  },
23
  "provenance": {
@@ -27,7 +27,7 @@
27
  "dirty": false
28
  },
29
  "kernel": {
30
- "sha": "bf15968fd9c281a7ca107e7696300fe091f588a2",
31
  "dirty": false
32
  }
33
  }
 
1
  {
2
  "name": "fp8-gemm",
3
+ "id": "_fp8_gemm_cuda_8fba1d7",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
 
15
  "digest": {
16
  "algorithm": "sha256",
17
  "files": {
18
+ "__init__.py": "HsFfsGY7AK/6Fziv4r2VQ+R2kDjS6hxKKgWqlA+zrKY=",
19
+ "_fp8_gemm_cuda_8fba1d7.abi3.so": "M0G0S89Ly8YCsBweD0CdY7ijtLDvl/9am8y8G5e9dNo=",
20
+ "_ops.py": "ptfSaRMzscUfi27OPI9uPdaK9uAgUUrImeBJSSDv3kY="
21
  }
22
  },
23
  "provenance": {
 
27
  "dirty": false
28
  },
29
  "kernel": {
30
+ "sha": "8fba1d7f2e4e627b1a2c3c8018f01c0ca4f430ee",
31
  "dirty": false
32
  }
33
  }
build/torch212-cxx11-cu132-x86_64-linux/__init__.py CHANGED
@@ -37,6 +37,34 @@ def _fp8_linear_residual_bf16_fake(
37
  return None
38
 
39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  @torch.library.register_fake(add_op_namespace_prefix("fp8_blockwise_linear_bf16"))
41
  def _fp8_blockwise_linear_bf16_fake(
42
  input: torch.Tensor,
@@ -95,8 +123,8 @@ def select_fp8_linear_tile(m: int, n: int, k: int, variant: int = 0) -> str:
95
  variant = int(variant)
96
  if m <= 0 or n <= 0 or k <= 0:
97
  raise RuntimeError("m, n, and k must be positive")
98
- if k % 32 != 0:
99
- raise RuntimeError("k must be divisible by 32")
100
  capability = torch.cuda.get_device_capability() if torch.cuda.is_available() else None
101
  if capability == (11, 0):
102
  forced = {1: "sm110_sq_bf16", 2: "sm110_t1_bf16", 3: "sm110_wide_bf16"}
@@ -106,6 +134,12 @@ def select_fp8_linear_tile(m: int, n: int, k: int, variant: int = 0) -> str:
106
  raise RuntimeError("SM110 requires n and k divisible by 16")
107
  if variant:
108
  return forced[variant]
 
 
 
 
 
 
109
  if n >= 8 * k:
110
  return "sm110_wide_bf16"
111
  if m >= 128 and k >= 4 * n:
@@ -116,6 +150,8 @@ def select_fp8_linear_tile(m: int, n: int, k: int, variant: int = 0) -> str:
116
  return "sm110_wide_bf16"
117
  return "sm110_t1_bf16"
118
  if m == 1:
 
 
119
  if variant == 4:
120
  return "gemv_fp8_m1_w4"
121
  if variant == 8:
@@ -131,6 +167,8 @@ def select_fp8_linear_tile(m: int, n: int, k: int, variant: int = 0) -> str:
131
  return "gemv_fp8_m1_w16"
132
  if variant != 0:
133
  raise RuntimeError("small-M dispatcher currently supports variant=0 only")
 
 
134
  if m <= 16:
135
  if k % 256 == 0:
136
  return "ld_fp8_gemm_16x128x256_w4" if n % 128 == 0 else "ld_fp8_gemm_16x64x256_w4"
@@ -197,6 +235,56 @@ def fp8_linear_residual_bf16(
197
  return residual
198
 
199
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  def fp8_blockwise_linear_bf16(
201
  input: torch.Tensor,
202
  weight: torch.Tensor,
@@ -248,6 +336,9 @@ def fp8_blockwise_swiglu_quantize_fp8(
248
  __all__ = [
249
  "fp8_linear_bf16",
250
  "fp8_linear_residual_bf16",
 
 
 
251
  "fp8_blockwise_linear_bf16",
252
  "fp8_blockwise_swiglu_quantize_fp8",
253
  "select_fp8_linear_tile",
 
37
  return None
38
 
39
 
40
+ def _check_bias_linear_shapes(input, weight, bias, out) -> None:
41
+ if input.dim() != 2 or weight.dim() != 2:
42
+ raise RuntimeError("input and weight must be rank-2 tensors")
43
+ if input.shape[1] != weight.shape[1]:
44
+ raise RuntimeError("input and weight K dimensions must match")
45
+ if bias.shape != (weight.shape[0],):
46
+ raise RuntimeError("bias must have shape (weight.shape[0],)")
47
+ if out.shape != (input.shape[0], weight.shape[0]):
48
+ raise RuntimeError("out must have shape (input.shape[0], weight.shape[0])")
49
+
50
+
51
+ @torch.library.register_fake(add_op_namespace_prefix("fp8_linear_bias_bf16"))
52
+ def _fp8_linear_bias_bf16_fake(input, weight, bias, alpha: float, out) -> None:
53
+ _check_bias_linear_shapes(input, weight, bias, out)
54
+
55
+
56
+ @torch.library.register_fake(add_op_namespace_prefix("fp8_linear_bias_residual_bf16"))
57
+ def _fp8_linear_bias_residual_bf16_fake(
58
+ input, weight, bias, alpha: float, residual
59
+ ) -> None:
60
+ _check_bias_linear_shapes(input, weight, bias, residual)
61
+
62
+
63
+ @torch.library.register_fake(add_op_namespace_prefix("fp8_linear_bias_gelu_bf16"))
64
+ def _fp8_linear_bias_gelu_bf16_fake(input, weight, bias, alpha: float, out) -> None:
65
+ _check_bias_linear_shapes(input, weight, bias, out)
66
+
67
+
68
  @torch.library.register_fake(add_op_namespace_prefix("fp8_blockwise_linear_bf16"))
69
  def _fp8_blockwise_linear_bf16_fake(
70
  input: torch.Tensor,
 
123
  variant = int(variant)
124
  if m <= 0 or n <= 0 or k <= 0:
125
  raise RuntimeError("m, n, and k must be positive")
126
+ if k % 16 != 0:
127
+ raise RuntimeError("k must be divisible by 16")
128
  capability = torch.cuda.get_device_capability() if torch.cuda.is_available() else None
129
  if capability == (11, 0):
130
  forced = {1: "sm110_sq_bf16", 2: "sm110_t1_bf16", 3: "sm110_wide_bf16"}
 
134
  raise RuntimeError("SM110 requires n and k divisible by 16")
135
  if variant:
136
  return forced[variant]
137
+ if m >= 512 and k == 2048 and 2048 <= n <= 2560:
138
+ return "sm110_sq_bf16"
139
+ if m >= 512 and n >= 16 * k:
140
+ return "sm110_t1_bf16"
141
+ if m >= 512 and k >= 4 * n:
142
+ return "sm110_wide_bf16"
143
  if n >= 8 * k:
144
  return "sm110_wide_bf16"
145
  if m >= 128 and k >= 4 * n:
 
150
  return "sm110_wide_bf16"
151
  return "sm110_t1_bf16"
152
  if m == 1:
153
+ if k % 32:
154
+ raise RuntimeError("SM120 requires k divisible by 32")
155
  if variant == 4:
156
  return "gemv_fp8_m1_w4"
157
  if variant == 8:
 
167
  return "gemv_fp8_m1_w16"
168
  if variant != 0:
169
  raise RuntimeError("small-M dispatcher currently supports variant=0 only")
170
+ if k % 32:
171
+ raise RuntimeError("SM120 requires k divisible by 32")
172
  if m <= 16:
173
  if k % 256 == 0:
174
  return "ld_fp8_gemm_16x128x256_w4" if n % 128 == 0 else "ld_fp8_gemm_16x64x256_w4"
 
235
  return residual
236
 
237
 
238
+ def fp8_linear_bias_bf16(
239
+ input: torch.Tensor,
240
+ weight: torch.Tensor,
241
+ bias: torch.Tensor,
242
+ alpha: float = 1.0,
243
+ out: torch.Tensor | None = None,
244
+ ) -> torch.Tensor:
245
+ """SM110 FP8 linear with fused BF16 bias and BF16 output."""
246
+ if out is None:
247
+ out = torch.empty(
248
+ (input.shape[0], weight.shape[0]),
249
+ device=input.device,
250
+ dtype=torch.bfloat16,
251
+ )
252
+ ops.fp8_linear_bias_bf16(input, weight, bias, float(alpha), out)
253
+ return out
254
+
255
+
256
+ def fp8_linear_bias_residual_bf16(
257
+ input: torch.Tensor,
258
+ weight: torch.Tensor,
259
+ bias: torch.Tensor,
260
+ residual: torch.Tensor,
261
+ alpha: float = 1.0,
262
+ ) -> torch.Tensor:
263
+ """SM110 fused ``residual += alpha * input @ weight.T + bias``."""
264
+ ops.fp8_linear_bias_residual_bf16(
265
+ input, weight, bias, float(alpha), residual
266
+ )
267
+ return residual
268
+
269
+
270
+ def fp8_linear_bias_gelu_bf16(
271
+ input: torch.Tensor,
272
+ weight: torch.Tensor,
273
+ bias: torch.Tensor,
274
+ alpha: float = 1.0,
275
+ out: torch.Tensor | None = None,
276
+ ) -> torch.Tensor:
277
+ """SM110 FP8 linear with fused BF16 bias and GELU epilogue."""
278
+ if out is None:
279
+ out = torch.empty(
280
+ (input.shape[0], weight.shape[0]),
281
+ device=input.device,
282
+ dtype=torch.bfloat16,
283
+ )
284
+ ops.fp8_linear_bias_gelu_bf16(input, weight, bias, float(alpha), out)
285
+ return out
286
+
287
+
288
  def fp8_blockwise_linear_bf16(
289
  input: torch.Tensor,
290
  weight: torch.Tensor,
 
336
  __all__ = [
337
  "fp8_linear_bf16",
338
  "fp8_linear_residual_bf16",
339
+ "fp8_linear_bias_bf16",
340
+ "fp8_linear_bias_residual_bf16",
341
+ "fp8_linear_bias_gelu_bf16",
342
  "fp8_blockwise_linear_bf16",
343
  "fp8_blockwise_swiglu_quantize_fp8",
344
  "select_fp8_linear_tile",
build/torch212-cxx11-cu132-x86_64-linux/{_fp8_gemm_cuda_bf15968.abi3.so → _fp8_gemm_cuda_8fba1d7.abi3.so} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:9b025dcd2da72fc44d87e0bb8a68168e56e2972bca5417631ff1f534615c31ae
3
- size 5431528
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:43cd1fb5e965a5db8be675915160e2b192781789bd808c61ca1521c22598c874
3
+ size 5710472
build/torch212-cxx11-cu132-x86_64-linux/_ops.py CHANGED
@@ -1,9 +1,9 @@
1
  import torch
2
- from . import _fp8_gemm_cuda_bf15968
3
- ops = torch.ops._fp8_gemm_cuda_bf15968
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
- return f"_fp8_gemm_cuda_bf15968::{op_name}"
 
1
  import torch
2
+ from . import _fp8_gemm_cuda_8fba1d7
3
+ ops = torch.ops._fp8_gemm_cuda_8fba1d7
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
+ return f"_fp8_gemm_cuda_8fba1d7::{op_name}"
build/torch212-cxx11-cu132-x86_64-linux/metadata.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "name": "fp8-gemm",
3
- "id": "_fp8_gemm_cuda_bf15968",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
@@ -15,9 +15,9 @@
15
  "digest": {
16
  "algorithm": "sha256",
17
  "files": {
18
- "__init__.py": "hKsdFER2ZmYz36/zz9LYE7ddsK/R1dprHJFx+9yBzks=",
19
- "_fp8_gemm_cuda_bf15968.abi3.so": "mwJdzS2nL8RNh+C7imgWjlbilyvKVBdjH/H1NGFcMa4=",
20
- "_ops.py": "wDFSPD8vh2K2qjj/9mdUYv6LrXuGz6MQCb2B/e8nqWs="
21
  }
22
  },
23
  "provenance": {
@@ -27,7 +27,7 @@
27
  "dirty": false
28
  },
29
  "kernel": {
30
- "sha": "bf15968fd9c281a7ca107e7696300fe091f588a2",
31
  "dirty": false
32
  }
33
  }
 
1
  {
2
  "name": "fp8-gemm",
3
+ "id": "_fp8_gemm_cuda_8fba1d7",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
 
15
  "digest": {
16
  "algorithm": "sha256",
17
  "files": {
18
+ "__init__.py": "HsFfsGY7AK/6Fziv4r2VQ+R2kDjS6hxKKgWqlA+zrKY=",
19
+ "_fp8_gemm_cuda_8fba1d7.abi3.so": "Q80ftellpduL5nWRUWDisZJ4F4m9gIxhyhUhwiWYyHQ=",
20
+ "_ops.py": "ptfSaRMzscUfi27OPI9uPdaK9uAgUUrImeBJSSDv3kY="
21
  }
22
  },
23
  "provenance": {
 
27
  "dirty": false
28
  },
29
  "kernel": {
30
+ "sha": "8fba1d7f2e4e627b1a2c3c8018f01c0ca4f430ee",
31
  "dirty": false
32
  }
33
  }
build/torch213-cxx11-cu130-x86_64-linux/__init__.py CHANGED
@@ -37,6 +37,34 @@ def _fp8_linear_residual_bf16_fake(
37
  return None
38
 
39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  @torch.library.register_fake(add_op_namespace_prefix("fp8_blockwise_linear_bf16"))
41
  def _fp8_blockwise_linear_bf16_fake(
42
  input: torch.Tensor,
@@ -95,8 +123,8 @@ def select_fp8_linear_tile(m: int, n: int, k: int, variant: int = 0) -> str:
95
  variant = int(variant)
96
  if m <= 0 or n <= 0 or k <= 0:
97
  raise RuntimeError("m, n, and k must be positive")
98
- if k % 32 != 0:
99
- raise RuntimeError("k must be divisible by 32")
100
  capability = torch.cuda.get_device_capability() if torch.cuda.is_available() else None
101
  if capability == (11, 0):
102
  forced = {1: "sm110_sq_bf16", 2: "sm110_t1_bf16", 3: "sm110_wide_bf16"}
@@ -106,6 +134,12 @@ def select_fp8_linear_tile(m: int, n: int, k: int, variant: int = 0) -> str:
106
  raise RuntimeError("SM110 requires n and k divisible by 16")
107
  if variant:
108
  return forced[variant]
 
 
 
 
 
 
109
  if n >= 8 * k:
110
  return "sm110_wide_bf16"
111
  if m >= 128 and k >= 4 * n:
@@ -116,6 +150,8 @@ def select_fp8_linear_tile(m: int, n: int, k: int, variant: int = 0) -> str:
116
  return "sm110_wide_bf16"
117
  return "sm110_t1_bf16"
118
  if m == 1:
 
 
119
  if variant == 4:
120
  return "gemv_fp8_m1_w4"
121
  if variant == 8:
@@ -131,6 +167,8 @@ def select_fp8_linear_tile(m: int, n: int, k: int, variant: int = 0) -> str:
131
  return "gemv_fp8_m1_w16"
132
  if variant != 0:
133
  raise RuntimeError("small-M dispatcher currently supports variant=0 only")
 
 
134
  if m <= 16:
135
  if k % 256 == 0:
136
  return "ld_fp8_gemm_16x128x256_w4" if n % 128 == 0 else "ld_fp8_gemm_16x64x256_w4"
@@ -197,6 +235,56 @@ def fp8_linear_residual_bf16(
197
  return residual
198
 
199
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  def fp8_blockwise_linear_bf16(
201
  input: torch.Tensor,
202
  weight: torch.Tensor,
@@ -248,6 +336,9 @@ def fp8_blockwise_swiglu_quantize_fp8(
248
  __all__ = [
249
  "fp8_linear_bf16",
250
  "fp8_linear_residual_bf16",
 
 
 
251
  "fp8_blockwise_linear_bf16",
252
  "fp8_blockwise_swiglu_quantize_fp8",
253
  "select_fp8_linear_tile",
 
37
  return None
38
 
39
 
40
+ def _check_bias_linear_shapes(input, weight, bias, out) -> None:
41
+ if input.dim() != 2 or weight.dim() != 2:
42
+ raise RuntimeError("input and weight must be rank-2 tensors")
43
+ if input.shape[1] != weight.shape[1]:
44
+ raise RuntimeError("input and weight K dimensions must match")
45
+ if bias.shape != (weight.shape[0],):
46
+ raise RuntimeError("bias must have shape (weight.shape[0],)")
47
+ if out.shape != (input.shape[0], weight.shape[0]):
48
+ raise RuntimeError("out must have shape (input.shape[0], weight.shape[0])")
49
+
50
+
51
+ @torch.library.register_fake(add_op_namespace_prefix("fp8_linear_bias_bf16"))
52
+ def _fp8_linear_bias_bf16_fake(input, weight, bias, alpha: float, out) -> None:
53
+ _check_bias_linear_shapes(input, weight, bias, out)
54
+
55
+
56
+ @torch.library.register_fake(add_op_namespace_prefix("fp8_linear_bias_residual_bf16"))
57
+ def _fp8_linear_bias_residual_bf16_fake(
58
+ input, weight, bias, alpha: float, residual
59
+ ) -> None:
60
+ _check_bias_linear_shapes(input, weight, bias, residual)
61
+
62
+
63
+ @torch.library.register_fake(add_op_namespace_prefix("fp8_linear_bias_gelu_bf16"))
64
+ def _fp8_linear_bias_gelu_bf16_fake(input, weight, bias, alpha: float, out) -> None:
65
+ _check_bias_linear_shapes(input, weight, bias, out)
66
+
67
+
68
  @torch.library.register_fake(add_op_namespace_prefix("fp8_blockwise_linear_bf16"))
69
  def _fp8_blockwise_linear_bf16_fake(
70
  input: torch.Tensor,
 
123
  variant = int(variant)
124
  if m <= 0 or n <= 0 or k <= 0:
125
  raise RuntimeError("m, n, and k must be positive")
126
+ if k % 16 != 0:
127
+ raise RuntimeError("k must be divisible by 16")
128
  capability = torch.cuda.get_device_capability() if torch.cuda.is_available() else None
129
  if capability == (11, 0):
130
  forced = {1: "sm110_sq_bf16", 2: "sm110_t1_bf16", 3: "sm110_wide_bf16"}
 
134
  raise RuntimeError("SM110 requires n and k divisible by 16")
135
  if variant:
136
  return forced[variant]
137
+ if m >= 512 and k == 2048 and 2048 <= n <= 2560:
138
+ return "sm110_sq_bf16"
139
+ if m >= 512 and n >= 16 * k:
140
+ return "sm110_t1_bf16"
141
+ if m >= 512 and k >= 4 * n:
142
+ return "sm110_wide_bf16"
143
  if n >= 8 * k:
144
  return "sm110_wide_bf16"
145
  if m >= 128 and k >= 4 * n:
 
150
  return "sm110_wide_bf16"
151
  return "sm110_t1_bf16"
152
  if m == 1:
153
+ if k % 32:
154
+ raise RuntimeError("SM120 requires k divisible by 32")
155
  if variant == 4:
156
  return "gemv_fp8_m1_w4"
157
  if variant == 8:
 
167
  return "gemv_fp8_m1_w16"
168
  if variant != 0:
169
  raise RuntimeError("small-M dispatcher currently supports variant=0 only")
170
+ if k % 32:
171
+ raise RuntimeError("SM120 requires k divisible by 32")
172
  if m <= 16:
173
  if k % 256 == 0:
174
  return "ld_fp8_gemm_16x128x256_w4" if n % 128 == 0 else "ld_fp8_gemm_16x64x256_w4"
 
235
  return residual
236
 
237
 
238
+ def fp8_linear_bias_bf16(
239
+ input: torch.Tensor,
240
+ weight: torch.Tensor,
241
+ bias: torch.Tensor,
242
+ alpha: float = 1.0,
243
+ out: torch.Tensor | None = None,
244
+ ) -> torch.Tensor:
245
+ """SM110 FP8 linear with fused BF16 bias and BF16 output."""
246
+ if out is None:
247
+ out = torch.empty(
248
+ (input.shape[0], weight.shape[0]),
249
+ device=input.device,
250
+ dtype=torch.bfloat16,
251
+ )
252
+ ops.fp8_linear_bias_bf16(input, weight, bias, float(alpha), out)
253
+ return out
254
+
255
+
256
+ def fp8_linear_bias_residual_bf16(
257
+ input: torch.Tensor,
258
+ weight: torch.Tensor,
259
+ bias: torch.Tensor,
260
+ residual: torch.Tensor,
261
+ alpha: float = 1.0,
262
+ ) -> torch.Tensor:
263
+ """SM110 fused ``residual += alpha * input @ weight.T + bias``."""
264
+ ops.fp8_linear_bias_residual_bf16(
265
+ input, weight, bias, float(alpha), residual
266
+ )
267
+ return residual
268
+
269
+
270
+ def fp8_linear_bias_gelu_bf16(
271
+ input: torch.Tensor,
272
+ weight: torch.Tensor,
273
+ bias: torch.Tensor,
274
+ alpha: float = 1.0,
275
+ out: torch.Tensor | None = None,
276
+ ) -> torch.Tensor:
277
+ """SM110 FP8 linear with fused BF16 bias and GELU epilogue."""
278
+ if out is None:
279
+ out = torch.empty(
280
+ (input.shape[0], weight.shape[0]),
281
+ device=input.device,
282
+ dtype=torch.bfloat16,
283
+ )
284
+ ops.fp8_linear_bias_gelu_bf16(input, weight, bias, float(alpha), out)
285
+ return out
286
+
287
+
288
  def fp8_blockwise_linear_bf16(
289
  input: torch.Tensor,
290
  weight: torch.Tensor,
 
336
  __all__ = [
337
  "fp8_linear_bf16",
338
  "fp8_linear_residual_bf16",
339
+ "fp8_linear_bias_bf16",
340
+ "fp8_linear_bias_residual_bf16",
341
+ "fp8_linear_bias_gelu_bf16",
342
  "fp8_blockwise_linear_bf16",
343
  "fp8_blockwise_swiglu_quantize_fp8",
344
  "select_fp8_linear_tile",
build/torch213-cxx11-cu130-x86_64-linux/{_fp8_gemm_cuda_bf15968.abi3.so → _fp8_gemm_cuda_8fba1d7.abi3.so} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:90adef3d22bb98b7dc1b2b48d860f0fa2fe682125acb31b1c554f889e0f171ce
3
- size 5390352
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6f3a290722fe4499c9566447d662776127bee8fb4885e92c72771d1c49f52364
3
+ size 5665200
build/torch213-cxx11-cu130-x86_64-linux/_ops.py CHANGED
@@ -1,9 +1,9 @@
1
  import torch
2
- from . import _fp8_gemm_cuda_bf15968
3
- ops = torch.ops._fp8_gemm_cuda_bf15968
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
- return f"_fp8_gemm_cuda_bf15968::{op_name}"
 
1
  import torch
2
+ from . import _fp8_gemm_cuda_8fba1d7
3
+ ops = torch.ops._fp8_gemm_cuda_8fba1d7
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
+ return f"_fp8_gemm_cuda_8fba1d7::{op_name}"
build/torch213-cxx11-cu130-x86_64-linux/metadata.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "name": "fp8-gemm",
3
- "id": "_fp8_gemm_cuda_bf15968",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
@@ -15,9 +15,9 @@
15
  "digest": {
16
  "algorithm": "sha256",
17
  "files": {
18
- "__init__.py": "hKsdFER2ZmYz36/zz9LYE7ddsK/R1dprHJFx+9yBzks=",
19
- "_fp8_gemm_cuda_bf15968.abi3.so": "kK3vPSK7mLfcGytI2GDw+i/mghJayzGxxVT4ieDxcc4=",
20
- "_ops.py": "wDFSPD8vh2K2qjj/9mdUYv6LrXuGz6MQCb2B/e8nqWs="
21
  }
22
  },
23
  "provenance": {
@@ -27,7 +27,7 @@
27
  "dirty": false
28
  },
29
  "kernel": {
30
- "sha": "bf15968fd9c281a7ca107e7696300fe091f588a2",
31
  "dirty": false
32
  }
33
  }
 
1
  {
2
  "name": "fp8-gemm",
3
+ "id": "_fp8_gemm_cuda_8fba1d7",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
 
15
  "digest": {
16
  "algorithm": "sha256",
17
  "files": {
18
+ "__init__.py": "HsFfsGY7AK/6Fziv4r2VQ+R2kDjS6hxKKgWqlA+zrKY=",
19
+ "_fp8_gemm_cuda_8fba1d7.abi3.so": "bzopByL+RJnJVmRH1mJ3YSe+6PtIhekscncdHEn1I2Q=",
20
+ "_ops.py": "ptfSaRMzscUfi27OPI9uPdaK9uAgUUrImeBJSSDv3kY="
21
  }
22
  },
23
  "provenance": {
 
27
  "dirty": false
28
  },
29
  "kernel": {
30
+ "sha": "8fba1d7f2e4e627b1a2c3c8018f01c0ca4f430ee",
31
  "dirty": false
32
  }
33
  }
build/torch213-cxx11-cu132-x86_64-linux/__init__.py CHANGED
@@ -37,6 +37,34 @@ def _fp8_linear_residual_bf16_fake(
37
  return None
38
 
39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  @torch.library.register_fake(add_op_namespace_prefix("fp8_blockwise_linear_bf16"))
41
  def _fp8_blockwise_linear_bf16_fake(
42
  input: torch.Tensor,
@@ -95,8 +123,8 @@ def select_fp8_linear_tile(m: int, n: int, k: int, variant: int = 0) -> str:
95
  variant = int(variant)
96
  if m <= 0 or n <= 0 or k <= 0:
97
  raise RuntimeError("m, n, and k must be positive")
98
- if k % 32 != 0:
99
- raise RuntimeError("k must be divisible by 32")
100
  capability = torch.cuda.get_device_capability() if torch.cuda.is_available() else None
101
  if capability == (11, 0):
102
  forced = {1: "sm110_sq_bf16", 2: "sm110_t1_bf16", 3: "sm110_wide_bf16"}
@@ -106,6 +134,12 @@ def select_fp8_linear_tile(m: int, n: int, k: int, variant: int = 0) -> str:
106
  raise RuntimeError("SM110 requires n and k divisible by 16")
107
  if variant:
108
  return forced[variant]
 
 
 
 
 
 
109
  if n >= 8 * k:
110
  return "sm110_wide_bf16"
111
  if m >= 128 and k >= 4 * n:
@@ -116,6 +150,8 @@ def select_fp8_linear_tile(m: int, n: int, k: int, variant: int = 0) -> str:
116
  return "sm110_wide_bf16"
117
  return "sm110_t1_bf16"
118
  if m == 1:
 
 
119
  if variant == 4:
120
  return "gemv_fp8_m1_w4"
121
  if variant == 8:
@@ -131,6 +167,8 @@ def select_fp8_linear_tile(m: int, n: int, k: int, variant: int = 0) -> str:
131
  return "gemv_fp8_m1_w16"
132
  if variant != 0:
133
  raise RuntimeError("small-M dispatcher currently supports variant=0 only")
 
 
134
  if m <= 16:
135
  if k % 256 == 0:
136
  return "ld_fp8_gemm_16x128x256_w4" if n % 128 == 0 else "ld_fp8_gemm_16x64x256_w4"
@@ -197,6 +235,56 @@ def fp8_linear_residual_bf16(
197
  return residual
198
 
199
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  def fp8_blockwise_linear_bf16(
201
  input: torch.Tensor,
202
  weight: torch.Tensor,
@@ -248,6 +336,9 @@ def fp8_blockwise_swiglu_quantize_fp8(
248
  __all__ = [
249
  "fp8_linear_bf16",
250
  "fp8_linear_residual_bf16",
 
 
 
251
  "fp8_blockwise_linear_bf16",
252
  "fp8_blockwise_swiglu_quantize_fp8",
253
  "select_fp8_linear_tile",
 
37
  return None
38
 
39
 
40
+ def _check_bias_linear_shapes(input, weight, bias, out) -> None:
41
+ if input.dim() != 2 or weight.dim() != 2:
42
+ raise RuntimeError("input and weight must be rank-2 tensors")
43
+ if input.shape[1] != weight.shape[1]:
44
+ raise RuntimeError("input and weight K dimensions must match")
45
+ if bias.shape != (weight.shape[0],):
46
+ raise RuntimeError("bias must have shape (weight.shape[0],)")
47
+ if out.shape != (input.shape[0], weight.shape[0]):
48
+ raise RuntimeError("out must have shape (input.shape[0], weight.shape[0])")
49
+
50
+
51
+ @torch.library.register_fake(add_op_namespace_prefix("fp8_linear_bias_bf16"))
52
+ def _fp8_linear_bias_bf16_fake(input, weight, bias, alpha: float, out) -> None:
53
+ _check_bias_linear_shapes(input, weight, bias, out)
54
+
55
+
56
+ @torch.library.register_fake(add_op_namespace_prefix("fp8_linear_bias_residual_bf16"))
57
+ def _fp8_linear_bias_residual_bf16_fake(
58
+ input, weight, bias, alpha: float, residual
59
+ ) -> None:
60
+ _check_bias_linear_shapes(input, weight, bias, residual)
61
+
62
+
63
+ @torch.library.register_fake(add_op_namespace_prefix("fp8_linear_bias_gelu_bf16"))
64
+ def _fp8_linear_bias_gelu_bf16_fake(input, weight, bias, alpha: float, out) -> None:
65
+ _check_bias_linear_shapes(input, weight, bias, out)
66
+
67
+
68
  @torch.library.register_fake(add_op_namespace_prefix("fp8_blockwise_linear_bf16"))
69
  def _fp8_blockwise_linear_bf16_fake(
70
  input: torch.Tensor,
 
123
  variant = int(variant)
124
  if m <= 0 or n <= 0 or k <= 0:
125
  raise RuntimeError("m, n, and k must be positive")
126
+ if k % 16 != 0:
127
+ raise RuntimeError("k must be divisible by 16")
128
  capability = torch.cuda.get_device_capability() if torch.cuda.is_available() else None
129
  if capability == (11, 0):
130
  forced = {1: "sm110_sq_bf16", 2: "sm110_t1_bf16", 3: "sm110_wide_bf16"}
 
134
  raise RuntimeError("SM110 requires n and k divisible by 16")
135
  if variant:
136
  return forced[variant]
137
+ if m >= 512 and k == 2048 and 2048 <= n <= 2560:
138
+ return "sm110_sq_bf16"
139
+ if m >= 512 and n >= 16 * k:
140
+ return "sm110_t1_bf16"
141
+ if m >= 512 and k >= 4 * n:
142
+ return "sm110_wide_bf16"
143
  if n >= 8 * k:
144
  return "sm110_wide_bf16"
145
  if m >= 128 and k >= 4 * n:
 
150
  return "sm110_wide_bf16"
151
  return "sm110_t1_bf16"
152
  if m == 1:
153
+ if k % 32:
154
+ raise RuntimeError("SM120 requires k divisible by 32")
155
  if variant == 4:
156
  return "gemv_fp8_m1_w4"
157
  if variant == 8:
 
167
  return "gemv_fp8_m1_w16"
168
  if variant != 0:
169
  raise RuntimeError("small-M dispatcher currently supports variant=0 only")
170
+ if k % 32:
171
+ raise RuntimeError("SM120 requires k divisible by 32")
172
  if m <= 16:
173
  if k % 256 == 0:
174
  return "ld_fp8_gemm_16x128x256_w4" if n % 128 == 0 else "ld_fp8_gemm_16x64x256_w4"
 
235
  return residual
236
 
237
 
238
+ def fp8_linear_bias_bf16(
239
+ input: torch.Tensor,
240
+ weight: torch.Tensor,
241
+ bias: torch.Tensor,
242
+ alpha: float = 1.0,
243
+ out: torch.Tensor | None = None,
244
+ ) -> torch.Tensor:
245
+ """SM110 FP8 linear with fused BF16 bias and BF16 output."""
246
+ if out is None:
247
+ out = torch.empty(
248
+ (input.shape[0], weight.shape[0]),
249
+ device=input.device,
250
+ dtype=torch.bfloat16,
251
+ )
252
+ ops.fp8_linear_bias_bf16(input, weight, bias, float(alpha), out)
253
+ return out
254
+
255
+
256
+ def fp8_linear_bias_residual_bf16(
257
+ input: torch.Tensor,
258
+ weight: torch.Tensor,
259
+ bias: torch.Tensor,
260
+ residual: torch.Tensor,
261
+ alpha: float = 1.0,
262
+ ) -> torch.Tensor:
263
+ """SM110 fused ``residual += alpha * input @ weight.T + bias``."""
264
+ ops.fp8_linear_bias_residual_bf16(
265
+ input, weight, bias, float(alpha), residual
266
+ )
267
+ return residual
268
+
269
+
270
+ def fp8_linear_bias_gelu_bf16(
271
+ input: torch.Tensor,
272
+ weight: torch.Tensor,
273
+ bias: torch.Tensor,
274
+ alpha: float = 1.0,
275
+ out: torch.Tensor | None = None,
276
+ ) -> torch.Tensor:
277
+ """SM110 FP8 linear with fused BF16 bias and GELU epilogue."""
278
+ if out is None:
279
+ out = torch.empty(
280
+ (input.shape[0], weight.shape[0]),
281
+ device=input.device,
282
+ dtype=torch.bfloat16,
283
+ )
284
+ ops.fp8_linear_bias_gelu_bf16(input, weight, bias, float(alpha), out)
285
+ return out
286
+
287
+
288
  def fp8_blockwise_linear_bf16(
289
  input: torch.Tensor,
290
  weight: torch.Tensor,
 
336
  __all__ = [
337
  "fp8_linear_bf16",
338
  "fp8_linear_residual_bf16",
339
+ "fp8_linear_bias_bf16",
340
+ "fp8_linear_bias_residual_bf16",
341
+ "fp8_linear_bias_gelu_bf16",
342
  "fp8_blockwise_linear_bf16",
343
  "fp8_blockwise_swiglu_quantize_fp8",
344
  "select_fp8_linear_tile",
build/torch213-cxx11-cu132-x86_64-linux/{_fp8_gemm_cuda_bf15968.abi3.so → _fp8_gemm_cuda_8fba1d7.abi3.so} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:e5395ce05668ccf4bec5f12109f073fb6ce743810f486ea98d67de77574a17b7
3
- size 5431368
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:357edcc14c6ab989908a21219b641179346b797eb5ea9d3b302aef7b3bee3988
3
+ size 5710312
build/torch213-cxx11-cu132-x86_64-linux/_ops.py CHANGED
@@ -1,9 +1,9 @@
1
  import torch
2
- from . import _fp8_gemm_cuda_bf15968
3
- ops = torch.ops._fp8_gemm_cuda_bf15968
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
- return f"_fp8_gemm_cuda_bf15968::{op_name}"
 
1
  import torch
2
+ from . import _fp8_gemm_cuda_8fba1d7
3
+ ops = torch.ops._fp8_gemm_cuda_8fba1d7
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
+ return f"_fp8_gemm_cuda_8fba1d7::{op_name}"
build/torch213-cxx11-cu132-x86_64-linux/metadata.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "name": "fp8-gemm",
3
- "id": "_fp8_gemm_cuda_bf15968",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
@@ -15,9 +15,9 @@
15
  "digest": {
16
  "algorithm": "sha256",
17
  "files": {
18
- "__init__.py": "hKsdFER2ZmYz36/zz9LYE7ddsK/R1dprHJFx+9yBzks=",
19
- "_fp8_gemm_cuda_bf15968.abi3.so": "5Tlc4FZozPS+xfEhCfBz+2znQ4EPSG6pjWfed1dKF7c=",
20
- "_ops.py": "wDFSPD8vh2K2qjj/9mdUYv6LrXuGz6MQCb2B/e8nqWs="
21
  }
22
  },
23
  "provenance": {
@@ -27,7 +27,7 @@
27
  "dirty": false
28
  },
29
  "kernel": {
30
- "sha": "bf15968fd9c281a7ca107e7696300fe091f588a2",
31
  "dirty": false
32
  }
33
  }
 
1
  {
2
  "name": "fp8-gemm",
3
+ "id": "_fp8_gemm_cuda_8fba1d7",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
 
15
  "digest": {
16
  "algorithm": "sha256",
17
  "files": {
18
+ "__init__.py": "HsFfsGY7AK/6Fziv4r2VQ+R2kDjS6hxKKgWqlA+zrKY=",
19
+ "_fp8_gemm_cuda_8fba1d7.abi3.so": "NX7cwUxquYmQiiEhm2QReTRreX616p07MCrvezvuOYg=",
20
+ "_ops.py": "ptfSaRMzscUfi27OPI9uPdaK9uAgUUrImeBJSSDv3kY="
21
  }
22
  },
23
  "provenance": {
 
27
  "dirty": false
28
  },
29
  "kernel": {
30
+ "sha": "8fba1d7f2e4e627b1a2c3c8018f01c0ca4f430ee",
31
  "dirty": false
32
  }
33
  }