liangsu9988 commited on
Commit
cf4e346
·
verified ·
1 Parent(s): 3086b82

Promote latest kernel artifacts to main

Browse files
Files changed (33) hide show
  1. README.md +0 -9
  2. benchmarks/benchmark.py +127 -12
  3. build/torch211-cxx11-cu128-x86_64-linux/__init__.py +171 -3
  4. build/torch211-cxx11-cu128-x86_64-linux/{_fp4_gemm_cuda_7e2e5b9.abi3.so → _fp4_gemm_cuda_7781728.abi3.so} +2 -2
  5. build/torch211-cxx11-cu128-x86_64-linux/_ops.py +3 -3
  6. build/torch211-cxx11-cu128-x86_64-linux/metadata.json +15 -4
  7. build/torch211-cxx11-cu130-aarch64-linux/__init__.py +254 -0
  8. build/{torch212-cxx11-cu132-x86_64-linux/_fp4_gemm_cuda_7e2e5b9.abi3.so → torch211-cxx11-cu130-aarch64-linux/_fp4_gemm_cuda_7781728.abi3.so} +2 -2
  9. build/torch211-cxx11-cu130-aarch64-linux/_ops.py +6 -0
  10. build/torch211-cxx11-cu130-aarch64-linux/fp4_gemm/__init__.py +14 -0
  11. build/torch211-cxx11-cu130-aarch64-linux/metadata.json +32 -0
  12. build/torch211-cxx11-cu130-x86_64-linux/__init__.py +171 -3
  13. build/torch211-cxx11-cu130-x86_64-linux/{_fp4_gemm_cuda_7e2e5b9.abi3.so → _fp4_gemm_cuda_7781728.abi3.so} +2 -2
  14. build/torch211-cxx11-cu130-x86_64-linux/_ops.py +3 -3
  15. build/torch211-cxx11-cu130-x86_64-linux/metadata.json +15 -4
  16. build/torch212-cxx11-cu130-x86_64-linux/__init__.py +226 -5
  17. build/torch212-cxx11-cu130-x86_64-linux/{_fp4_gemm_cuda_7e2e5b9.abi3.so → _fp4_gemm_cuda_b46a817.abi3.so} +2 -2
  18. build/torch212-cxx11-cu130-x86_64-linux/_ops.py +3 -3
  19. build/torch212-cxx11-cu130-x86_64-linux/fp4_gemm/__init__.py +0 -26
  20. build/torch212-cxx11-cu130-x86_64-linux/metadata.json +16 -5
  21. build/torch212-cxx11-cu132-x86_64-linux/__init__.py +226 -5
  22. build/torch212-cxx11-cu132-x86_64-linux/_fp4_gemm_cuda_b46a817.abi3.so +3 -0
  23. build/torch212-cxx11-cu132-x86_64-linux/_ops.py +3 -3
  24. build/torch212-cxx11-cu132-x86_64-linux/fp4_gemm/__init__.py +0 -26
  25. build/torch212-cxx11-cu132-x86_64-linux/metadata.json +16 -5
  26. build/torch213-cxx11-cu130-x86_64-linux/__init__.py +307 -0
  27. build/torch213-cxx11-cu130-x86_64-linux/_fp4_gemm_cuda_b46a817.abi3.so +3 -0
  28. build/torch213-cxx11-cu130-x86_64-linux/_ops.py +9 -0
  29. build/torch213-cxx11-cu130-x86_64-linux/metadata.json +33 -0
  30. build/torch213-cxx11-cu132-x86_64-linux/__init__.py +307 -0
  31. build/torch213-cxx11-cu132-x86_64-linux/_fp4_gemm_cuda_b46a817.abi3.so +3 -0
  32. build/torch213-cxx11-cu132-x86_64-linux/_ops.py +9 -0
  33. build/torch213-cxx11-cu132-x86_64-linux/metadata.json +33 -0
README.md DELETED
@@ -1,9 +0,0 @@
1
- # flashrt/fp4-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/fp4-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.
 
 
 
 
 
 
 
 
 
 
benchmarks/benchmark.py CHANGED
@@ -6,6 +6,7 @@ from __future__ import annotations
6
  import argparse
7
  import importlib.util
8
  import json
 
9
  import sys
10
  from dataclasses import asdict, dataclass
11
  from pathlib import Path
@@ -24,9 +25,13 @@ class BenchResult:
24
  N: int
25
  K: int
26
  variant: int
 
27
  flashrt_us: float
28
- torch_reference_us: float
29
- speedup_vs_reference: float
 
 
 
30
  max_abs: float
31
  mean_abs: float
32
  p99_abs: float
@@ -58,7 +63,7 @@ def measure(fn, warmup: int, iters: int) -> float:
58
  return float(start.elapsed_time(end) * 1000.0 / iters)
59
 
60
 
61
- def bench_case(helpers, ops, name: str, shape: tuple[int, int, int], warmup: int, iters: int) -> list[BenchResult]:
62
  m, n, k = shape
63
  a_packed, b_packed, sfa, sfb, expected = helpers.prepare_quantized(ops, m, n, k)
64
  a_deq = torch.empty((m, k), device="cuda", dtype=torch.float16)
@@ -70,15 +75,45 @@ def bench_case(helpers, ops, name: str, shape: tuple[int, int, int], warmup: int
70
  def torch_ref():
71
  return (a_deq.float() @ b_deq.float().T).to(torch.bfloat16)
72
 
73
- torch_us = measure(torch_ref, warmup, iters)
 
 
 
74
  results: list[BenchResult] = []
75
- for variant in (0, 1, 2):
 
76
  out = torch.empty((m, n), device="cuda", dtype=torch.bfloat16)
77
- ops.fp4_w4a16_linear_bf16(a_packed, b_packed, sfa, sfb, out, 1.0, variant)
78
  torch.cuda.synchronize()
79
  max_abs, mean_abs, p99_abs, cosine = helpers.metrics(out, expected)
80
  flashrt_us = measure(
81
- lambda: ops.fp4_w4a16_linear_bf16(a_packed, b_packed, sfa, sfb, out, 1.0, variant),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  warmup,
83
  iters,
84
  )
@@ -89,9 +124,13 @@ def bench_case(helpers, ops, name: str, shape: tuple[int, int, int], warmup: int
89
  N=n,
90
  K=k,
91
  variant=variant,
 
92
  flashrt_us=flashrt_us,
93
- torch_reference_us=torch_us,
94
- speedup_vs_reference=torch_us / flashrt_us,
 
 
 
95
  max_abs=max_abs,
96
  mean_abs=mean_abs,
97
  p99_abs=p99_abs,
@@ -102,31 +141,107 @@ def bench_case(helpers, ops, name: str, shape: tuple[int, int, int], warmup: int
102
  return results
103
 
104
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  def main() -> int:
106
  parser = argparse.ArgumentParser()
107
- parser.add_argument("--mode", choices=["smoke", "headline"], default="headline")
 
 
 
 
108
  parser.add_argument("--warmup", type=int, default=20)
109
  parser.add_argument("--iterations", type=int, default=100)
110
  parser.add_argument("--json-out", default=None)
111
  args = parser.parse_args()
112
 
113
  helpers = load_helpers()
114
- ops = helpers.load_source_ops()
 
 
 
 
 
 
 
 
 
 
 
 
115
  shapes = {
116
  "small_m16_n128_k128": (16, 128, 128),
117
  "small_m32_n256_k256": (32, 256, 256),
118
  "mlp_tile_m64_n512_k512": (64, 512, 512),
 
 
 
 
119
  }
120
  if args.mode == "smoke":
121
  shapes = {"small_m16_n128_k128": shapes["small_m16_n128_k128"]}
 
 
122
  results: list[BenchResult] = []
123
  for name, shape in shapes.items():
124
- results.extend(bench_case(helpers, ops, name, shape, args.warmup, args.iterations))
 
 
 
 
 
 
 
 
125
  payload = {
126
  "mode": args.mode,
 
127
  "device": torch.cuda.get_device_name(),
128
  "torch": torch.__version__,
129
  "results": [asdict(item) for item in results],
 
130
  }
131
  print(json.dumps(payload, indent=2))
132
  if args.json_out:
 
6
  import argparse
7
  import importlib.util
8
  import json
9
+ import os
10
  import sys
11
  from dataclasses import asdict, dataclass
12
  from pathlib import Path
 
25
  N: int
26
  K: int
27
  variant: int
28
+ native_us: float
29
  flashrt_us: float
30
+ torch_eager_us: float
31
+ torch_compile_us: float
32
+ speedup_vs_eager: float
33
+ speedup_vs_compile: float
34
+ wrapper_over_native: float
35
  max_abs: float
36
  mean_abs: float
37
  p99_abs: float
 
63
  return float(start.elapsed_time(end) * 1000.0 / iters)
64
 
65
 
66
+ def bench_case(helpers, ops, native, name: str, shape: tuple[int, int, int], warmup: int, iters: int) -> list[BenchResult]:
67
  m, n, k = shape
68
  a_packed, b_packed, sfa, sfb, expected = helpers.prepare_quantized(ops, m, n, k)
69
  a_deq = torch.empty((m, k), device="cuda", dtype=torch.float16)
 
75
  def torch_ref():
76
  return (a_deq.float() @ b_deq.float().T).to(torch.bfloat16)
77
 
78
+ torch_eager_us = measure(torch_ref, warmup, iters)
79
+ compiled_ref = torch.compile(torch_ref, mode="max-autotune-no-cudagraphs")
80
+ torch_compile_us = measure(compiled_ref, warmup, iters)
81
+ stream = torch.cuda.current_stream().cuda_stream
82
  results: list[BenchResult] = []
83
+ variants = (-1, 0, 1, 2) if torch.cuda.get_device_capability(0) == (11, 0) else (0, 1, 2)
84
+ for variant in variants:
85
  out = torch.empty((m, n), device="cuda", dtype=torch.bfloat16)
86
+ ops.nvfp4_gemm_bf16(a_packed, b_packed, sfa, sfb, out, 1.0, variant)
87
  torch.cuda.synchronize()
88
  max_abs, mean_abs, p99_abs, cosine = helpers.metrics(out, expected)
89
  flashrt_us = measure(
90
+ lambda: ops.nvfp4_gemm_bf16(a_packed, b_packed, sfa, sfb, out, 1.0, variant),
91
+ warmup,
92
+ iters,
93
+ )
94
+ native_variant = variant
95
+ if native_variant < 0:
96
+ native_variant = helpers.select_sm110_variant(shape)
97
+ native_function = (
98
+ native.fp4_w4a16_gemm_sm120_bf16out
99
+ if native_variant == 0
100
+ else native.fp4_w4a16_gemm_sm120_bf16out_widen
101
+ if native_variant == 1
102
+ else native.fp4_w4a16_gemm_sm120_bf16out_pingpong
103
+ )
104
+ native_us = measure(
105
+ lambda: native_function(
106
+ a_packed.data_ptr(),
107
+ b_packed.data_ptr(),
108
+ out.data_ptr(),
109
+ m,
110
+ n,
111
+ k,
112
+ sfa.data_ptr(),
113
+ sfb.data_ptr(),
114
+ 1.0,
115
+ stream,
116
+ ),
117
  warmup,
118
  iters,
119
  )
 
124
  N=n,
125
  K=k,
126
  variant=variant,
127
+ native_us=native_us,
128
  flashrt_us=flashrt_us,
129
+ torch_eager_us=torch_eager_us,
130
+ torch_compile_us=torch_compile_us,
131
+ speedup_vs_eager=torch_eager_us / flashrt_us,
132
+ speedup_vs_compile=torch_compile_us / flashrt_us,
133
+ wrapper_over_native=flashrt_us / native_us,
134
  max_abs=max_abs,
135
  mean_abs=mean_abs,
136
  p99_abs=p99_abs,
 
141
  return results
142
 
143
 
144
+ def bench_bf16_producer(ops, native, k: int, warmup: int, iters: int):
145
+ x = torch.randn((1, k), device="cuda", dtype=torch.bfloat16)
146
+ direct_packed, direct_sfa = ops.alloc_fp4(1, k)
147
+ compat_packed, compat_sfa = ops.alloc_fp4(1, k)
148
+ native_packed, native_sfa = ops.alloc_fp4(1, k)
149
+ stream = torch.cuda.current_stream().cuda_stream
150
+
151
+ def direct():
152
+ ops.quantize_fp4_sfa_bf16(
153
+ x, direct_packed, direct_sfa, False
154
+ )
155
+
156
+ def compat():
157
+ ops.quantize_fp4_sfa_fp16(
158
+ x.to(torch.float16), compat_packed, compat_sfa, False
159
+ )
160
+
161
+ def native_direct():
162
+ native.quantize_bf16_to_nvfp4_swizzled(
163
+ x.data_ptr(), native_packed.data_ptr(), native_sfa.data_ptr(),
164
+ 1, k, stream,
165
+ )
166
+
167
+ direct()
168
+ compat()
169
+ torch.cuda.synchronize()
170
+ direct_us = measure(direct, warmup, iters)
171
+ compat_us = measure(compat, warmup, iters)
172
+ native_us = measure(native_direct, warmup, iters)
173
+ return {
174
+ "M": 1,
175
+ "K": k,
176
+ "direct_bf16_us": direct_us,
177
+ "cast_plus_fp16_us": compat_us,
178
+ "native_bf16_us": native_us,
179
+ "speedup_vs_cast_plus_fp16": compat_us / direct_us,
180
+ "wrapper_over_native": direct_us / native_us,
181
+ "packed_exact_vs_fp16_contract": bool(
182
+ torch.equal(direct_packed, compat_packed)
183
+ ),
184
+ "note": "native_bf16 uses a distinct FlashRT quantization strategy",
185
+ }
186
+
187
+
188
  def main() -> int:
189
  parser = argparse.ArgumentParser()
190
+ parser.add_argument("--backend", choices=["source", "installed"], default="source")
191
+ parser.add_argument("--artifact", default=None)
192
+ parser.add_argument(
193
+ "--mode", choices=["smoke", "headline", "thor-models"], default="headline"
194
+ )
195
  parser.add_argument("--warmup", type=int, default=20)
196
  parser.add_argument("--iterations", type=int, default=100)
197
  parser.add_argument("--json-out", default=None)
198
  args = parser.parse_args()
199
 
200
  helpers = load_helpers()
201
+ native_root = Path(
202
+ os.environ.get("FLASHRT_NATIVE_ROOT", str(ROOT.parent / "official" / "FlashRT"))
203
+ )
204
+ sys.path.insert(0, str(native_root))
205
+ try:
206
+ import flash_rt.flash_rt_kernels as native
207
+ finally:
208
+ sys.path.pop(0)
209
+ ops = (
210
+ helpers.load_source_ops()
211
+ if args.backend == "source"
212
+ else helpers.load_installed_ops(args.artifact)
213
+ )
214
  shapes = {
215
  "small_m16_n128_k128": (16, 128, 128),
216
  "small_m32_n256_k256": (32, 256, 256),
217
  "mlp_tile_m64_n512_k512": (64, 512, 512),
218
+ "groot_dit_projection": (51, 1536, 1536),
219
+ "vla_projection": (105, 2048, 2048),
220
+ "motus_up": (360, 14336, 3072),
221
+ "motus_down": (360, 3072, 14336),
222
  }
223
  if args.mode == "smoke":
224
  shapes = {"small_m16_n128_k128": shapes["small_m16_n128_k128"]}
225
+ elif args.mode == "thor-models":
226
+ shapes = dict(helpers.SM110_SHAPES)
227
  results: list[BenchResult] = []
228
  for name, shape in shapes.items():
229
+ results.extend(
230
+ bench_case(
231
+ helpers, ops, native, name, shape, args.warmup, args.iterations
232
+ )
233
+ )
234
+ producer_results = [
235
+ bench_bf16_producer(ops, native, k, args.warmup, args.iterations)
236
+ for k in (5120, 6144, 17408)
237
+ ]
238
  payload = {
239
  "mode": args.mode,
240
+ "backend": args.backend,
241
  "device": torch.cuda.get_device_name(),
242
  "torch": torch.__version__,
243
  "results": [asdict(item) for item in results],
244
+ "bf16_producer_results": producer_results,
245
  }
246
  print(json.dumps(payload, indent=2))
247
  if args.json_out:
build/torch211-cxx11-cu128-x86_64-linux/__init__.py CHANGED
@@ -23,7 +23,7 @@ def _alloc_fp4(rows: int, dim: int, device: torch.device | str):
23
  )
24
 
25
 
26
- @torch.library.register_fake(add_op_namespace_prefix("fp4_w4a16_linear_bf16"))
27
  def _linear_fake(
28
  a_packed: torch.Tensor,
29
  b_packed: torch.Tensor,
@@ -36,6 +36,19 @@ def _linear_fake(
36
  return None
37
 
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  @torch.library.register_fake(add_op_namespace_prefix("quantize_fp4_sfa_fp16"))
40
  def _quant_fake(x: torch.Tensor, packed: torch.Tensor, sfa: torch.Tensor, is_sfb: bool = False) -> None:
41
  return None
@@ -46,6 +59,33 @@ def _dequant_fake(packed: torch.Tensor, sfa: torch.Tensor, out: torch.Tensor, is
46
  return None
47
 
48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  def quantize_fp4_sfa_fp16(
50
  x: torch.Tensor,
51
  packed: torch.Tensor | None = None,
@@ -70,7 +110,7 @@ def dequantize_fp4_sfa_fp16(
70
  return out
71
 
72
 
73
- def fp4_w4a16_linear_bf16(
74
  a_packed: torch.Tensor,
75
  b_packed: torch.Tensor,
76
  sfa: torch.Tensor,
@@ -81,6 +121,134 @@ def fp4_w4a16_linear_bf16(
81
  ) -> torch.Tensor:
82
  if out is None:
83
  out = torch.empty((a_packed.shape[0], b_packed.shape[0]), device=a_packed.device, dtype=torch.bfloat16)
84
- ops.fp4_w4a16_linear_bf16(a_packed, b_packed, sfa, sfb, out, float(alpha), int(variant))
85
  return out
86
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  )
24
 
25
 
26
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_bf16"))
27
  def _linear_fake(
28
  a_packed: torch.Tensor,
29
  b_packed: torch.Tensor,
 
36
  return None
37
 
38
 
39
+ @torch.library.register_fake(add_op_namespace_prefix("fp4_w4a16_linear_bf16"))
40
+ def _legacy_linear_fake(
41
+ a_packed: torch.Tensor,
42
+ b_packed: torch.Tensor,
43
+ sfa: torch.Tensor,
44
+ sfb: torch.Tensor,
45
+ out: torch.Tensor,
46
+ alpha: float = 1.0,
47
+ variant: int = 0,
48
+ ) -> None:
49
+ return None
50
+
51
+
52
  @torch.library.register_fake(add_op_namespace_prefix("quantize_fp4_sfa_fp16"))
53
  def _quant_fake(x: torch.Tensor, packed: torch.Tensor, sfa: torch.Tensor, is_sfb: bool = False) -> None:
54
  return None
 
59
  return None
60
 
61
 
62
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_residual_bf16"))
63
+ def _residual_fake(a, b, sfa, sfb, residual, out, alpha: float = 1.0) -> None:
64
+ return None
65
+
66
+
67
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_bias_gelu_bf16"))
68
+ def _bias_gelu_fake(a, b, sfa, sfb, bias, out, alpha: float = 1.0) -> None:
69
+ return None
70
+
71
+
72
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_bias_gelu_nvfp4"))
73
+ def _bias_gelu_nvfp4_fake(
74
+ a, b, sfa, sfb, bias, out_packed, out_sfa, alpha: float = 1.0
75
+ ) -> None:
76
+ return None
77
+
78
+
79
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_streamk_bf16"))
80
+ def _streamk_fake(a, b, sfa, sfb, out, alpha: float = 1.0) -> None:
81
+ return None
82
+
83
+
84
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_streamk_bias_bf16"))
85
+ def _streamk_bias_fake(a, b, sfa, sfb, bias, out, alpha: float = 1.0) -> None:
86
+ return None
87
+
88
+
89
  def quantize_fp4_sfa_fp16(
90
  x: torch.Tensor,
91
  packed: torch.Tensor | None = None,
 
110
  return out
111
 
112
 
113
+ def nvfp4_gemm_bf16(
114
  a_packed: torch.Tensor,
115
  b_packed: torch.Tensor,
116
  sfa: torch.Tensor,
 
121
  ) -> torch.Tensor:
122
  if out is None:
123
  out = torch.empty((a_packed.shape[0], b_packed.shape[0]), device=a_packed.device, dtype=torch.bfloat16)
124
+ ops.nvfp4_gemm_bf16(a_packed, b_packed, sfa, sfb, out, float(alpha), int(variant))
125
  return out
126
 
127
+
128
+ def fp4_w4a16_linear_bf16(
129
+ a_packed: torch.Tensor,
130
+ b_packed: torch.Tensor,
131
+ sfa: torch.Tensor,
132
+ sfb: torch.Tensor,
133
+ alpha: float = 1.0,
134
+ out: torch.Tensor | None = None,
135
+ variant: int = 0,
136
+ ) -> torch.Tensor:
137
+ """Compatibility alias for :func:`nvfp4_gemm_bf16`."""
138
+ return nvfp4_gemm_bf16(
139
+ a_packed, b_packed, sfa, sfb, alpha=alpha, out=out, variant=variant
140
+ )
141
+
142
+
143
+ def nvfp4_gemm_residual_bf16(
144
+ a_packed: torch.Tensor,
145
+ b_packed: torch.Tensor,
146
+ sfa: torch.Tensor,
147
+ sfb: torch.Tensor,
148
+ residual: torch.Tensor,
149
+ alpha: float = 1.0,
150
+ out: torch.Tensor | None = None,
151
+ ) -> torch.Tensor:
152
+ if out is None:
153
+ out = torch.empty_like(residual)
154
+ ops.nvfp4_gemm_residual_bf16(
155
+ a_packed, b_packed, sfa, sfb, residual, out, float(alpha)
156
+ )
157
+ return out
158
+
159
+
160
+ def nvfp4_gemm_bias_gelu_bf16(
161
+ a_packed: torch.Tensor,
162
+ b_packed: torch.Tensor,
163
+ sfa: torch.Tensor,
164
+ sfb: torch.Tensor,
165
+ bias: torch.Tensor,
166
+ alpha: float = 1.0,
167
+ out: torch.Tensor | None = None,
168
+ ) -> torch.Tensor:
169
+ if out is None:
170
+ out = torch.empty(
171
+ (a_packed.shape[0], b_packed.shape[0]),
172
+ device=a_packed.device,
173
+ dtype=torch.bfloat16,
174
+ )
175
+ ops.nvfp4_gemm_bias_gelu_bf16(
176
+ a_packed, b_packed, sfa, sfb, bias, out, float(alpha)
177
+ )
178
+ return out
179
+
180
+
181
+ def nvfp4_gemm_bias_gelu_nvfp4(
182
+ a_packed: torch.Tensor,
183
+ b_packed: torch.Tensor,
184
+ sfa: torch.Tensor,
185
+ sfb: torch.Tensor,
186
+ bias: torch.Tensor,
187
+ alpha: float = 1.0,
188
+ out_packed: torch.Tensor | None = None,
189
+ out_sfa: torch.Tensor | None = None,
190
+ ) -> tuple[torch.Tensor, torch.Tensor]:
191
+ m, n = a_packed.shape[0], b_packed.shape[0]
192
+ if out_packed is None:
193
+ out_packed = torch.empty((m, n // 2), device=a_packed.device, dtype=torch.uint8)
194
+ if out_sfa is None:
195
+ out_sfa = torch.empty((sfa_size_bytes(m, n),), device=a_packed.device, dtype=torch.uint8)
196
+ ops.nvfp4_gemm_bias_gelu_nvfp4(
197
+ a_packed, b_packed, sfa, sfb, bias, out_packed, out_sfa, float(alpha)
198
+ )
199
+ return out_packed, out_sfa
200
+
201
+
202
+ def nvfp4_gemm_streamk_bf16(
203
+ a_packed: torch.Tensor,
204
+ b_packed: torch.Tensor,
205
+ sfa: torch.Tensor,
206
+ sfb: torch.Tensor,
207
+ alpha: float = 1.0,
208
+ out: torch.Tensor | None = None,
209
+ ) -> torch.Tensor:
210
+ if out is None:
211
+ out = torch.empty(
212
+ (a_packed.shape[0], b_packed.shape[0]),
213
+ device=a_packed.device,
214
+ dtype=torch.bfloat16,
215
+ )
216
+ ops.nvfp4_gemm_streamk_bf16(
217
+ a_packed, b_packed, sfa, sfb, out, float(alpha)
218
+ )
219
+ return out
220
+
221
+
222
+ def nvfp4_gemm_streamk_bias_bf16(
223
+ a_packed: torch.Tensor,
224
+ b_packed: torch.Tensor,
225
+ sfa: torch.Tensor,
226
+ sfb: torch.Tensor,
227
+ bias: torch.Tensor,
228
+ alpha: float = 1.0,
229
+ out: torch.Tensor | None = None,
230
+ ) -> torch.Tensor:
231
+ if out is None:
232
+ out = torch.empty(
233
+ (a_packed.shape[0], b_packed.shape[0]),
234
+ device=a_packed.device,
235
+ dtype=torch.bfloat16,
236
+ )
237
+ ops.nvfp4_gemm_streamk_bias_bf16(
238
+ a_packed, b_packed, sfa, sfb, bias, out, float(alpha)
239
+ )
240
+ return out
241
+
242
+
243
+ __all__ = [
244
+ "dequantize_fp4_sfa_fp16",
245
+ "fp4_w4a16_linear_bf16",
246
+ "nvfp4_gemm_bf16",
247
+ "nvfp4_gemm_bias_gelu_bf16",
248
+ "nvfp4_gemm_bias_gelu_nvfp4",
249
+ "nvfp4_gemm_residual_bf16",
250
+ "nvfp4_gemm_streamk_bf16",
251
+ "nvfp4_gemm_streamk_bias_bf16",
252
+ "quantize_fp4_sfa_fp16",
253
+ "sfa_size_bytes",
254
+ ]
build/torch211-cxx11-cu128-x86_64-linux/{_fp4_gemm_cuda_7e2e5b9.abi3.so → _fp4_gemm_cuda_7781728.abi3.so} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:d031c5d46ab5e14b13f68565ad53dff18a7f9ee76296b8158f626b11b50f61ef
3
- size 671608
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:43c2606ea93854faa4bd43f78835977beed5ddd1a005411ab41dc79988d99920
3
+ size 1633016
build/torch211-cxx11-cu128-x86_64-linux/_ops.py CHANGED
@@ -1,9 +1,9 @@
1
  import torch
2
- from . import _fp4_gemm_cuda_7e2e5b9
3
- ops = torch.ops._fp4_gemm_cuda_7e2e5b9
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
- return f"_fp4_gemm_cuda_7e2e5b9::{op_name}"
 
1
  import torch
2
+ from . import _fp4_gemm_cuda_7781728
3
+ ops = torch.ops._fp4_gemm_cuda_7781728
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
+ return f"_fp4_gemm_cuda_7781728::{op_name}"
build/torch211-cxx11-cu128-x86_64-linux/metadata.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "name": "fp4-gemm",
3
- "id": "_fp4_gemm_cuda_7e2e5b9",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
@@ -13,10 +13,21 @@
13
  "digest": {
14
  "algorithm": "sha256",
15
  "files": {
16
- "__init__.py": "WSLdLQD92ulRtOhSLoAhWgFYN6oucbbkTg19GAaltBs=",
17
- "_fp4_gemm_cuda_7e2e5b9.abi3.so": "0DHF1Gq14UsT9oVlrVPf8Yp/nudilrgVj2JrEbUPYe8=",
18
- "_ops.py": "UnZlP4anh/kfneg4T/V+ueYOufY4kzFv6zxKMKlaRuA=",
19
  "fp4_gemm/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY="
20
  }
 
 
 
 
 
 
 
 
 
 
 
21
  }
22
  }
 
1
  {
2
  "name": "fp4-gemm",
3
+ "id": "_fp4_gemm_cuda_7781728",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
 
13
  "digest": {
14
  "algorithm": "sha256",
15
  "files": {
16
+ "__init__.py": "FD6tCd6u2NRYfLKq1Uz7OYi+tZV5o9GDAb+KN3GX2oU=",
17
+ "_fp4_gemm_cuda_7781728.abi3.so": "Q8Jgbqk4VPqkvUP3iDWXe+7V3dGgBUEatB3HmYjZmSA=",
18
+ "_ops.py": "4wRBLd5HIJqgJskLFCRBmKJpvQfYeE9AmKTqIPQtPnw=",
19
  "fp4_gemm/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY="
20
  }
21
+ },
22
+ "provenance": {
23
+ "kernel-builder": {
24
+ "version": "0.17.0-dev0",
25
+ "sha": "19aaa6421e674e9fecc352bbae6eab81d19a6bf4",
26
+ "dirty": false
27
+ },
28
+ "kernel": {
29
+ "sha": "77817286c522d8f7abf8d2cd873e1f84a79357b9",
30
+ "dirty": false
31
+ }
32
  }
33
  }
build/torch211-cxx11-cu130-aarch64-linux/__init__.py ADDED
@@ -0,0 +1,254 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """FlashRT FP4 GEMM kernels."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import torch
6
+
7
+ from ._ops import add_op_namespace_prefix, ops
8
+
9
+
10
+ def sfa_size_bytes(rows: int, dim: int) -> int:
11
+ if rows <= 0 or dim <= 0 or dim % 16 != 0:
12
+ raise ValueError("rows must be positive and dim must be positive/divisible by 16")
13
+ n_blocks = dim // 16
14
+ n_row_super = (rows + 127) // 128
15
+ n_col_super = (n_blocks + 3) // 4
16
+ return n_row_super * n_col_super * 512
17
+
18
+
19
+ def _alloc_fp4(rows: int, dim: int, device: torch.device | str):
20
+ return (
21
+ torch.empty((rows, dim // 2), device=device, dtype=torch.uint8),
22
+ torch.empty((sfa_size_bytes(rows, dim),), device=device, dtype=torch.uint8),
23
+ )
24
+
25
+
26
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_bf16"))
27
+ def _linear_fake(
28
+ a_packed: torch.Tensor,
29
+ b_packed: torch.Tensor,
30
+ sfa: torch.Tensor,
31
+ sfb: torch.Tensor,
32
+ out: torch.Tensor,
33
+ alpha: float = 1.0,
34
+ variant: int = -1,
35
+ ) -> None:
36
+ return None
37
+
38
+
39
+ @torch.library.register_fake(add_op_namespace_prefix("fp4_w4a16_linear_bf16"))
40
+ def _legacy_linear_fake(
41
+ a_packed: torch.Tensor,
42
+ b_packed: torch.Tensor,
43
+ sfa: torch.Tensor,
44
+ sfb: torch.Tensor,
45
+ out: torch.Tensor,
46
+ alpha: float = 1.0,
47
+ variant: int = -1,
48
+ ) -> None:
49
+ return None
50
+
51
+
52
+ @torch.library.register_fake(add_op_namespace_prefix("quantize_fp4_sfa_fp16"))
53
+ def _quant_fake(x: torch.Tensor, packed: torch.Tensor, sfa: torch.Tensor, is_sfb: bool = False) -> None:
54
+ return None
55
+
56
+
57
+ @torch.library.register_fake(add_op_namespace_prefix("dequantize_fp4_sfa_fp16"))
58
+ def _dequant_fake(packed: torch.Tensor, sfa: torch.Tensor, out: torch.Tensor, is_sfb: bool = False) -> None:
59
+ return None
60
+
61
+
62
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_residual_bf16"))
63
+ def _residual_fake(a, b, sfa, sfb, residual, out, alpha: float = 1.0) -> None:
64
+ return None
65
+
66
+
67
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_bias_gelu_bf16"))
68
+ def _bias_gelu_fake(a, b, sfa, sfb, bias, out, alpha: float = 1.0) -> None:
69
+ return None
70
+
71
+
72
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_bias_gelu_nvfp4"))
73
+ def _bias_gelu_nvfp4_fake(
74
+ a, b, sfa, sfb, bias, out_packed, out_sfa, alpha: float = 1.0
75
+ ) -> None:
76
+ return None
77
+
78
+
79
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_streamk_bf16"))
80
+ def _streamk_fake(a, b, sfa, sfb, out, alpha: float = 1.0) -> None:
81
+ return None
82
+
83
+
84
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_streamk_bias_bf16"))
85
+ def _streamk_bias_fake(a, b, sfa, sfb, bias, out, alpha: float = 1.0) -> None:
86
+ return None
87
+
88
+
89
+ def quantize_fp4_sfa_fp16(
90
+ x: torch.Tensor,
91
+ packed: torch.Tensor | None = None,
92
+ sfa: torch.Tensor | None = None,
93
+ is_sfb: bool = False,
94
+ ):
95
+ if packed is None or sfa is None:
96
+ packed, sfa = _alloc_fp4(x.shape[0], x.shape[1], x.device)
97
+ ops.quantize_fp4_sfa_fp16(x, packed, sfa, bool(is_sfb))
98
+ return packed, sfa
99
+
100
+
101
+ def dequantize_fp4_sfa_fp16(
102
+ packed: torch.Tensor,
103
+ sfa: torch.Tensor,
104
+ out: torch.Tensor | None = None,
105
+ is_sfb: bool = False,
106
+ ) -> torch.Tensor:
107
+ if out is None:
108
+ out = torch.empty((packed.shape[0], packed.shape[1] * 2), device=packed.device, dtype=torch.float16)
109
+ ops.dequantize_fp4_sfa_fp16(packed, sfa, out, bool(is_sfb))
110
+ return out
111
+
112
+
113
+ def nvfp4_gemm_bf16(
114
+ a_packed: torch.Tensor,
115
+ b_packed: torch.Tensor,
116
+ sfa: torch.Tensor,
117
+ sfb: torch.Tensor,
118
+ alpha: float = 1.0,
119
+ out: torch.Tensor | None = None,
120
+ variant: int = -1,
121
+ ) -> torch.Tensor:
122
+ if out is None:
123
+ out = torch.empty((a_packed.shape[0], b_packed.shape[0]), device=a_packed.device, dtype=torch.bfloat16)
124
+ ops.nvfp4_gemm_bf16(a_packed, b_packed, sfa, sfb, out, float(alpha), int(variant))
125
+ return out
126
+
127
+
128
+ def fp4_w4a16_linear_bf16(
129
+ a_packed: torch.Tensor,
130
+ b_packed: torch.Tensor,
131
+ sfa: torch.Tensor,
132
+ sfb: torch.Tensor,
133
+ alpha: float = 1.0,
134
+ out: torch.Tensor | None = None,
135
+ variant: int = -1,
136
+ ) -> torch.Tensor:
137
+ """Compatibility alias for :func:`nvfp4_gemm_bf16`."""
138
+ return nvfp4_gemm_bf16(
139
+ a_packed, b_packed, sfa, sfb, alpha=alpha, out=out, variant=variant
140
+ )
141
+
142
+
143
+ def nvfp4_gemm_residual_bf16(
144
+ a_packed: torch.Tensor,
145
+ b_packed: torch.Tensor,
146
+ sfa: torch.Tensor,
147
+ sfb: torch.Tensor,
148
+ residual: torch.Tensor,
149
+ alpha: float = 1.0,
150
+ out: torch.Tensor | None = None,
151
+ ) -> torch.Tensor:
152
+ if out is None:
153
+ out = torch.empty_like(residual)
154
+ ops.nvfp4_gemm_residual_bf16(
155
+ a_packed, b_packed, sfa, sfb, residual, out, float(alpha)
156
+ )
157
+ return out
158
+
159
+
160
+ def nvfp4_gemm_bias_gelu_bf16(
161
+ a_packed: torch.Tensor,
162
+ b_packed: torch.Tensor,
163
+ sfa: torch.Tensor,
164
+ sfb: torch.Tensor,
165
+ bias: torch.Tensor,
166
+ alpha: float = 1.0,
167
+ out: torch.Tensor | None = None,
168
+ ) -> torch.Tensor:
169
+ if out is None:
170
+ out = torch.empty(
171
+ (a_packed.shape[0], b_packed.shape[0]),
172
+ device=a_packed.device,
173
+ dtype=torch.bfloat16,
174
+ )
175
+ ops.nvfp4_gemm_bias_gelu_bf16(
176
+ a_packed, b_packed, sfa, sfb, bias, out, float(alpha)
177
+ )
178
+ return out
179
+
180
+
181
+ def nvfp4_gemm_bias_gelu_nvfp4(
182
+ a_packed: torch.Tensor,
183
+ b_packed: torch.Tensor,
184
+ sfa: torch.Tensor,
185
+ sfb: torch.Tensor,
186
+ bias: torch.Tensor,
187
+ alpha: float = 1.0,
188
+ out_packed: torch.Tensor | None = None,
189
+ out_sfa: torch.Tensor | None = None,
190
+ ) -> tuple[torch.Tensor, torch.Tensor]:
191
+ m, n = a_packed.shape[0], b_packed.shape[0]
192
+ if out_packed is None:
193
+ out_packed = torch.empty((m, n // 2), device=a_packed.device, dtype=torch.uint8)
194
+ if out_sfa is None:
195
+ out_sfa = torch.empty((sfa_size_bytes(m, n),), device=a_packed.device, dtype=torch.uint8)
196
+ ops.nvfp4_gemm_bias_gelu_nvfp4(
197
+ a_packed, b_packed, sfa, sfb, bias, out_packed, out_sfa, float(alpha)
198
+ )
199
+ return out_packed, out_sfa
200
+
201
+
202
+ def nvfp4_gemm_streamk_bf16(
203
+ a_packed: torch.Tensor,
204
+ b_packed: torch.Tensor,
205
+ sfa: torch.Tensor,
206
+ sfb: torch.Tensor,
207
+ alpha: float = 1.0,
208
+ out: torch.Tensor | None = None,
209
+ ) -> torch.Tensor:
210
+ if out is None:
211
+ out = torch.empty(
212
+ (a_packed.shape[0], b_packed.shape[0]),
213
+ device=a_packed.device,
214
+ dtype=torch.bfloat16,
215
+ )
216
+ ops.nvfp4_gemm_streamk_bf16(
217
+ a_packed, b_packed, sfa, sfb, out, float(alpha)
218
+ )
219
+ return out
220
+
221
+
222
+ def nvfp4_gemm_streamk_bias_bf16(
223
+ a_packed: torch.Tensor,
224
+ b_packed: torch.Tensor,
225
+ sfa: torch.Tensor,
226
+ sfb: torch.Tensor,
227
+ bias: torch.Tensor,
228
+ alpha: float = 1.0,
229
+ out: torch.Tensor | None = None,
230
+ ) -> torch.Tensor:
231
+ if out is None:
232
+ out = torch.empty(
233
+ (a_packed.shape[0], b_packed.shape[0]),
234
+ device=a_packed.device,
235
+ dtype=torch.bfloat16,
236
+ )
237
+ ops.nvfp4_gemm_streamk_bias_bf16(
238
+ a_packed, b_packed, sfa, sfb, bias, out, float(alpha)
239
+ )
240
+ return out
241
+
242
+
243
+ __all__ = [
244
+ "dequantize_fp4_sfa_fp16",
245
+ "fp4_w4a16_linear_bf16",
246
+ "nvfp4_gemm_bf16",
247
+ "nvfp4_gemm_bias_gelu_bf16",
248
+ "nvfp4_gemm_bias_gelu_nvfp4",
249
+ "nvfp4_gemm_residual_bf16",
250
+ "nvfp4_gemm_streamk_bf16",
251
+ "nvfp4_gemm_streamk_bias_bf16",
252
+ "quantize_fp4_sfa_fp16",
253
+ "sfa_size_bytes",
254
+ ]
build/{torch212-cxx11-cu132-x86_64-linux/_fp4_gemm_cuda_7e2e5b9.abi3.so → torch211-cxx11-cu130-aarch64-linux/_fp4_gemm_cuda_7781728.abi3.so} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:fd5e66f4faeddfb45f42d8467508f13b2e065fb5d3c52a8404dc6a765a1b891f
3
- size 724632
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ca5e0135a51929d6d3fdbb486ddfaf1de4b0626150eeb93a00de328036501acb
3
+ size 680560
build/torch211-cxx11-cu130-aarch64-linux/_ops.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _fp4_gemm_cuda_7781728
3
+ ops = torch.ops._fp4_gemm_cuda_7781728
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ return f"_fp4_gemm_cuda_7781728::{op_name}"
build/torch211-cxx11-cu130-aarch64-linux/fp4_gemm/__init__.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import ctypes
2
+ import importlib.util
3
+ import sys
4
+ from pathlib import Path
5
+
6
+ def _import_from_path(file_path: Path):
7
+ path_hash = '{:x}'.format(ctypes.c_size_t(hash(file_path.absolute())).value)
8
+ spec = importlib.util.spec_from_file_location(path_hash, file_path)
9
+ module = importlib.util.module_from_spec(spec)
10
+ sys.modules[path_hash] = module
11
+ spec.loader.exec_module(module)
12
+ return module
13
+
14
+ globals().update(vars(_import_from_path(Path(__file__).parent.parent / '__init__.py')))
build/torch211-cxx11-cu130-aarch64-linux/metadata.json ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "fp4-gemm",
3
+ "id": "_fp4_gemm_cuda_7781728",
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": "EJ8HPhVwOKhifotSgdwCmB6MRbtnP1S0QfUGOVascy0=",
17
+ "_fp4_gemm_cuda_7781728.abi3.so": "yl4BNaUZKdbT/btIbd+vHeSwYmFQ7rk6AN4ygDZQGss=",
18
+ "_ops.py": "V90sTDYZObC3Ga+eak9fZiO8p6DsMdNZaWpcnYd61Yo=",
19
+ "fp4_gemm/__init__.py": "v6p5XMfQzddhi1fLSAw4HX9CyS0rQsidvu9VsT01xi4="
20
+ }
21
+ },
22
+ "provenance": {
23
+ "kernel": {
24
+ "sha": "4c95454360b18c79bed75ec6346a7bac47ae2ca2",
25
+ "dirty": false
26
+ },
27
+ "validation": {
28
+ "torch": "2.11.0+cu130",
29
+ "cuda": "13.0"
30
+ }
31
+ }
32
+ }
build/torch211-cxx11-cu130-x86_64-linux/__init__.py CHANGED
@@ -23,7 +23,7 @@ def _alloc_fp4(rows: int, dim: int, device: torch.device | str):
23
  )
24
 
25
 
26
- @torch.library.register_fake(add_op_namespace_prefix("fp4_w4a16_linear_bf16"))
27
  def _linear_fake(
28
  a_packed: torch.Tensor,
29
  b_packed: torch.Tensor,
@@ -36,6 +36,19 @@ def _linear_fake(
36
  return None
37
 
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  @torch.library.register_fake(add_op_namespace_prefix("quantize_fp4_sfa_fp16"))
40
  def _quant_fake(x: torch.Tensor, packed: torch.Tensor, sfa: torch.Tensor, is_sfb: bool = False) -> None:
41
  return None
@@ -46,6 +59,33 @@ def _dequant_fake(packed: torch.Tensor, sfa: torch.Tensor, out: torch.Tensor, is
46
  return None
47
 
48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  def quantize_fp4_sfa_fp16(
50
  x: torch.Tensor,
51
  packed: torch.Tensor | None = None,
@@ -70,7 +110,7 @@ def dequantize_fp4_sfa_fp16(
70
  return out
71
 
72
 
73
- def fp4_w4a16_linear_bf16(
74
  a_packed: torch.Tensor,
75
  b_packed: torch.Tensor,
76
  sfa: torch.Tensor,
@@ -81,6 +121,134 @@ def fp4_w4a16_linear_bf16(
81
  ) -> torch.Tensor:
82
  if out is None:
83
  out = torch.empty((a_packed.shape[0], b_packed.shape[0]), device=a_packed.device, dtype=torch.bfloat16)
84
- ops.fp4_w4a16_linear_bf16(a_packed, b_packed, sfa, sfb, out, float(alpha), int(variant))
85
  return out
86
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  )
24
 
25
 
26
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_bf16"))
27
  def _linear_fake(
28
  a_packed: torch.Tensor,
29
  b_packed: torch.Tensor,
 
36
  return None
37
 
38
 
39
+ @torch.library.register_fake(add_op_namespace_prefix("fp4_w4a16_linear_bf16"))
40
+ def _legacy_linear_fake(
41
+ a_packed: torch.Tensor,
42
+ b_packed: torch.Tensor,
43
+ sfa: torch.Tensor,
44
+ sfb: torch.Tensor,
45
+ out: torch.Tensor,
46
+ alpha: float = 1.0,
47
+ variant: int = 0,
48
+ ) -> None:
49
+ return None
50
+
51
+
52
  @torch.library.register_fake(add_op_namespace_prefix("quantize_fp4_sfa_fp16"))
53
  def _quant_fake(x: torch.Tensor, packed: torch.Tensor, sfa: torch.Tensor, is_sfb: bool = False) -> None:
54
  return None
 
59
  return None
60
 
61
 
62
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_residual_bf16"))
63
+ def _residual_fake(a, b, sfa, sfb, residual, out, alpha: float = 1.0) -> None:
64
+ return None
65
+
66
+
67
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_bias_gelu_bf16"))
68
+ def _bias_gelu_fake(a, b, sfa, sfb, bias, out, alpha: float = 1.0) -> None:
69
+ return None
70
+
71
+
72
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_bias_gelu_nvfp4"))
73
+ def _bias_gelu_nvfp4_fake(
74
+ a, b, sfa, sfb, bias, out_packed, out_sfa, alpha: float = 1.0
75
+ ) -> None:
76
+ return None
77
+
78
+
79
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_streamk_bf16"))
80
+ def _streamk_fake(a, b, sfa, sfb, out, alpha: float = 1.0) -> None:
81
+ return None
82
+
83
+
84
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_streamk_bias_bf16"))
85
+ def _streamk_bias_fake(a, b, sfa, sfb, bias, out, alpha: float = 1.0) -> None:
86
+ return None
87
+
88
+
89
  def quantize_fp4_sfa_fp16(
90
  x: torch.Tensor,
91
  packed: torch.Tensor | None = None,
 
110
  return out
111
 
112
 
113
+ def nvfp4_gemm_bf16(
114
  a_packed: torch.Tensor,
115
  b_packed: torch.Tensor,
116
  sfa: torch.Tensor,
 
121
  ) -> torch.Tensor:
122
  if out is None:
123
  out = torch.empty((a_packed.shape[0], b_packed.shape[0]), device=a_packed.device, dtype=torch.bfloat16)
124
+ ops.nvfp4_gemm_bf16(a_packed, b_packed, sfa, sfb, out, float(alpha), int(variant))
125
  return out
126
 
127
+
128
+ def fp4_w4a16_linear_bf16(
129
+ a_packed: torch.Tensor,
130
+ b_packed: torch.Tensor,
131
+ sfa: torch.Tensor,
132
+ sfb: torch.Tensor,
133
+ alpha: float = 1.0,
134
+ out: torch.Tensor | None = None,
135
+ variant: int = 0,
136
+ ) -> torch.Tensor:
137
+ """Compatibility alias for :func:`nvfp4_gemm_bf16`."""
138
+ return nvfp4_gemm_bf16(
139
+ a_packed, b_packed, sfa, sfb, alpha=alpha, out=out, variant=variant
140
+ )
141
+
142
+
143
+ def nvfp4_gemm_residual_bf16(
144
+ a_packed: torch.Tensor,
145
+ b_packed: torch.Tensor,
146
+ sfa: torch.Tensor,
147
+ sfb: torch.Tensor,
148
+ residual: torch.Tensor,
149
+ alpha: float = 1.0,
150
+ out: torch.Tensor | None = None,
151
+ ) -> torch.Tensor:
152
+ if out is None:
153
+ out = torch.empty_like(residual)
154
+ ops.nvfp4_gemm_residual_bf16(
155
+ a_packed, b_packed, sfa, sfb, residual, out, float(alpha)
156
+ )
157
+ return out
158
+
159
+
160
+ def nvfp4_gemm_bias_gelu_bf16(
161
+ a_packed: torch.Tensor,
162
+ b_packed: torch.Tensor,
163
+ sfa: torch.Tensor,
164
+ sfb: torch.Tensor,
165
+ bias: torch.Tensor,
166
+ alpha: float = 1.0,
167
+ out: torch.Tensor | None = None,
168
+ ) -> torch.Tensor:
169
+ if out is None:
170
+ out = torch.empty(
171
+ (a_packed.shape[0], b_packed.shape[0]),
172
+ device=a_packed.device,
173
+ dtype=torch.bfloat16,
174
+ )
175
+ ops.nvfp4_gemm_bias_gelu_bf16(
176
+ a_packed, b_packed, sfa, sfb, bias, out, float(alpha)
177
+ )
178
+ return out
179
+
180
+
181
+ def nvfp4_gemm_bias_gelu_nvfp4(
182
+ a_packed: torch.Tensor,
183
+ b_packed: torch.Tensor,
184
+ sfa: torch.Tensor,
185
+ sfb: torch.Tensor,
186
+ bias: torch.Tensor,
187
+ alpha: float = 1.0,
188
+ out_packed: torch.Tensor | None = None,
189
+ out_sfa: torch.Tensor | None = None,
190
+ ) -> tuple[torch.Tensor, torch.Tensor]:
191
+ m, n = a_packed.shape[0], b_packed.shape[0]
192
+ if out_packed is None:
193
+ out_packed = torch.empty((m, n // 2), device=a_packed.device, dtype=torch.uint8)
194
+ if out_sfa is None:
195
+ out_sfa = torch.empty((sfa_size_bytes(m, n),), device=a_packed.device, dtype=torch.uint8)
196
+ ops.nvfp4_gemm_bias_gelu_nvfp4(
197
+ a_packed, b_packed, sfa, sfb, bias, out_packed, out_sfa, float(alpha)
198
+ )
199
+ return out_packed, out_sfa
200
+
201
+
202
+ def nvfp4_gemm_streamk_bf16(
203
+ a_packed: torch.Tensor,
204
+ b_packed: torch.Tensor,
205
+ sfa: torch.Tensor,
206
+ sfb: torch.Tensor,
207
+ alpha: float = 1.0,
208
+ out: torch.Tensor | None = None,
209
+ ) -> torch.Tensor:
210
+ if out is None:
211
+ out = torch.empty(
212
+ (a_packed.shape[0], b_packed.shape[0]),
213
+ device=a_packed.device,
214
+ dtype=torch.bfloat16,
215
+ )
216
+ ops.nvfp4_gemm_streamk_bf16(
217
+ a_packed, b_packed, sfa, sfb, out, float(alpha)
218
+ )
219
+ return out
220
+
221
+
222
+ def nvfp4_gemm_streamk_bias_bf16(
223
+ a_packed: torch.Tensor,
224
+ b_packed: torch.Tensor,
225
+ sfa: torch.Tensor,
226
+ sfb: torch.Tensor,
227
+ bias: torch.Tensor,
228
+ alpha: float = 1.0,
229
+ out: torch.Tensor | None = None,
230
+ ) -> torch.Tensor:
231
+ if out is None:
232
+ out = torch.empty(
233
+ (a_packed.shape[0], b_packed.shape[0]),
234
+ device=a_packed.device,
235
+ dtype=torch.bfloat16,
236
+ )
237
+ ops.nvfp4_gemm_streamk_bias_bf16(
238
+ a_packed, b_packed, sfa, sfb, bias, out, float(alpha)
239
+ )
240
+ return out
241
+
242
+
243
+ __all__ = [
244
+ "dequantize_fp4_sfa_fp16",
245
+ "fp4_w4a16_linear_bf16",
246
+ "nvfp4_gemm_bf16",
247
+ "nvfp4_gemm_bias_gelu_bf16",
248
+ "nvfp4_gemm_bias_gelu_nvfp4",
249
+ "nvfp4_gemm_residual_bf16",
250
+ "nvfp4_gemm_streamk_bf16",
251
+ "nvfp4_gemm_streamk_bias_bf16",
252
+ "quantize_fp4_sfa_fp16",
253
+ "sfa_size_bytes",
254
+ ]
build/torch211-cxx11-cu130-x86_64-linux/{_fp4_gemm_cuda_7e2e5b9.abi3.so → _fp4_gemm_cuda_7781728.abi3.so} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:e211cafb6cf95d3ba32015492d7de6bdb29cb6df0cff26400146ed1099ce1cb3
3
- size 714176
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4c48b26279edf27c786fa4acba75e8b66e410e2f0fbb6fa1c318bfa84e23c392
3
+ size 1721016
build/torch211-cxx11-cu130-x86_64-linux/_ops.py CHANGED
@@ -1,9 +1,9 @@
1
  import torch
2
- from . import _fp4_gemm_cuda_7e2e5b9
3
- ops = torch.ops._fp4_gemm_cuda_7e2e5b9
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
- return f"_fp4_gemm_cuda_7e2e5b9::{op_name}"
 
1
  import torch
2
+ from . import _fp4_gemm_cuda_7781728
3
+ ops = torch.ops._fp4_gemm_cuda_7781728
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
+ return f"_fp4_gemm_cuda_7781728::{op_name}"
build/torch211-cxx11-cu130-x86_64-linux/metadata.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "name": "fp4-gemm",
3
- "id": "_fp4_gemm_cuda_7e2e5b9",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
@@ -13,10 +13,21 @@
13
  "digest": {
14
  "algorithm": "sha256",
15
  "files": {
16
- "__init__.py": "WSLdLQD92ulRtOhSLoAhWgFYN6oucbbkTg19GAaltBs=",
17
- "_fp4_gemm_cuda_7e2e5b9.abi3.so": "4hHK+2z5XTujIBVJLX3mvbKctt8M/yZAAUbtEJnOHLM=",
18
- "_ops.py": "UnZlP4anh/kfneg4T/V+ueYOufY4kzFv6zxKMKlaRuA=",
19
  "fp4_gemm/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY="
20
  }
 
 
 
 
 
 
 
 
 
 
 
21
  }
22
  }
 
1
  {
2
  "name": "fp4-gemm",
3
+ "id": "_fp4_gemm_cuda_7781728",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
 
13
  "digest": {
14
  "algorithm": "sha256",
15
  "files": {
16
+ "__init__.py": "FD6tCd6u2NRYfLKq1Uz7OYi+tZV5o9GDAb+KN3GX2oU=",
17
+ "_fp4_gemm_cuda_7781728.abi3.so": "TEiyYnnt8nx4b6SsunXotm5BDi8Pu2+hwxi/qE4jw5I=",
18
+ "_ops.py": "4wRBLd5HIJqgJskLFCRBmKJpvQfYeE9AmKTqIPQtPnw=",
19
  "fp4_gemm/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY="
20
  }
21
+ },
22
+ "provenance": {
23
+ "kernel-builder": {
24
+ "version": "0.17.0-dev0",
25
+ "sha": "19aaa6421e674e9fecc352bbae6eab81d19a6bf4",
26
+ "dirty": false
27
+ },
28
+ "kernel": {
29
+ "sha": "77817286c522d8f7abf8d2cd873e1f84a79357b9",
30
+ "dirty": false
31
+ }
32
  }
33
  }
build/torch212-cxx11-cu130-x86_64-linux/__init__.py CHANGED
@@ -23,7 +23,7 @@ def _alloc_fp4(rows: int, dim: int, device: torch.device | str):
23
  )
24
 
25
 
26
- @torch.library.register_fake(add_op_namespace_prefix("fp4_w4a16_linear_bf16"))
27
  def _linear_fake(
28
  a_packed: torch.Tensor,
29
  b_packed: torch.Tensor,
@@ -31,7 +31,29 @@ def _linear_fake(
31
  sfb: torch.Tensor,
32
  out: torch.Tensor,
33
  alpha: float = 1.0,
34
- variant: int = 0,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  ) -> None:
36
  return None
37
 
@@ -41,11 +63,43 @@ def _quant_fake(x: torch.Tensor, packed: torch.Tensor, sfa: torch.Tensor, is_sfb
41
  return None
42
 
43
 
 
 
 
 
 
44
  @torch.library.register_fake(add_op_namespace_prefix("dequantize_fp4_sfa_fp16"))
45
  def _dequant_fake(packed: torch.Tensor, sfa: torch.Tensor, out: torch.Tensor, is_sfb: bool = False) -> None:
46
  return None
47
 
48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  def quantize_fp4_sfa_fp16(
50
  x: torch.Tensor,
51
  packed: torch.Tensor | None = None,
@@ -58,6 +112,19 @@ def quantize_fp4_sfa_fp16(
58
  return packed, sfa
59
 
60
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  def dequantize_fp4_sfa_fp16(
62
  packed: torch.Tensor,
63
  sfa: torch.Tensor,
@@ -70,17 +137,171 @@ def dequantize_fp4_sfa_fp16(
70
  return out
71
 
72
 
73
- def fp4_w4a16_linear_bf16(
74
  a_packed: torch.Tensor,
75
  b_packed: torch.Tensor,
76
  sfa: torch.Tensor,
77
  sfb: torch.Tensor,
78
  alpha: float = 1.0,
79
  out: torch.Tensor | None = None,
80
- variant: int = 0,
81
  ) -> torch.Tensor:
82
  if out is None:
83
  out = torch.empty((a_packed.shape[0], b_packed.shape[0]), device=a_packed.device, dtype=torch.bfloat16)
84
- ops.fp4_w4a16_linear_bf16(a_packed, b_packed, sfa, sfb, out, float(alpha), int(variant))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  return out
86
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  )
24
 
25
 
26
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_bf16"))
27
  def _linear_fake(
28
  a_packed: torch.Tensor,
29
  b_packed: torch.Tensor,
 
31
  sfb: torch.Tensor,
32
  out: torch.Tensor,
33
  alpha: float = 1.0,
34
+ variant: int = -1,
35
+ ) -> None:
36
+ return None
37
+
38
+
39
+ @torch.library.register_fake(add_op_namespace_prefix("fp4_w4a4_gemv_warpsplit_bf16"))
40
+ def _gemv_warpsplit_fake(a_packed, b_packed, sfa, sfb, out, alpha: float = 1.0, warps: int = 4, stages: int = 4) -> None:
41
+ if a_packed.shape[0] != 1:
42
+ raise RuntimeError("warp-split GEMV serves M=1 only")
43
+ if out.shape != (1, b_packed.shape[0]):
44
+ raise RuntimeError("out must have shape (1, N)")
45
+ return None
46
+
47
+
48
+ @torch.library.register_fake(add_op_namespace_prefix("fp4_w4a16_linear_bf16"))
49
+ def _legacy_linear_fake(
50
+ a_packed: torch.Tensor,
51
+ b_packed: torch.Tensor,
52
+ sfa: torch.Tensor,
53
+ sfb: torch.Tensor,
54
+ out: torch.Tensor,
55
+ alpha: float = 1.0,
56
+ variant: int = -1,
57
  ) -> None:
58
  return None
59
 
 
63
  return None
64
 
65
 
66
+ @torch.library.register_fake(add_op_namespace_prefix("quantize_fp4_sfa_bf16"))
67
+ def _quant_bf16_fake(x: torch.Tensor, packed: torch.Tensor, sfa: torch.Tensor, is_sfb: bool = False) -> None:
68
+ return None
69
+
70
+
71
  @torch.library.register_fake(add_op_namespace_prefix("dequantize_fp4_sfa_fp16"))
72
  def _dequant_fake(packed: torch.Tensor, sfa: torch.Tensor, out: torch.Tensor, is_sfb: bool = False) -> None:
73
  return None
74
 
75
 
76
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_residual_bf16"))
77
+ def _residual_fake(a, b, sfa, sfb, residual, out, alpha: float = 1.0) -> None:
78
+ return None
79
+
80
+
81
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_bias_gelu_bf16"))
82
+ def _bias_gelu_fake(a, b, sfa, sfb, bias, out, alpha: float = 1.0) -> None:
83
+ return None
84
+
85
+
86
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_bias_gelu_nvfp4"))
87
+ def _bias_gelu_nvfp4_fake(
88
+ a, b, sfa, sfb, bias, out_packed, out_sfa, alpha: float = 1.0
89
+ ) -> None:
90
+ return None
91
+
92
+
93
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_streamk_bf16"))
94
+ def _streamk_fake(a, b, sfa, sfb, out, alpha: float = 1.0) -> None:
95
+ return None
96
+
97
+
98
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_streamk_bias_bf16"))
99
+ def _streamk_bias_fake(a, b, sfa, sfb, bias, out, alpha: float = 1.0) -> None:
100
+ return None
101
+
102
+
103
  def quantize_fp4_sfa_fp16(
104
  x: torch.Tensor,
105
  packed: torch.Tensor | None = None,
 
112
  return packed, sfa
113
 
114
 
115
+ def quantize_fp4_sfa_bf16(
116
+ x: torch.Tensor,
117
+ packed: torch.Tensor | None = None,
118
+ sfa: torch.Tensor | None = None,
119
+ is_sfb: bool = False,
120
+ ):
121
+ """Quantize BF16 directly to packed E2M1 and CUTLASS SFA/SFB."""
122
+ if packed is None or sfa is None:
123
+ packed, sfa = _alloc_fp4(x.shape[0], x.shape[1], x.device)
124
+ ops.quantize_fp4_sfa_bf16(x, packed, sfa, bool(is_sfb))
125
+ return packed, sfa
126
+
127
+
128
  def dequantize_fp4_sfa_fp16(
129
  packed: torch.Tensor,
130
  sfa: torch.Tensor,
 
137
  return out
138
 
139
 
140
+ def nvfp4_gemm_bf16(
141
  a_packed: torch.Tensor,
142
  b_packed: torch.Tensor,
143
  sfa: torch.Tensor,
144
  sfb: torch.Tensor,
145
  alpha: float = 1.0,
146
  out: torch.Tensor | None = None,
147
+ variant: int = -1,
148
  ) -> torch.Tensor:
149
  if out is None:
150
  out = torch.empty((a_packed.shape[0], b_packed.shape[0]), device=a_packed.device, dtype=torch.bfloat16)
151
+ ops.nvfp4_gemm_bf16(a_packed, b_packed, sfa, sfb, out, float(alpha), int(variant))
152
+ return out
153
+
154
+
155
+ def fp4_w4a4_gemv_warpsplit_bf16(
156
+ a_packed: torch.Tensor,
157
+ b_packed: torch.Tensor,
158
+ sfa: torch.Tensor,
159
+ sfb: torch.Tensor,
160
+ *,
161
+ alpha: float = 1.0,
162
+ warps: int = 4,
163
+ stages: int = 4,
164
+ out: Optional[torch.Tensor] = None,
165
+ ) -> torch.Tensor:
166
+ """Warp-split-K NVFP4 W4A4 GEMV for the M=1 decode row (SM120).
167
+
168
+ Splits K across warps inside one block with a shared-memory reduce -
169
+ no cross-block intermediate, so it stays safe under CUDA-graph
170
+ replay - and fills the SMs the tiled GEMM underfills at long-K
171
+ small-M decode shapes. Same packed/scale layouts as the linear
172
+ entry points."""
173
+ if out is None:
174
+ out = torch.empty((1, b_packed.shape[0]), device=a_packed.device, dtype=torch.bfloat16)
175
+ ops.fp4_w4a4_gemv_warpsplit_bf16(a_packed, b_packed, sfa, sfb, out, float(alpha), int(warps), int(stages))
176
+ return out
177
+
178
+
179
+ def fp4_w4a16_linear_bf16(
180
+ a_packed: torch.Tensor,
181
+ b_packed: torch.Tensor,
182
+ sfa: torch.Tensor,
183
+ sfb: torch.Tensor,
184
+ alpha: float = 1.0,
185
+ out: torch.Tensor | None = None,
186
+ variant: int = -1,
187
+ ) -> torch.Tensor:
188
+ """Compatibility alias for :func:`nvfp4_gemm_bf16`."""
189
+ return nvfp4_gemm_bf16(
190
+ a_packed, b_packed, sfa, sfb, alpha=alpha, out=out, variant=variant
191
+ )
192
+
193
+
194
+ def nvfp4_gemm_residual_bf16(
195
+ a_packed: torch.Tensor,
196
+ b_packed: torch.Tensor,
197
+ sfa: torch.Tensor,
198
+ sfb: torch.Tensor,
199
+ residual: torch.Tensor,
200
+ alpha: float = 1.0,
201
+ out: torch.Tensor | None = None,
202
+ ) -> torch.Tensor:
203
+ if out is None:
204
+ out = torch.empty_like(residual)
205
+ ops.nvfp4_gemm_residual_bf16(
206
+ a_packed, b_packed, sfa, sfb, residual, out, float(alpha)
207
+ )
208
+ return out
209
+
210
+
211
+ def nvfp4_gemm_bias_gelu_bf16(
212
+ a_packed: torch.Tensor,
213
+ b_packed: torch.Tensor,
214
+ sfa: torch.Tensor,
215
+ sfb: torch.Tensor,
216
+ bias: torch.Tensor,
217
+ alpha: float = 1.0,
218
+ out: torch.Tensor | None = None,
219
+ ) -> torch.Tensor:
220
+ if out is None:
221
+ out = torch.empty(
222
+ (a_packed.shape[0], b_packed.shape[0]),
223
+ device=a_packed.device,
224
+ dtype=torch.bfloat16,
225
+ )
226
+ ops.nvfp4_gemm_bias_gelu_bf16(
227
+ a_packed, b_packed, sfa, sfb, bias, out, float(alpha)
228
+ )
229
+ return out
230
+
231
+
232
+ def nvfp4_gemm_bias_gelu_nvfp4(
233
+ a_packed: torch.Tensor,
234
+ b_packed: torch.Tensor,
235
+ sfa: torch.Tensor,
236
+ sfb: torch.Tensor,
237
+ bias: torch.Tensor,
238
+ alpha: float = 1.0,
239
+ out_packed: torch.Tensor | None = None,
240
+ out_sfa: torch.Tensor | None = None,
241
+ ) -> tuple[torch.Tensor, torch.Tensor]:
242
+ m, n = a_packed.shape[0], b_packed.shape[0]
243
+ if out_packed is None:
244
+ out_packed = torch.empty((m, n // 2), device=a_packed.device, dtype=torch.uint8)
245
+ if out_sfa is None:
246
+ out_sfa = torch.empty((sfa_size_bytes(m, n),), device=a_packed.device, dtype=torch.uint8)
247
+ ops.nvfp4_gemm_bias_gelu_nvfp4(
248
+ a_packed, b_packed, sfa, sfb, bias, out_packed, out_sfa, float(alpha)
249
+ )
250
+ return out_packed, out_sfa
251
+
252
+
253
+ def nvfp4_gemm_streamk_bf16(
254
+ a_packed: torch.Tensor,
255
+ b_packed: torch.Tensor,
256
+ sfa: torch.Tensor,
257
+ sfb: torch.Tensor,
258
+ alpha: float = 1.0,
259
+ out: torch.Tensor | None = None,
260
+ ) -> torch.Tensor:
261
+ if out is None:
262
+ out = torch.empty(
263
+ (a_packed.shape[0], b_packed.shape[0]),
264
+ device=a_packed.device,
265
+ dtype=torch.bfloat16,
266
+ )
267
+ ops.nvfp4_gemm_streamk_bf16(
268
+ a_packed, b_packed, sfa, sfb, out, float(alpha)
269
+ )
270
  return out
271
 
272
+
273
+ def nvfp4_gemm_streamk_bias_bf16(
274
+ a_packed: torch.Tensor,
275
+ b_packed: torch.Tensor,
276
+ sfa: torch.Tensor,
277
+ sfb: torch.Tensor,
278
+ bias: torch.Tensor,
279
+ alpha: float = 1.0,
280
+ out: torch.Tensor | None = None,
281
+ ) -> torch.Tensor:
282
+ if out is None:
283
+ out = torch.empty(
284
+ (a_packed.shape[0], b_packed.shape[0]),
285
+ device=a_packed.device,
286
+ dtype=torch.bfloat16,
287
+ )
288
+ ops.nvfp4_gemm_streamk_bias_bf16(
289
+ a_packed, b_packed, sfa, sfb, bias, out, float(alpha)
290
+ )
291
+ return out
292
+
293
+
294
+ __all__ = [
295
+ "dequantize_fp4_sfa_fp16",
296
+ "fp4_w4a16_linear_bf16",
297
+ "fp4_w4a4_gemv_warpsplit_bf16",
298
+ "nvfp4_gemm_bf16",
299
+ "nvfp4_gemm_bias_gelu_bf16",
300
+ "nvfp4_gemm_bias_gelu_nvfp4",
301
+ "nvfp4_gemm_residual_bf16",
302
+ "nvfp4_gemm_streamk_bf16",
303
+ "nvfp4_gemm_streamk_bias_bf16",
304
+ "quantize_fp4_sfa_fp16",
305
+ "quantize_fp4_sfa_bf16",
306
+ "sfa_size_bytes",
307
+ ]
build/torch212-cxx11-cu130-x86_64-linux/{_fp4_gemm_cuda_7e2e5b9.abi3.so → _fp4_gemm_cuda_b46a817.abi3.so} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:63e8e675f69f6cdb3cf1c0a78fe0032f72638db29e8e4844501a2204cca77e08
3
- size 724584
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1234af9f97c77fdec732392890c5b8fa889a416b3034c8c7491edfbecb4cd4d8
3
+ size 2428552
build/torch212-cxx11-cu130-x86_64-linux/_ops.py CHANGED
@@ -1,9 +1,9 @@
1
  import torch
2
- from . import _fp4_gemm_cuda_7e2e5b9
3
- ops = torch.ops._fp4_gemm_cuda_7e2e5b9
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
- return f"_fp4_gemm_cuda_7e2e5b9::{op_name}"
 
1
  import torch
2
+ from . import _fp4_gemm_cuda_b46a817
3
+ ops = torch.ops._fp4_gemm_cuda_b46a817
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
+ return f"_fp4_gemm_cuda_b46a817::{op_name}"
build/torch212-cxx11-cu130-x86_64-linux/fp4_gemm/__init__.py DELETED
@@ -1,26 +0,0 @@
1
- import ctypes
2
- import importlib.util
3
- import sys
4
- from pathlib import Path
5
- from types import ModuleType
6
-
7
-
8
- def _import_from_path(file_path: Path) -> ModuleType:
9
- # We cannot use the module name as-is, after adding it to `sys.modules`,
10
- # it would also be used for other imports. So, we make a module name that
11
- # depends on the path for it to be unique using the hex-encoded hash of
12
- # the path.
13
- path_hash = "{:x}".format(ctypes.c_size_t(hash(file_path.absolute())).value)
14
- module_name = path_hash
15
- spec = importlib.util.spec_from_file_location(module_name, file_path)
16
- if spec is None:
17
- raise ImportError(f"Cannot load spec for {module_name} from {file_path}")
18
- module = importlib.util.module_from_spec(spec)
19
- if module is None:
20
- raise ImportError(f"Cannot load module {module_name} from spec")
21
- sys.modules[module_name] = module
22
- spec.loader.exec_module(module) # type: ignore
23
- return module
24
-
25
-
26
- globals().update(vars(_import_from_path(Path(__file__).parent.parent / "__init__.py")))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch212-cxx11-cu130-x86_64-linux/metadata.json CHANGED
@@ -1,22 +1,33 @@
1
  {
2
  "name": "fp4-gemm",
3
- "id": "_fp4_gemm_cuda_7e2e5b9",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
7
  "backend": {
8
  "type": "cuda",
9
  "archs": [
 
10
  "12.0a"
11
  ]
12
  },
13
  "digest": {
14
  "algorithm": "sha256",
15
  "files": {
16
- "__init__.py": "WSLdLQD92ulRtOhSLoAhWgFYN6oucbbkTg19GAaltBs=",
17
- "_fp4_gemm_cuda_7e2e5b9.abi3.so": "Y+jmdfafbNs88cCnj+ADL3JjjbKejkhEUBoiBMynfgg=",
18
- "_ops.py": "UnZlP4anh/kfneg4T/V+ueYOufY4kzFv6zxKMKlaRuA=",
19
- "fp4_gemm/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY="
 
 
 
 
 
 
 
 
 
 
20
  }
21
  }
22
  }
 
1
  {
2
  "name": "fp4-gemm",
3
+ "id": "_fp4_gemm_cuda_b46a817",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
7
  "backend": {
8
  "type": "cuda",
9
  "archs": [
10
+ "11.0a",
11
  "12.0a"
12
  ]
13
  },
14
  "digest": {
15
  "algorithm": "sha256",
16
  "files": {
17
+ "__init__.py": "pJlGLDlOKnju+m59WyZJjpynMTvkPQTF6w+z4YfCwSY=",
18
+ "_fp4_gemm_cuda_b46a817.abi3.so": "EjSvn5fHf97HMjkokMW4+oiaQWswNMjHSR7fvstM1Ng=",
19
+ "_ops.py": "tD2Fh7MGjwwYSATplu1PwYdWuhn0eHO42VKMA5pSjgU="
20
+ }
21
+ },
22
+ "provenance": {
23
+ "kernel-builder": {
24
+ "version": "0.17.0-dev0",
25
+ "sha": "d720fa90fb9cd92d1bc60a9dc5c55bef2aafabb8",
26
+ "dirty": false
27
+ },
28
+ "kernel": {
29
+ "sha": "b46a81771fdabe26f2c2494dc2ecf8492c88c45a",
30
+ "dirty": false
31
  }
32
  }
33
  }
build/torch212-cxx11-cu132-x86_64-linux/__init__.py CHANGED
@@ -23,7 +23,7 @@ def _alloc_fp4(rows: int, dim: int, device: torch.device | str):
23
  )
24
 
25
 
26
- @torch.library.register_fake(add_op_namespace_prefix("fp4_w4a16_linear_bf16"))
27
  def _linear_fake(
28
  a_packed: torch.Tensor,
29
  b_packed: torch.Tensor,
@@ -31,7 +31,29 @@ def _linear_fake(
31
  sfb: torch.Tensor,
32
  out: torch.Tensor,
33
  alpha: float = 1.0,
34
- variant: int = 0,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  ) -> None:
36
  return None
37
 
@@ -41,11 +63,43 @@ def _quant_fake(x: torch.Tensor, packed: torch.Tensor, sfa: torch.Tensor, is_sfb
41
  return None
42
 
43
 
 
 
 
 
 
44
  @torch.library.register_fake(add_op_namespace_prefix("dequantize_fp4_sfa_fp16"))
45
  def _dequant_fake(packed: torch.Tensor, sfa: torch.Tensor, out: torch.Tensor, is_sfb: bool = False) -> None:
46
  return None
47
 
48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  def quantize_fp4_sfa_fp16(
50
  x: torch.Tensor,
51
  packed: torch.Tensor | None = None,
@@ -58,6 +112,19 @@ def quantize_fp4_sfa_fp16(
58
  return packed, sfa
59
 
60
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  def dequantize_fp4_sfa_fp16(
62
  packed: torch.Tensor,
63
  sfa: torch.Tensor,
@@ -70,17 +137,171 @@ def dequantize_fp4_sfa_fp16(
70
  return out
71
 
72
 
73
- def fp4_w4a16_linear_bf16(
74
  a_packed: torch.Tensor,
75
  b_packed: torch.Tensor,
76
  sfa: torch.Tensor,
77
  sfb: torch.Tensor,
78
  alpha: float = 1.0,
79
  out: torch.Tensor | None = None,
80
- variant: int = 0,
81
  ) -> torch.Tensor:
82
  if out is None:
83
  out = torch.empty((a_packed.shape[0], b_packed.shape[0]), device=a_packed.device, dtype=torch.bfloat16)
84
- ops.fp4_w4a16_linear_bf16(a_packed, b_packed, sfa, sfb, out, float(alpha), int(variant))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  return out
86
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  )
24
 
25
 
26
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_bf16"))
27
  def _linear_fake(
28
  a_packed: torch.Tensor,
29
  b_packed: torch.Tensor,
 
31
  sfb: torch.Tensor,
32
  out: torch.Tensor,
33
  alpha: float = 1.0,
34
+ variant: int = -1,
35
+ ) -> None:
36
+ return None
37
+
38
+
39
+ @torch.library.register_fake(add_op_namespace_prefix("fp4_w4a4_gemv_warpsplit_bf16"))
40
+ def _gemv_warpsplit_fake(a_packed, b_packed, sfa, sfb, out, alpha: float = 1.0, warps: int = 4, stages: int = 4) -> None:
41
+ if a_packed.shape[0] != 1:
42
+ raise RuntimeError("warp-split GEMV serves M=1 only")
43
+ if out.shape != (1, b_packed.shape[0]):
44
+ raise RuntimeError("out must have shape (1, N)")
45
+ return None
46
+
47
+
48
+ @torch.library.register_fake(add_op_namespace_prefix("fp4_w4a16_linear_bf16"))
49
+ def _legacy_linear_fake(
50
+ a_packed: torch.Tensor,
51
+ b_packed: torch.Tensor,
52
+ sfa: torch.Tensor,
53
+ sfb: torch.Tensor,
54
+ out: torch.Tensor,
55
+ alpha: float = 1.0,
56
+ variant: int = -1,
57
  ) -> None:
58
  return None
59
 
 
63
  return None
64
 
65
 
66
+ @torch.library.register_fake(add_op_namespace_prefix("quantize_fp4_sfa_bf16"))
67
+ def _quant_bf16_fake(x: torch.Tensor, packed: torch.Tensor, sfa: torch.Tensor, is_sfb: bool = False) -> None:
68
+ return None
69
+
70
+
71
  @torch.library.register_fake(add_op_namespace_prefix("dequantize_fp4_sfa_fp16"))
72
  def _dequant_fake(packed: torch.Tensor, sfa: torch.Tensor, out: torch.Tensor, is_sfb: bool = False) -> None:
73
  return None
74
 
75
 
76
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_residual_bf16"))
77
+ def _residual_fake(a, b, sfa, sfb, residual, out, alpha: float = 1.0) -> None:
78
+ return None
79
+
80
+
81
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_bias_gelu_bf16"))
82
+ def _bias_gelu_fake(a, b, sfa, sfb, bias, out, alpha: float = 1.0) -> None:
83
+ return None
84
+
85
+
86
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_bias_gelu_nvfp4"))
87
+ def _bias_gelu_nvfp4_fake(
88
+ a, b, sfa, sfb, bias, out_packed, out_sfa, alpha: float = 1.0
89
+ ) -> None:
90
+ return None
91
+
92
+
93
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_streamk_bf16"))
94
+ def _streamk_fake(a, b, sfa, sfb, out, alpha: float = 1.0) -> None:
95
+ return None
96
+
97
+
98
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_streamk_bias_bf16"))
99
+ def _streamk_bias_fake(a, b, sfa, sfb, bias, out, alpha: float = 1.0) -> None:
100
+ return None
101
+
102
+
103
  def quantize_fp4_sfa_fp16(
104
  x: torch.Tensor,
105
  packed: torch.Tensor | None = None,
 
112
  return packed, sfa
113
 
114
 
115
+ def quantize_fp4_sfa_bf16(
116
+ x: torch.Tensor,
117
+ packed: torch.Tensor | None = None,
118
+ sfa: torch.Tensor | None = None,
119
+ is_sfb: bool = False,
120
+ ):
121
+ """Quantize BF16 directly to packed E2M1 and CUTLASS SFA/SFB."""
122
+ if packed is None or sfa is None:
123
+ packed, sfa = _alloc_fp4(x.shape[0], x.shape[1], x.device)
124
+ ops.quantize_fp4_sfa_bf16(x, packed, sfa, bool(is_sfb))
125
+ return packed, sfa
126
+
127
+
128
  def dequantize_fp4_sfa_fp16(
129
  packed: torch.Tensor,
130
  sfa: torch.Tensor,
 
137
  return out
138
 
139
 
140
+ def nvfp4_gemm_bf16(
141
  a_packed: torch.Tensor,
142
  b_packed: torch.Tensor,
143
  sfa: torch.Tensor,
144
  sfb: torch.Tensor,
145
  alpha: float = 1.0,
146
  out: torch.Tensor | None = None,
147
+ variant: int = -1,
148
  ) -> torch.Tensor:
149
  if out is None:
150
  out = torch.empty((a_packed.shape[0], b_packed.shape[0]), device=a_packed.device, dtype=torch.bfloat16)
151
+ ops.nvfp4_gemm_bf16(a_packed, b_packed, sfa, sfb, out, float(alpha), int(variant))
152
+ return out
153
+
154
+
155
+ def fp4_w4a4_gemv_warpsplit_bf16(
156
+ a_packed: torch.Tensor,
157
+ b_packed: torch.Tensor,
158
+ sfa: torch.Tensor,
159
+ sfb: torch.Tensor,
160
+ *,
161
+ alpha: float = 1.0,
162
+ warps: int = 4,
163
+ stages: int = 4,
164
+ out: Optional[torch.Tensor] = None,
165
+ ) -> torch.Tensor:
166
+ """Warp-split-K NVFP4 W4A4 GEMV for the M=1 decode row (SM120).
167
+
168
+ Splits K across warps inside one block with a shared-memory reduce -
169
+ no cross-block intermediate, so it stays safe under CUDA-graph
170
+ replay - and fills the SMs the tiled GEMM underfills at long-K
171
+ small-M decode shapes. Same packed/scale layouts as the linear
172
+ entry points."""
173
+ if out is None:
174
+ out = torch.empty((1, b_packed.shape[0]), device=a_packed.device, dtype=torch.bfloat16)
175
+ ops.fp4_w4a4_gemv_warpsplit_bf16(a_packed, b_packed, sfa, sfb, out, float(alpha), int(warps), int(stages))
176
+ return out
177
+
178
+
179
+ def fp4_w4a16_linear_bf16(
180
+ a_packed: torch.Tensor,
181
+ b_packed: torch.Tensor,
182
+ sfa: torch.Tensor,
183
+ sfb: torch.Tensor,
184
+ alpha: float = 1.0,
185
+ out: torch.Tensor | None = None,
186
+ variant: int = -1,
187
+ ) -> torch.Tensor:
188
+ """Compatibility alias for :func:`nvfp4_gemm_bf16`."""
189
+ return nvfp4_gemm_bf16(
190
+ a_packed, b_packed, sfa, sfb, alpha=alpha, out=out, variant=variant
191
+ )
192
+
193
+
194
+ def nvfp4_gemm_residual_bf16(
195
+ a_packed: torch.Tensor,
196
+ b_packed: torch.Tensor,
197
+ sfa: torch.Tensor,
198
+ sfb: torch.Tensor,
199
+ residual: torch.Tensor,
200
+ alpha: float = 1.0,
201
+ out: torch.Tensor | None = None,
202
+ ) -> torch.Tensor:
203
+ if out is None:
204
+ out = torch.empty_like(residual)
205
+ ops.nvfp4_gemm_residual_bf16(
206
+ a_packed, b_packed, sfa, sfb, residual, out, float(alpha)
207
+ )
208
+ return out
209
+
210
+
211
+ def nvfp4_gemm_bias_gelu_bf16(
212
+ a_packed: torch.Tensor,
213
+ b_packed: torch.Tensor,
214
+ sfa: torch.Tensor,
215
+ sfb: torch.Tensor,
216
+ bias: torch.Tensor,
217
+ alpha: float = 1.0,
218
+ out: torch.Tensor | None = None,
219
+ ) -> torch.Tensor:
220
+ if out is None:
221
+ out = torch.empty(
222
+ (a_packed.shape[0], b_packed.shape[0]),
223
+ device=a_packed.device,
224
+ dtype=torch.bfloat16,
225
+ )
226
+ ops.nvfp4_gemm_bias_gelu_bf16(
227
+ a_packed, b_packed, sfa, sfb, bias, out, float(alpha)
228
+ )
229
+ return out
230
+
231
+
232
+ def nvfp4_gemm_bias_gelu_nvfp4(
233
+ a_packed: torch.Tensor,
234
+ b_packed: torch.Tensor,
235
+ sfa: torch.Tensor,
236
+ sfb: torch.Tensor,
237
+ bias: torch.Tensor,
238
+ alpha: float = 1.0,
239
+ out_packed: torch.Tensor | None = None,
240
+ out_sfa: torch.Tensor | None = None,
241
+ ) -> tuple[torch.Tensor, torch.Tensor]:
242
+ m, n = a_packed.shape[0], b_packed.shape[0]
243
+ if out_packed is None:
244
+ out_packed = torch.empty((m, n // 2), device=a_packed.device, dtype=torch.uint8)
245
+ if out_sfa is None:
246
+ out_sfa = torch.empty((sfa_size_bytes(m, n),), device=a_packed.device, dtype=torch.uint8)
247
+ ops.nvfp4_gemm_bias_gelu_nvfp4(
248
+ a_packed, b_packed, sfa, sfb, bias, out_packed, out_sfa, float(alpha)
249
+ )
250
+ return out_packed, out_sfa
251
+
252
+
253
+ def nvfp4_gemm_streamk_bf16(
254
+ a_packed: torch.Tensor,
255
+ b_packed: torch.Tensor,
256
+ sfa: torch.Tensor,
257
+ sfb: torch.Tensor,
258
+ alpha: float = 1.0,
259
+ out: torch.Tensor | None = None,
260
+ ) -> torch.Tensor:
261
+ if out is None:
262
+ out = torch.empty(
263
+ (a_packed.shape[0], b_packed.shape[0]),
264
+ device=a_packed.device,
265
+ dtype=torch.bfloat16,
266
+ )
267
+ ops.nvfp4_gemm_streamk_bf16(
268
+ a_packed, b_packed, sfa, sfb, out, float(alpha)
269
+ )
270
  return out
271
 
272
+
273
+ def nvfp4_gemm_streamk_bias_bf16(
274
+ a_packed: torch.Tensor,
275
+ b_packed: torch.Tensor,
276
+ sfa: torch.Tensor,
277
+ sfb: torch.Tensor,
278
+ bias: torch.Tensor,
279
+ alpha: float = 1.0,
280
+ out: torch.Tensor | None = None,
281
+ ) -> torch.Tensor:
282
+ if out is None:
283
+ out = torch.empty(
284
+ (a_packed.shape[0], b_packed.shape[0]),
285
+ device=a_packed.device,
286
+ dtype=torch.bfloat16,
287
+ )
288
+ ops.nvfp4_gemm_streamk_bias_bf16(
289
+ a_packed, b_packed, sfa, sfb, bias, out, float(alpha)
290
+ )
291
+ return out
292
+
293
+
294
+ __all__ = [
295
+ "dequantize_fp4_sfa_fp16",
296
+ "fp4_w4a16_linear_bf16",
297
+ "fp4_w4a4_gemv_warpsplit_bf16",
298
+ "nvfp4_gemm_bf16",
299
+ "nvfp4_gemm_bias_gelu_bf16",
300
+ "nvfp4_gemm_bias_gelu_nvfp4",
301
+ "nvfp4_gemm_residual_bf16",
302
+ "nvfp4_gemm_streamk_bf16",
303
+ "nvfp4_gemm_streamk_bias_bf16",
304
+ "quantize_fp4_sfa_fp16",
305
+ "quantize_fp4_sfa_bf16",
306
+ "sfa_size_bytes",
307
+ ]
build/torch212-cxx11-cu132-x86_64-linux/_fp4_gemm_cuda_b46a817.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b8803916d0184845f4c341fce391dcdf57ac715b6f885319e7f281906329dd48
3
+ size 2428504
build/torch212-cxx11-cu132-x86_64-linux/_ops.py CHANGED
@@ -1,9 +1,9 @@
1
  import torch
2
- from . import _fp4_gemm_cuda_7e2e5b9
3
- ops = torch.ops._fp4_gemm_cuda_7e2e5b9
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
- return f"_fp4_gemm_cuda_7e2e5b9::{op_name}"
 
1
  import torch
2
+ from . import _fp4_gemm_cuda_b46a817
3
+ ops = torch.ops._fp4_gemm_cuda_b46a817
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
+ return f"_fp4_gemm_cuda_b46a817::{op_name}"
build/torch212-cxx11-cu132-x86_64-linux/fp4_gemm/__init__.py DELETED
@@ -1,26 +0,0 @@
1
- import ctypes
2
- import importlib.util
3
- import sys
4
- from pathlib import Path
5
- from types import ModuleType
6
-
7
-
8
- def _import_from_path(file_path: Path) -> ModuleType:
9
- # We cannot use the module name as-is, after adding it to `sys.modules`,
10
- # it would also be used for other imports. So, we make a module name that
11
- # depends on the path for it to be unique using the hex-encoded hash of
12
- # the path.
13
- path_hash = "{:x}".format(ctypes.c_size_t(hash(file_path.absolute())).value)
14
- module_name = path_hash
15
- spec = importlib.util.spec_from_file_location(module_name, file_path)
16
- if spec is None:
17
- raise ImportError(f"Cannot load spec for {module_name} from {file_path}")
18
- module = importlib.util.module_from_spec(spec)
19
- if module is None:
20
- raise ImportError(f"Cannot load module {module_name} from spec")
21
- sys.modules[module_name] = module
22
- spec.loader.exec_module(module) # type: ignore
23
- return module
24
-
25
-
26
- globals().update(vars(_import_from_path(Path(__file__).parent.parent / "__init__.py")))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch212-cxx11-cu132-x86_64-linux/metadata.json CHANGED
@@ -1,22 +1,33 @@
1
  {
2
  "name": "fp4-gemm",
3
- "id": "_fp4_gemm_cuda_7e2e5b9",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
7
  "backend": {
8
  "type": "cuda",
9
  "archs": [
 
10
  "12.0a"
11
  ]
12
  },
13
  "digest": {
14
  "algorithm": "sha256",
15
  "files": {
16
- "__init__.py": "WSLdLQD92ulRtOhSLoAhWgFYN6oucbbkTg19GAaltBs=",
17
- "_fp4_gemm_cuda_7e2e5b9.abi3.so": "/V5m9Prt37RfQthGdQjxOy4GX7XTxSqEBNxqdlobiR8=",
18
- "_ops.py": "UnZlP4anh/kfneg4T/V+ueYOufY4kzFv6zxKMKlaRuA=",
19
- "fp4_gemm/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY="
 
 
 
 
 
 
 
 
 
 
20
  }
21
  }
22
  }
 
1
  {
2
  "name": "fp4-gemm",
3
+ "id": "_fp4_gemm_cuda_b46a817",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
7
  "backend": {
8
  "type": "cuda",
9
  "archs": [
10
+ "11.0a",
11
  "12.0a"
12
  ]
13
  },
14
  "digest": {
15
  "algorithm": "sha256",
16
  "files": {
17
+ "__init__.py": "pJlGLDlOKnju+m59WyZJjpynMTvkPQTF6w+z4YfCwSY=",
18
+ "_fp4_gemm_cuda_b46a817.abi3.so": "uIA5FtAYSEX0w0H845Hc31escVtviFMZ5/KBkGMp3Ug=",
19
+ "_ops.py": "tD2Fh7MGjwwYSATplu1PwYdWuhn0eHO42VKMA5pSjgU="
20
+ }
21
+ },
22
+ "provenance": {
23
+ "kernel-builder": {
24
+ "version": "0.17.0-dev0",
25
+ "sha": "d720fa90fb9cd92d1bc60a9dc5c55bef2aafabb8",
26
+ "dirty": false
27
+ },
28
+ "kernel": {
29
+ "sha": "b46a81771fdabe26f2c2494dc2ecf8492c88c45a",
30
+ "dirty": false
31
  }
32
  }
33
  }
build/torch213-cxx11-cu130-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,307 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """FlashRT FP4 GEMM kernels."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import torch
6
+
7
+ from ._ops import add_op_namespace_prefix, ops
8
+
9
+
10
+ def sfa_size_bytes(rows: int, dim: int) -> int:
11
+ if rows <= 0 or dim <= 0 or dim % 16 != 0:
12
+ raise ValueError("rows must be positive and dim must be positive/divisible by 16")
13
+ n_blocks = dim // 16
14
+ n_row_super = (rows + 127) // 128
15
+ n_col_super = (n_blocks + 3) // 4
16
+ return n_row_super * n_col_super * 512
17
+
18
+
19
+ def _alloc_fp4(rows: int, dim: int, device: torch.device | str):
20
+ return (
21
+ torch.empty((rows, dim // 2), device=device, dtype=torch.uint8),
22
+ torch.empty((sfa_size_bytes(rows, dim),), device=device, dtype=torch.uint8),
23
+ )
24
+
25
+
26
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_bf16"))
27
+ def _linear_fake(
28
+ a_packed: torch.Tensor,
29
+ b_packed: torch.Tensor,
30
+ sfa: torch.Tensor,
31
+ sfb: torch.Tensor,
32
+ out: torch.Tensor,
33
+ alpha: float = 1.0,
34
+ variant: int = -1,
35
+ ) -> None:
36
+ return None
37
+
38
+
39
+ @torch.library.register_fake(add_op_namespace_prefix("fp4_w4a4_gemv_warpsplit_bf16"))
40
+ def _gemv_warpsplit_fake(a_packed, b_packed, sfa, sfb, out, alpha: float = 1.0, warps: int = 4, stages: int = 4) -> None:
41
+ if a_packed.shape[0] != 1:
42
+ raise RuntimeError("warp-split GEMV serves M=1 only")
43
+ if out.shape != (1, b_packed.shape[0]):
44
+ raise RuntimeError("out must have shape (1, N)")
45
+ return None
46
+
47
+
48
+ @torch.library.register_fake(add_op_namespace_prefix("fp4_w4a16_linear_bf16"))
49
+ def _legacy_linear_fake(
50
+ a_packed: torch.Tensor,
51
+ b_packed: torch.Tensor,
52
+ sfa: torch.Tensor,
53
+ sfb: torch.Tensor,
54
+ out: torch.Tensor,
55
+ alpha: float = 1.0,
56
+ variant: int = -1,
57
+ ) -> None:
58
+ return None
59
+
60
+
61
+ @torch.library.register_fake(add_op_namespace_prefix("quantize_fp4_sfa_fp16"))
62
+ def _quant_fake(x: torch.Tensor, packed: torch.Tensor, sfa: torch.Tensor, is_sfb: bool = False) -> None:
63
+ return None
64
+
65
+
66
+ @torch.library.register_fake(add_op_namespace_prefix("quantize_fp4_sfa_bf16"))
67
+ def _quant_bf16_fake(x: torch.Tensor, packed: torch.Tensor, sfa: torch.Tensor, is_sfb: bool = False) -> None:
68
+ return None
69
+
70
+
71
+ @torch.library.register_fake(add_op_namespace_prefix("dequantize_fp4_sfa_fp16"))
72
+ def _dequant_fake(packed: torch.Tensor, sfa: torch.Tensor, out: torch.Tensor, is_sfb: bool = False) -> None:
73
+ return None
74
+
75
+
76
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_residual_bf16"))
77
+ def _residual_fake(a, b, sfa, sfb, residual, out, alpha: float = 1.0) -> None:
78
+ return None
79
+
80
+
81
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_bias_gelu_bf16"))
82
+ def _bias_gelu_fake(a, b, sfa, sfb, bias, out, alpha: float = 1.0) -> None:
83
+ return None
84
+
85
+
86
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_bias_gelu_nvfp4"))
87
+ def _bias_gelu_nvfp4_fake(
88
+ a, b, sfa, sfb, bias, out_packed, out_sfa, alpha: float = 1.0
89
+ ) -> None:
90
+ return None
91
+
92
+
93
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_streamk_bf16"))
94
+ def _streamk_fake(a, b, sfa, sfb, out, alpha: float = 1.0) -> None:
95
+ return None
96
+
97
+
98
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_streamk_bias_bf16"))
99
+ def _streamk_bias_fake(a, b, sfa, sfb, bias, out, alpha: float = 1.0) -> None:
100
+ return None
101
+
102
+
103
+ def quantize_fp4_sfa_fp16(
104
+ x: torch.Tensor,
105
+ packed: torch.Tensor | None = None,
106
+ sfa: torch.Tensor | None = None,
107
+ is_sfb: bool = False,
108
+ ):
109
+ if packed is None or sfa is None:
110
+ packed, sfa = _alloc_fp4(x.shape[0], x.shape[1], x.device)
111
+ ops.quantize_fp4_sfa_fp16(x, packed, sfa, bool(is_sfb))
112
+ return packed, sfa
113
+
114
+
115
+ def quantize_fp4_sfa_bf16(
116
+ x: torch.Tensor,
117
+ packed: torch.Tensor | None = None,
118
+ sfa: torch.Tensor | None = None,
119
+ is_sfb: bool = False,
120
+ ):
121
+ """Quantize BF16 directly to packed E2M1 and CUTLASS SFA/SFB."""
122
+ if packed is None or sfa is None:
123
+ packed, sfa = _alloc_fp4(x.shape[0], x.shape[1], x.device)
124
+ ops.quantize_fp4_sfa_bf16(x, packed, sfa, bool(is_sfb))
125
+ return packed, sfa
126
+
127
+
128
+ def dequantize_fp4_sfa_fp16(
129
+ packed: torch.Tensor,
130
+ sfa: torch.Tensor,
131
+ out: torch.Tensor | None = None,
132
+ is_sfb: bool = False,
133
+ ) -> torch.Tensor:
134
+ if out is None:
135
+ out = torch.empty((packed.shape[0], packed.shape[1] * 2), device=packed.device, dtype=torch.float16)
136
+ ops.dequantize_fp4_sfa_fp16(packed, sfa, out, bool(is_sfb))
137
+ return out
138
+
139
+
140
+ def nvfp4_gemm_bf16(
141
+ a_packed: torch.Tensor,
142
+ b_packed: torch.Tensor,
143
+ sfa: torch.Tensor,
144
+ sfb: torch.Tensor,
145
+ alpha: float = 1.0,
146
+ out: torch.Tensor | None = None,
147
+ variant: int = -1,
148
+ ) -> torch.Tensor:
149
+ if out is None:
150
+ out = torch.empty((a_packed.shape[0], b_packed.shape[0]), device=a_packed.device, dtype=torch.bfloat16)
151
+ ops.nvfp4_gemm_bf16(a_packed, b_packed, sfa, sfb, out, float(alpha), int(variant))
152
+ return out
153
+
154
+
155
+ def fp4_w4a4_gemv_warpsplit_bf16(
156
+ a_packed: torch.Tensor,
157
+ b_packed: torch.Tensor,
158
+ sfa: torch.Tensor,
159
+ sfb: torch.Tensor,
160
+ *,
161
+ alpha: float = 1.0,
162
+ warps: int = 4,
163
+ stages: int = 4,
164
+ out: Optional[torch.Tensor] = None,
165
+ ) -> torch.Tensor:
166
+ """Warp-split-K NVFP4 W4A4 GEMV for the M=1 decode row (SM120).
167
+
168
+ Splits K across warps inside one block with a shared-memory reduce -
169
+ no cross-block intermediate, so it stays safe under CUDA-graph
170
+ replay - and fills the SMs the tiled GEMM underfills at long-K
171
+ small-M decode shapes. Same packed/scale layouts as the linear
172
+ entry points."""
173
+ if out is None:
174
+ out = torch.empty((1, b_packed.shape[0]), device=a_packed.device, dtype=torch.bfloat16)
175
+ ops.fp4_w4a4_gemv_warpsplit_bf16(a_packed, b_packed, sfa, sfb, out, float(alpha), int(warps), int(stages))
176
+ return out
177
+
178
+
179
+ def fp4_w4a16_linear_bf16(
180
+ a_packed: torch.Tensor,
181
+ b_packed: torch.Tensor,
182
+ sfa: torch.Tensor,
183
+ sfb: torch.Tensor,
184
+ alpha: float = 1.0,
185
+ out: torch.Tensor | None = None,
186
+ variant: int = -1,
187
+ ) -> torch.Tensor:
188
+ """Compatibility alias for :func:`nvfp4_gemm_bf16`."""
189
+ return nvfp4_gemm_bf16(
190
+ a_packed, b_packed, sfa, sfb, alpha=alpha, out=out, variant=variant
191
+ )
192
+
193
+
194
+ def nvfp4_gemm_residual_bf16(
195
+ a_packed: torch.Tensor,
196
+ b_packed: torch.Tensor,
197
+ sfa: torch.Tensor,
198
+ sfb: torch.Tensor,
199
+ residual: torch.Tensor,
200
+ alpha: float = 1.0,
201
+ out: torch.Tensor | None = None,
202
+ ) -> torch.Tensor:
203
+ if out is None:
204
+ out = torch.empty_like(residual)
205
+ ops.nvfp4_gemm_residual_bf16(
206
+ a_packed, b_packed, sfa, sfb, residual, out, float(alpha)
207
+ )
208
+ return out
209
+
210
+
211
+ def nvfp4_gemm_bias_gelu_bf16(
212
+ a_packed: torch.Tensor,
213
+ b_packed: torch.Tensor,
214
+ sfa: torch.Tensor,
215
+ sfb: torch.Tensor,
216
+ bias: torch.Tensor,
217
+ alpha: float = 1.0,
218
+ out: torch.Tensor | None = None,
219
+ ) -> torch.Tensor:
220
+ if out is None:
221
+ out = torch.empty(
222
+ (a_packed.shape[0], b_packed.shape[0]),
223
+ device=a_packed.device,
224
+ dtype=torch.bfloat16,
225
+ )
226
+ ops.nvfp4_gemm_bias_gelu_bf16(
227
+ a_packed, b_packed, sfa, sfb, bias, out, float(alpha)
228
+ )
229
+ return out
230
+
231
+
232
+ def nvfp4_gemm_bias_gelu_nvfp4(
233
+ a_packed: torch.Tensor,
234
+ b_packed: torch.Tensor,
235
+ sfa: torch.Tensor,
236
+ sfb: torch.Tensor,
237
+ bias: torch.Tensor,
238
+ alpha: float = 1.0,
239
+ out_packed: torch.Tensor | None = None,
240
+ out_sfa: torch.Tensor | None = None,
241
+ ) -> tuple[torch.Tensor, torch.Tensor]:
242
+ m, n = a_packed.shape[0], b_packed.shape[0]
243
+ if out_packed is None:
244
+ out_packed = torch.empty((m, n // 2), device=a_packed.device, dtype=torch.uint8)
245
+ if out_sfa is None:
246
+ out_sfa = torch.empty((sfa_size_bytes(m, n),), device=a_packed.device, dtype=torch.uint8)
247
+ ops.nvfp4_gemm_bias_gelu_nvfp4(
248
+ a_packed, b_packed, sfa, sfb, bias, out_packed, out_sfa, float(alpha)
249
+ )
250
+ return out_packed, out_sfa
251
+
252
+
253
+ def nvfp4_gemm_streamk_bf16(
254
+ a_packed: torch.Tensor,
255
+ b_packed: torch.Tensor,
256
+ sfa: torch.Tensor,
257
+ sfb: torch.Tensor,
258
+ alpha: float = 1.0,
259
+ out: torch.Tensor | None = None,
260
+ ) -> torch.Tensor:
261
+ if out is None:
262
+ out = torch.empty(
263
+ (a_packed.shape[0], b_packed.shape[0]),
264
+ device=a_packed.device,
265
+ dtype=torch.bfloat16,
266
+ )
267
+ ops.nvfp4_gemm_streamk_bf16(
268
+ a_packed, b_packed, sfa, sfb, out, float(alpha)
269
+ )
270
+ return out
271
+
272
+
273
+ def nvfp4_gemm_streamk_bias_bf16(
274
+ a_packed: torch.Tensor,
275
+ b_packed: torch.Tensor,
276
+ sfa: torch.Tensor,
277
+ sfb: torch.Tensor,
278
+ bias: torch.Tensor,
279
+ alpha: float = 1.0,
280
+ out: torch.Tensor | None = None,
281
+ ) -> torch.Tensor:
282
+ if out is None:
283
+ out = torch.empty(
284
+ (a_packed.shape[0], b_packed.shape[0]),
285
+ device=a_packed.device,
286
+ dtype=torch.bfloat16,
287
+ )
288
+ ops.nvfp4_gemm_streamk_bias_bf16(
289
+ a_packed, b_packed, sfa, sfb, bias, out, float(alpha)
290
+ )
291
+ return out
292
+
293
+
294
+ __all__ = [
295
+ "dequantize_fp4_sfa_fp16",
296
+ "fp4_w4a16_linear_bf16",
297
+ "fp4_w4a4_gemv_warpsplit_bf16",
298
+ "nvfp4_gemm_bf16",
299
+ "nvfp4_gemm_bias_gelu_bf16",
300
+ "nvfp4_gemm_bias_gelu_nvfp4",
301
+ "nvfp4_gemm_residual_bf16",
302
+ "nvfp4_gemm_streamk_bf16",
303
+ "nvfp4_gemm_streamk_bias_bf16",
304
+ "quantize_fp4_sfa_fp16",
305
+ "quantize_fp4_sfa_bf16",
306
+ "sfa_size_bytes",
307
+ ]
build/torch213-cxx11-cu130-x86_64-linux/_fp4_gemm_cuda_b46a817.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5b9f1a611ead04f85b31c62ed460b0291ce948e028cd5501d26092259b688d9e
3
+ size 2428392
build/torch213-cxx11-cu130-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _fp4_gemm_cuda_b46a817
3
+ ops = torch.ops._fp4_gemm_cuda_b46a817
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_fp4_gemm_cuda_b46a817::{op_name}"
build/torch213-cxx11-cu130-x86_64-linux/metadata.json ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "fp4-gemm",
3
+ "id": "_fp4_gemm_cuda_b46a817",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "python-depends": [],
7
+ "backend": {
8
+ "type": "cuda",
9
+ "archs": [
10
+ "11.0a",
11
+ "12.0a"
12
+ ]
13
+ },
14
+ "digest": {
15
+ "algorithm": "sha256",
16
+ "files": {
17
+ "__init__.py": "pJlGLDlOKnju+m59WyZJjpynMTvkPQTF6w+z4YfCwSY=",
18
+ "_fp4_gemm_cuda_b46a817.abi3.so": "W58aYR6tBPhbMcYu1GCwKRzpSOAozVUB0mCSJZtojZ4=",
19
+ "_ops.py": "tD2Fh7MGjwwYSATplu1PwYdWuhn0eHO42VKMA5pSjgU="
20
+ }
21
+ },
22
+ "provenance": {
23
+ "kernel-builder": {
24
+ "version": "0.17.0-dev0",
25
+ "sha": "d720fa90fb9cd92d1bc60a9dc5c55bef2aafabb8",
26
+ "dirty": false
27
+ },
28
+ "kernel": {
29
+ "sha": "b46a81771fdabe26f2c2494dc2ecf8492c88c45a",
30
+ "dirty": false
31
+ }
32
+ }
33
+ }
build/torch213-cxx11-cu132-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,307 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """FlashRT FP4 GEMM kernels."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import torch
6
+
7
+ from ._ops import add_op_namespace_prefix, ops
8
+
9
+
10
+ def sfa_size_bytes(rows: int, dim: int) -> int:
11
+ if rows <= 0 or dim <= 0 or dim % 16 != 0:
12
+ raise ValueError("rows must be positive and dim must be positive/divisible by 16")
13
+ n_blocks = dim // 16
14
+ n_row_super = (rows + 127) // 128
15
+ n_col_super = (n_blocks + 3) // 4
16
+ return n_row_super * n_col_super * 512
17
+
18
+
19
+ def _alloc_fp4(rows: int, dim: int, device: torch.device | str):
20
+ return (
21
+ torch.empty((rows, dim // 2), device=device, dtype=torch.uint8),
22
+ torch.empty((sfa_size_bytes(rows, dim),), device=device, dtype=torch.uint8),
23
+ )
24
+
25
+
26
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_bf16"))
27
+ def _linear_fake(
28
+ a_packed: torch.Tensor,
29
+ b_packed: torch.Tensor,
30
+ sfa: torch.Tensor,
31
+ sfb: torch.Tensor,
32
+ out: torch.Tensor,
33
+ alpha: float = 1.0,
34
+ variant: int = -1,
35
+ ) -> None:
36
+ return None
37
+
38
+
39
+ @torch.library.register_fake(add_op_namespace_prefix("fp4_w4a4_gemv_warpsplit_bf16"))
40
+ def _gemv_warpsplit_fake(a_packed, b_packed, sfa, sfb, out, alpha: float = 1.0, warps: int = 4, stages: int = 4) -> None:
41
+ if a_packed.shape[0] != 1:
42
+ raise RuntimeError("warp-split GEMV serves M=1 only")
43
+ if out.shape != (1, b_packed.shape[0]):
44
+ raise RuntimeError("out must have shape (1, N)")
45
+ return None
46
+
47
+
48
+ @torch.library.register_fake(add_op_namespace_prefix("fp4_w4a16_linear_bf16"))
49
+ def _legacy_linear_fake(
50
+ a_packed: torch.Tensor,
51
+ b_packed: torch.Tensor,
52
+ sfa: torch.Tensor,
53
+ sfb: torch.Tensor,
54
+ out: torch.Tensor,
55
+ alpha: float = 1.0,
56
+ variant: int = -1,
57
+ ) -> None:
58
+ return None
59
+
60
+
61
+ @torch.library.register_fake(add_op_namespace_prefix("quantize_fp4_sfa_fp16"))
62
+ def _quant_fake(x: torch.Tensor, packed: torch.Tensor, sfa: torch.Tensor, is_sfb: bool = False) -> None:
63
+ return None
64
+
65
+
66
+ @torch.library.register_fake(add_op_namespace_prefix("quantize_fp4_sfa_bf16"))
67
+ def _quant_bf16_fake(x: torch.Tensor, packed: torch.Tensor, sfa: torch.Tensor, is_sfb: bool = False) -> None:
68
+ return None
69
+
70
+
71
+ @torch.library.register_fake(add_op_namespace_prefix("dequantize_fp4_sfa_fp16"))
72
+ def _dequant_fake(packed: torch.Tensor, sfa: torch.Tensor, out: torch.Tensor, is_sfb: bool = False) -> None:
73
+ return None
74
+
75
+
76
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_residual_bf16"))
77
+ def _residual_fake(a, b, sfa, sfb, residual, out, alpha: float = 1.0) -> None:
78
+ return None
79
+
80
+
81
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_bias_gelu_bf16"))
82
+ def _bias_gelu_fake(a, b, sfa, sfb, bias, out, alpha: float = 1.0) -> None:
83
+ return None
84
+
85
+
86
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_bias_gelu_nvfp4"))
87
+ def _bias_gelu_nvfp4_fake(
88
+ a, b, sfa, sfb, bias, out_packed, out_sfa, alpha: float = 1.0
89
+ ) -> None:
90
+ return None
91
+
92
+
93
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_streamk_bf16"))
94
+ def _streamk_fake(a, b, sfa, sfb, out, alpha: float = 1.0) -> None:
95
+ return None
96
+
97
+
98
+ @torch.library.register_fake(add_op_namespace_prefix("nvfp4_gemm_streamk_bias_bf16"))
99
+ def _streamk_bias_fake(a, b, sfa, sfb, bias, out, alpha: float = 1.0) -> None:
100
+ return None
101
+
102
+
103
+ def quantize_fp4_sfa_fp16(
104
+ x: torch.Tensor,
105
+ packed: torch.Tensor | None = None,
106
+ sfa: torch.Tensor | None = None,
107
+ is_sfb: bool = False,
108
+ ):
109
+ if packed is None or sfa is None:
110
+ packed, sfa = _alloc_fp4(x.shape[0], x.shape[1], x.device)
111
+ ops.quantize_fp4_sfa_fp16(x, packed, sfa, bool(is_sfb))
112
+ return packed, sfa
113
+
114
+
115
+ def quantize_fp4_sfa_bf16(
116
+ x: torch.Tensor,
117
+ packed: torch.Tensor | None = None,
118
+ sfa: torch.Tensor | None = None,
119
+ is_sfb: bool = False,
120
+ ):
121
+ """Quantize BF16 directly to packed E2M1 and CUTLASS SFA/SFB."""
122
+ if packed is None or sfa is None:
123
+ packed, sfa = _alloc_fp4(x.shape[0], x.shape[1], x.device)
124
+ ops.quantize_fp4_sfa_bf16(x, packed, sfa, bool(is_sfb))
125
+ return packed, sfa
126
+
127
+
128
+ def dequantize_fp4_sfa_fp16(
129
+ packed: torch.Tensor,
130
+ sfa: torch.Tensor,
131
+ out: torch.Tensor | None = None,
132
+ is_sfb: bool = False,
133
+ ) -> torch.Tensor:
134
+ if out is None:
135
+ out = torch.empty((packed.shape[0], packed.shape[1] * 2), device=packed.device, dtype=torch.float16)
136
+ ops.dequantize_fp4_sfa_fp16(packed, sfa, out, bool(is_sfb))
137
+ return out
138
+
139
+
140
+ def nvfp4_gemm_bf16(
141
+ a_packed: torch.Tensor,
142
+ b_packed: torch.Tensor,
143
+ sfa: torch.Tensor,
144
+ sfb: torch.Tensor,
145
+ alpha: float = 1.0,
146
+ out: torch.Tensor | None = None,
147
+ variant: int = -1,
148
+ ) -> torch.Tensor:
149
+ if out is None:
150
+ out = torch.empty((a_packed.shape[0], b_packed.shape[0]), device=a_packed.device, dtype=torch.bfloat16)
151
+ ops.nvfp4_gemm_bf16(a_packed, b_packed, sfa, sfb, out, float(alpha), int(variant))
152
+ return out
153
+
154
+
155
+ def fp4_w4a4_gemv_warpsplit_bf16(
156
+ a_packed: torch.Tensor,
157
+ b_packed: torch.Tensor,
158
+ sfa: torch.Tensor,
159
+ sfb: torch.Tensor,
160
+ *,
161
+ alpha: float = 1.0,
162
+ warps: int = 4,
163
+ stages: int = 4,
164
+ out: Optional[torch.Tensor] = None,
165
+ ) -> torch.Tensor:
166
+ """Warp-split-K NVFP4 W4A4 GEMV for the M=1 decode row (SM120).
167
+
168
+ Splits K across warps inside one block with a shared-memory reduce -
169
+ no cross-block intermediate, so it stays safe under CUDA-graph
170
+ replay - and fills the SMs the tiled GEMM underfills at long-K
171
+ small-M decode shapes. Same packed/scale layouts as the linear
172
+ entry points."""
173
+ if out is None:
174
+ out = torch.empty((1, b_packed.shape[0]), device=a_packed.device, dtype=torch.bfloat16)
175
+ ops.fp4_w4a4_gemv_warpsplit_bf16(a_packed, b_packed, sfa, sfb, out, float(alpha), int(warps), int(stages))
176
+ return out
177
+
178
+
179
+ def fp4_w4a16_linear_bf16(
180
+ a_packed: torch.Tensor,
181
+ b_packed: torch.Tensor,
182
+ sfa: torch.Tensor,
183
+ sfb: torch.Tensor,
184
+ alpha: float = 1.0,
185
+ out: torch.Tensor | None = None,
186
+ variant: int = -1,
187
+ ) -> torch.Tensor:
188
+ """Compatibility alias for :func:`nvfp4_gemm_bf16`."""
189
+ return nvfp4_gemm_bf16(
190
+ a_packed, b_packed, sfa, sfb, alpha=alpha, out=out, variant=variant
191
+ )
192
+
193
+
194
+ def nvfp4_gemm_residual_bf16(
195
+ a_packed: torch.Tensor,
196
+ b_packed: torch.Tensor,
197
+ sfa: torch.Tensor,
198
+ sfb: torch.Tensor,
199
+ residual: torch.Tensor,
200
+ alpha: float = 1.0,
201
+ out: torch.Tensor | None = None,
202
+ ) -> torch.Tensor:
203
+ if out is None:
204
+ out = torch.empty_like(residual)
205
+ ops.nvfp4_gemm_residual_bf16(
206
+ a_packed, b_packed, sfa, sfb, residual, out, float(alpha)
207
+ )
208
+ return out
209
+
210
+
211
+ def nvfp4_gemm_bias_gelu_bf16(
212
+ a_packed: torch.Tensor,
213
+ b_packed: torch.Tensor,
214
+ sfa: torch.Tensor,
215
+ sfb: torch.Tensor,
216
+ bias: torch.Tensor,
217
+ alpha: float = 1.0,
218
+ out: torch.Tensor | None = None,
219
+ ) -> torch.Tensor:
220
+ if out is None:
221
+ out = torch.empty(
222
+ (a_packed.shape[0], b_packed.shape[0]),
223
+ device=a_packed.device,
224
+ dtype=torch.bfloat16,
225
+ )
226
+ ops.nvfp4_gemm_bias_gelu_bf16(
227
+ a_packed, b_packed, sfa, sfb, bias, out, float(alpha)
228
+ )
229
+ return out
230
+
231
+
232
+ def nvfp4_gemm_bias_gelu_nvfp4(
233
+ a_packed: torch.Tensor,
234
+ b_packed: torch.Tensor,
235
+ sfa: torch.Tensor,
236
+ sfb: torch.Tensor,
237
+ bias: torch.Tensor,
238
+ alpha: float = 1.0,
239
+ out_packed: torch.Tensor | None = None,
240
+ out_sfa: torch.Tensor | None = None,
241
+ ) -> tuple[torch.Tensor, torch.Tensor]:
242
+ m, n = a_packed.shape[0], b_packed.shape[0]
243
+ if out_packed is None:
244
+ out_packed = torch.empty((m, n // 2), device=a_packed.device, dtype=torch.uint8)
245
+ if out_sfa is None:
246
+ out_sfa = torch.empty((sfa_size_bytes(m, n),), device=a_packed.device, dtype=torch.uint8)
247
+ ops.nvfp4_gemm_bias_gelu_nvfp4(
248
+ a_packed, b_packed, sfa, sfb, bias, out_packed, out_sfa, float(alpha)
249
+ )
250
+ return out_packed, out_sfa
251
+
252
+
253
+ def nvfp4_gemm_streamk_bf16(
254
+ a_packed: torch.Tensor,
255
+ b_packed: torch.Tensor,
256
+ sfa: torch.Tensor,
257
+ sfb: torch.Tensor,
258
+ alpha: float = 1.0,
259
+ out: torch.Tensor | None = None,
260
+ ) -> torch.Tensor:
261
+ if out is None:
262
+ out = torch.empty(
263
+ (a_packed.shape[0], b_packed.shape[0]),
264
+ device=a_packed.device,
265
+ dtype=torch.bfloat16,
266
+ )
267
+ ops.nvfp4_gemm_streamk_bf16(
268
+ a_packed, b_packed, sfa, sfb, out, float(alpha)
269
+ )
270
+ return out
271
+
272
+
273
+ def nvfp4_gemm_streamk_bias_bf16(
274
+ a_packed: torch.Tensor,
275
+ b_packed: torch.Tensor,
276
+ sfa: torch.Tensor,
277
+ sfb: torch.Tensor,
278
+ bias: torch.Tensor,
279
+ alpha: float = 1.0,
280
+ out: torch.Tensor | None = None,
281
+ ) -> torch.Tensor:
282
+ if out is None:
283
+ out = torch.empty(
284
+ (a_packed.shape[0], b_packed.shape[0]),
285
+ device=a_packed.device,
286
+ dtype=torch.bfloat16,
287
+ )
288
+ ops.nvfp4_gemm_streamk_bias_bf16(
289
+ a_packed, b_packed, sfa, sfb, bias, out, float(alpha)
290
+ )
291
+ return out
292
+
293
+
294
+ __all__ = [
295
+ "dequantize_fp4_sfa_fp16",
296
+ "fp4_w4a16_linear_bf16",
297
+ "fp4_w4a4_gemv_warpsplit_bf16",
298
+ "nvfp4_gemm_bf16",
299
+ "nvfp4_gemm_bias_gelu_bf16",
300
+ "nvfp4_gemm_bias_gelu_nvfp4",
301
+ "nvfp4_gemm_residual_bf16",
302
+ "nvfp4_gemm_streamk_bf16",
303
+ "nvfp4_gemm_streamk_bias_bf16",
304
+ "quantize_fp4_sfa_fp16",
305
+ "quantize_fp4_sfa_bf16",
306
+ "sfa_size_bytes",
307
+ ]
build/torch213-cxx11-cu132-x86_64-linux/_fp4_gemm_cuda_b46a817.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5082b53906993de143af4d334995ab99d936ca06c6b014ce9d56af1ef101b8d4
3
+ size 2428344
build/torch213-cxx11-cu132-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _fp4_gemm_cuda_b46a817
3
+ ops = torch.ops._fp4_gemm_cuda_b46a817
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_fp4_gemm_cuda_b46a817::{op_name}"
build/torch213-cxx11-cu132-x86_64-linux/metadata.json ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "fp4-gemm",
3
+ "id": "_fp4_gemm_cuda_b46a817",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "python-depends": [],
7
+ "backend": {
8
+ "type": "cuda",
9
+ "archs": [
10
+ "11.0a",
11
+ "12.0a"
12
+ ]
13
+ },
14
+ "digest": {
15
+ "algorithm": "sha256",
16
+ "files": {
17
+ "__init__.py": "pJlGLDlOKnju+m59WyZJjpynMTvkPQTF6w+z4YfCwSY=",
18
+ "_fp4_gemm_cuda_b46a817.abi3.so": "UIK1OQaZPeFDr00zSZWrmdk2ygbGsBTOnVavHvEBuNQ=",
19
+ "_ops.py": "tD2Fh7MGjwwYSATplu1PwYdWuhn0eHO42VKMA5pSjgU="
20
+ }
21
+ },
22
+ "provenance": {
23
+ "kernel-builder": {
24
+ "version": "0.17.0-dev0",
25
+ "sha": "d720fa90fb9cd92d1bc60a9dc5c55bef2aafabb8",
26
+ "dirty": false
27
+ },
28
+ "kernel": {
29
+ "sha": "b46a81771fdabe26f2c2494dc2ecf8492c88c45a",
30
+ "dirty": false
31
+ }
32
+ }
33
+ }