nbxtensor 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (291) hide show
  1. nbxtensor/THIRD_PARTY_NOTICES.md +287 -0
  2. nbxtensor/__init__.py +17 -0
  3. nbxtensor/backend/__init__.py +1 -0
  4. nbxtensor/backend/capabilities.py +207 -0
  5. nbxtensor/backend/cpu/__init__.py +1 -0
  6. nbxtensor/backend/cpu/blas.py +102 -0
  7. nbxtensor/backend/cpu/pool.py +204 -0
  8. nbxtensor/backend/cpu_backend.py +162 -0
  9. nbxtensor/backend/device_facts.py +105 -0
  10. nbxtensor/backend/device_files.py +129 -0
  11. nbxtensor/backend/device_names.py +18 -0
  12. nbxtensor/backend/devices/amd/cdna.yml +228 -0
  13. nbxtensor/backend/devices/amd/cdna2.yml +228 -0
  14. nbxtensor/backend/devices/amd/cdna3.yml +227 -0
  15. nbxtensor/backend/devices/apple/apple_m1.yml +266 -0
  16. nbxtensor/backend/devices/apple/apple_m1_max.yml +266 -0
  17. nbxtensor/backend/devices/apple/apple_m1_pro.yml +266 -0
  18. nbxtensor/backend/devices/apple/apple_m1_ultra.yml +266 -0
  19. nbxtensor/backend/devices/apple/apple_m2.yml +266 -0
  20. nbxtensor/backend/devices/apple/apple_m2_max.yml +266 -0
  21. nbxtensor/backend/devices/apple/apple_m2_pro.yml +266 -0
  22. nbxtensor/backend/devices/apple/apple_m2_ultra.yml +266 -0
  23. nbxtensor/backend/devices/apple/apple_m3.yml +266 -0
  24. nbxtensor/backend/devices/apple/apple_m3_max.yml +266 -0
  25. nbxtensor/backend/devices/apple/apple_m3_pro.yml +266 -0
  26. nbxtensor/backend/devices/apple/apple_m3_ultra.yml +266 -0
  27. nbxtensor/backend/devices/apple/apple_m4.yml +266 -0
  28. nbxtensor/backend/devices/apple/apple_m4_max.yml +266 -0
  29. nbxtensor/backend/devices/apple/apple_m4_pro.yml +308 -0
  30. nbxtensor/backend/devices/apple/apple_m5.yml +269 -0
  31. nbxtensor/backend/devices/apple/apple_m5_max.yml +269 -0
  32. nbxtensor/backend/devices/apple/apple_m5_pro.yml +269 -0
  33. nbxtensor/backend/devices/apple/apple_m5_ultra.yml +269 -0
  34. nbxtensor/backend/devices/apple/apple_m6.yml +269 -0
  35. nbxtensor/backend/devices/apple/apple_silicon.yml +263 -0
  36. nbxtensor/backend/devices/nvidia/ampere.yml +214 -0
  37. nbxtensor/backend/devices/nvidia/hopper.yml +213 -0
  38. nbxtensor/backend/devices/nvidia/volta.yml +411 -0
  39. nbxtensor/backend/faults.py +151 -0
  40. nbxtensor/backend/host_memory.py +185 -0
  41. nbxtensor/backend/launcher.py +2350 -0
  42. nbxtensor/backend/launcher_contract.py +429 -0
  43. nbxtensor/backend/metal_backend.py +661 -0
  44. nbxtensor/backend/metal_device.py +1274 -0
  45. nbxtensor/backend/process_memory.py +73 -0
  46. nbxtensor/backend/replay_graph.py +322 -0
  47. nbxtensor/backend/runtime.py +409 -0
  48. nbxtensor/backend/triton_ext_driver.py +735 -0
  49. nbxtensor/dtype/__init__.py +1 -0
  50. nbxtensor/dtype/convert.py +107 -0
  51. nbxtensor/dtype/dtypes.yml +70 -0
  52. nbxtensor/dtype/itemsize.py +166 -0
  53. nbxtensor/dtype/nbx_dtype.py +72 -0
  54. nbxtensor/dtype/operands.py +158 -0
  55. nbxtensor/dtype/outputs.py +64 -0
  56. nbxtensor/dtype/policy.py +155 -0
  57. nbxtensor/dtype/policy.yml +51 -0
  58. nbxtensor/dtype/promotion.py +112 -0
  59. nbxtensor/host.py +55 -0
  60. nbxtensor/io/__init__.py +1 -0
  61. nbxtensor/io/read_rate.py +197 -0
  62. nbxtensor/io/safetensors.py +314 -0
  63. nbxtensor/memory/__init__.py +9 -0
  64. nbxtensor/memory/allocator.py +1988 -0
  65. nbxtensor/memory/arena.py +75 -0
  66. nbxtensor/memory/device_memory.py +150 -0
  67. nbxtensor/memory/device_transfer.py +154 -0
  68. nbxtensor/memory/layout.py +43 -0
  69. nbxtensor/memory/memory_pool.py +191 -0
  70. nbxtensor/memory/metal.py +96 -0
  71. nbxtensor/memory/oom_advice.py +91 -0
  72. nbxtensor/memory/pointer_tables.py +323 -0
  73. nbxtensor/memory/pool.py +507 -0
  74. nbxtensor/memory/shadow.py +43 -0
  75. nbxtensor/memory/slab.py +273 -0
  76. nbxtensor/memory/trace_replay.py +122 -0
  77. nbxtensor/memory/traces/sana-video-2b-720p.16g.2026-11-02.tsv +13610 -0
  78. nbxtensor/memory/vmm.py +118 -0
  79. nbxtensor/ops/__init__.py +1 -0
  80. nbxtensor/ops/_autotune_policy.py +90 -0
  81. nbxtensor/ops/_common.py +32 -0
  82. nbxtensor/ops/_configs.py +1041 -0
  83. nbxtensor/ops/_cost.py +231 -0
  84. nbxtensor/ops/abs.py +17 -0
  85. nbxtensor/ops/adaptive_avg_pool2d.py +161 -0
  86. nbxtensor/ops/add.py +96 -0
  87. nbxtensor/ops/addcdiv.py +29 -0
  88. nbxtensor/ops/addcmul.py +29 -0
  89. nbxtensor/ops/addmv_op.py +64 -0
  90. nbxtensor/ops/addr.py +68 -0
  91. nbxtensor/ops/all_reduce.py +83 -0
  92. nbxtensor/ops/amax.py +40 -0
  93. nbxtensor/ops/any_reduce.py +83 -0
  94. nbxtensor/ops/arange_op.py +27 -0
  95. nbxtensor/ops/argmax.py +107 -0
  96. nbxtensor/ops/argmin.py +93 -0
  97. nbxtensor/ops/atan2.py +71 -0
  98. nbxtensor/ops/attention_wrappers.py +1648 -0
  99. nbxtensor/ops/autotune_bucket.py +137 -0
  100. nbxtensor/ops/autotune_cache.py +430 -0
  101. nbxtensor/ops/autotune_certified.py +1262 -0
  102. nbxtensor/ops/autotune_refusals.py +380 -0
  103. nbxtensor/ops/autotune_settings.py +58 -0
  104. nbxtensor/ops/avg_pool2d.py +73 -0
  105. nbxtensor/ops/baddbmm_op.py +132 -0
  106. nbxtensor/ops/batch_norm.py +163 -0
  107. nbxtensor/ops/binary_strided.py +196 -0
  108. nbxtensor/ops/bitwise_and.py +26 -0
  109. nbxtensor/ops/bitwise_left_shift.py +47 -0
  110. nbxtensor/ops/bitwise_not.py +24 -0
  111. nbxtensor/ops/bitwise_or.py +26 -0
  112. nbxtensor/ops/bitwise_right_shift.py +47 -0
  113. nbxtensor/ops/bucketize.py +37 -0
  114. nbxtensor/ops/cat_op.py +87 -0
  115. nbxtensor/ops/celu.py +20 -0
  116. nbxtensor/ops/clamp.py +24 -0
  117. nbxtensor/ops/clamp_min.py +22 -0
  118. nbxtensor/ops/conv2d.py +265 -0
  119. nbxtensor/ops/conv2d_m8n8k4.py +165 -0
  120. nbxtensor/ops/conv_depthwise2d.py +154 -0
  121. nbxtensor/ops/conv_transpose2d.py +148 -0
  122. nbxtensor/ops/conv_wrappers.py +1482 -0
  123. nbxtensor/ops/copy.py +18 -0
  124. nbxtensor/ops/copy_op.py +39 -0
  125. nbxtensor/ops/cos.py +17 -0
  126. nbxtensor/ops/count_nonzero.py +64 -0
  127. nbxtensor/ops/cross_entropy.py +67 -0
  128. nbxtensor/ops/cummax.py +109 -0
  129. nbxtensor/ops/cummin.py +105 -0
  130. nbxtensor/ops/cumsum.py +244 -0
  131. nbxtensor/ops/decode_attn_vec.py +162 -0
  132. nbxtensor/ops/depthwise_conv2d.py +132 -0
  133. nbxtensor/ops/dequant_gemv.py +190 -0
  134. nbxtensor/ops/dft.py +67 -0
  135. nbxtensor/ops/dispatch.py +1228 -0
  136. nbxtensor/ops/div.py +75 -0
  137. nbxtensor/ops/dot_op.py +67 -0
  138. nbxtensor/ops/dropout.py +23 -0
  139. nbxtensor/ops/dtype_convert.py +42 -0
  140. nbxtensor/ops/elementwise_launch.py +81 -0
  141. nbxtensor/ops/elementwise_wrappers.py +2315 -0
  142. nbxtensor/ops/elu.py +20 -0
  143. nbxtensor/ops/embedding.py +69 -0
  144. nbxtensor/ops/eq.py +32 -0
  145. nbxtensor/ops/erf.py +18 -0
  146. nbxtensor/ops/exp.py +17 -0
  147. nbxtensor/ops/exp2.py +18 -0
  148. nbxtensor/ops/fft_op.py +125 -0
  149. nbxtensor/ops/fill_op.py +20 -0
  150. nbxtensor/ops/flash_attention.py +307 -0
  151. nbxtensor/ops/flash_attention_m8n8k4.py +384 -0
  152. nbxtensor/ops/flash_decode.py +78 -0
  153. nbxtensor/ops/flip_op.py +60 -0
  154. nbxtensor/ops/floor.py +90 -0
  155. nbxtensor/ops/full_op.py +24 -0
  156. nbxtensor/ops/fused_moe.py +417 -0
  157. nbxtensor/ops/fused_moe_m8n8k4.py +99 -0
  158. nbxtensor/ops/fused_upsample_conv.py +413 -0
  159. nbxtensor/ops/gather_op.py +52 -0
  160. nbxtensor/ops/ge.py +32 -0
  161. nbxtensor/ops/gelu.py +31 -0
  162. nbxtensor/ops/gemv_vec.py +80 -0
  163. nbxtensor/ops/glu.py +43 -0
  164. nbxtensor/ops/grid_sampler.py +145 -0
  165. nbxtensor/ops/group_norm_tiled.py +67 -0
  166. nbxtensor/ops/groupnorm.py +123 -0
  167. nbxtensor/ops/gt.py +32 -0
  168. nbxtensor/ops/hardsigmoid.py +18 -0
  169. nbxtensor/ops/hardswish.py +19 -0
  170. nbxtensor/ops/im2col.py +57 -0
  171. nbxtensor/ops/index_add.py +95 -0
  172. nbxtensor/ops/index_put_op.py +92 -0
  173. nbxtensor/ops/index_select.py +121 -0
  174. nbxtensor/ops/index_wrappers.py +770 -0
  175. nbxtensor/ops/isfinite.py +20 -0
  176. nbxtensor/ops/isinf.py +20 -0
  177. nbxtensor/ops/isnan.py +18 -0
  178. nbxtensor/ops/launch_keys.py +1054 -0
  179. nbxtensor/ops/launch_observer.py +54 -0
  180. nbxtensor/ops/layernorm.py +71 -0
  181. nbxtensor/ops/le.py +35 -0
  182. nbxtensor/ops/leaky_relu.py +19 -0
  183. nbxtensor/ops/lerp.py +76 -0
  184. nbxtensor/ops/linalg_wrappers.py +1370 -0
  185. nbxtensor/ops/linspace_op.py +47 -0
  186. nbxtensor/ops/log.py +17 -0
  187. nbxtensor/ops/log_sigmoid.py +23 -0
  188. nbxtensor/ops/logical_and.py +26 -0
  189. nbxtensor/ops/logical_not.py +24 -0
  190. nbxtensor/ops/logical_or.py +26 -0
  191. nbxtensor/ops/logical_xor.py +37 -0
  192. nbxtensor/ops/loss_wrappers.py +282 -0
  193. nbxtensor/ops/lt.py +32 -0
  194. nbxtensor/ops/masked_fill.py +21 -0
  195. nbxtensor/ops/matmul.py +377 -0
  196. nbxtensor/ops/matmul_m8n8k4.py +235 -0
  197. nbxtensor/ops/max_pool2d.py +74 -0
  198. nbxtensor/ops/max_pool3d.py +93 -0
  199. nbxtensor/ops/max_reduce.py +91 -0
  200. nbxtensor/ops/maximum.py +18 -0
  201. nbxtensor/ops/mean.py +40 -0
  202. nbxtensor/ops/min_reduce.py +91 -0
  203. nbxtensor/ops/minimum.py +18 -0
  204. nbxtensor/ops/mish.py +22 -0
  205. nbxtensor/ops/mma_m8n8k4.py +152 -0
  206. nbxtensor/ops/moe_align.py +195 -0
  207. nbxtensor/ops/moe_decode_vec.py +374 -0
  208. nbxtensor/ops/moe_device_residency.py +141 -0
  209. nbxtensor/ops/moe_wrappers.py +345 -0
  210. nbxtensor/ops/mse_loss.py +79 -0
  211. nbxtensor/ops/mul.py +51 -0
  212. nbxtensor/ops/nan_to_num.py +23 -0
  213. nbxtensor/ops/ne.py +32 -0
  214. nbxtensor/ops/neg.py +17 -0
  215. nbxtensor/ops/nllloss.py +124 -0
  216. nbxtensor/ops/nonzero.py +33 -0
  217. nbxtensor/ops/nonzero_op.py +62 -0
  218. nbxtensor/ops/norm_wrappers.py +579 -0
  219. nbxtensor/ops/ones_op.py +20 -0
  220. nbxtensor/ops/oracles/__init__.py +6 -0
  221. nbxtensor/ops/oracles/conv2d_fp64.py +450 -0
  222. nbxtensor/ops/pad_op.py +159 -0
  223. nbxtensor/ops/paged_decode_attn.py +215 -0
  224. nbxtensor/ops/pixel_shuffle.py +144 -0
  225. nbxtensor/ops/pixel_unshuffle.py +72 -0
  226. nbxtensor/ops/pow.py +137 -0
  227. nbxtensor/ops/prod.py +81 -0
  228. nbxtensor/ops/rand_op.py +52 -0
  229. nbxtensor/ops/random_wrappers.py +366 -0
  230. nbxtensor/ops/reciprocal.py +17 -0
  231. nbxtensor/ops/reduction_wrappers.py +845 -0
  232. nbxtensor/ops/relu.py +18 -0
  233. nbxtensor/ops/remainder.py +46 -0
  234. nbxtensor/ops/repeat_interleave.py +48 -0
  235. nbxtensor/ops/repeat_op.py +132 -0
  236. nbxtensor/ops/residual_chain.py +374 -0
  237. nbxtensor/ops/rmsnorm.py +68 -0
  238. nbxtensor/ops/rope.py +142 -0
  239. nbxtensor/ops/rsqrt.py +17 -0
  240. nbxtensor/ops/scaled_softmax.py +96 -0
  241. nbxtensor/ops/scatter_op.py +139 -0
  242. nbxtensor/ops/screen_oracle.py +479 -0
  243. nbxtensor/ops/selu.py +22 -0
  244. nbxtensor/ops/shape_wrappers.py +1032 -0
  245. nbxtensor/ops/sigmoid.py +19 -0
  246. nbxtensor/ops/silu.py +27 -0
  247. nbxtensor/ops/sin.py +17 -0
  248. nbxtensor/ops/softmax.py +169 -0
  249. nbxtensor/ops/softplus.py +27 -0
  250. nbxtensor/ops/sort_op.py +304 -0
  251. nbxtensor/ops/spectral_wrappers.py +481 -0
  252. nbxtensor/ops/sqrt.py +17 -0
  253. nbxtensor/ops/stack_op.py +84 -0
  254. nbxtensor/ops/std.py +113 -0
  255. nbxtensor/ops/strided_copy.py +200 -0
  256. nbxtensor/ops/sub.py +35 -0
  257. nbxtensor/ops/sum.py +40 -0
  258. nbxtensor/ops/tan.py +19 -0
  259. nbxtensor/ops/tanh.py +21 -0
  260. nbxtensor/ops/threshold.py +19 -0
  261. nbxtensor/ops/tiling.yml +91 -0
  262. nbxtensor/ops/tiling_policy.py +43 -0
  263. nbxtensor/ops/tiling_sizes.py +370 -0
  264. nbxtensor/ops/topk.py +267 -0
  265. nbxtensor/ops/trace_op.py +64 -0
  266. nbxtensor/ops/tril.py +64 -0
  267. nbxtensor/ops/triu.py +62 -0
  268. nbxtensor/ops/unfold_op.py +37 -0
  269. nbxtensor/ops/unique_op.py +97 -0
  270. nbxtensor/ops/upsample_bilinear2d.py +106 -0
  271. nbxtensor/ops/upsample_nearest2d.py +52 -0
  272. nbxtensor/ops/upsample_nearest3d.py +61 -0
  273. nbxtensor/ops/var.py +136 -0
  274. nbxtensor/ops/vector_norm.py +216 -0
  275. nbxtensor/ops/weight_norm.py +104 -0
  276. nbxtensor/ops/where.py +39 -0
  277. nbxtensor/ops/wrappers.py +825 -0
  278. nbxtensor/ops/zeros_op.py +20 -0
  279. nbxtensor/quant/__init__.py +1 -0
  280. nbxtensor/quant/quantized_tensor.py +187 -0
  281. nbxtensor/random/__init__.py +1 -0
  282. nbxtensor/random/mt_randn.py +154 -0
  283. nbxtensor/random/rng_pin.py +59 -0
  284. nbxtensor/random/rng_stream.py +118 -0
  285. nbxtensor/random/seeded_draw.py +223 -0
  286. nbxtensor/shape/__init__.py +157 -0
  287. nbxtensor/tensor.py +1867 -0
  288. nbxtensor-0.0.1.dist-info/METADATA +379 -0
  289. nbxtensor-0.0.1.dist-info/RECORD +291 -0
  290. nbxtensor-0.0.1.dist-info/WHEEL +4 -0
  291. nbxtensor-0.0.1.dist-info/licenses/LICENSE +189 -0
nbxtensor/ops/relu.py ADDED
@@ -0,0 +1,18 @@
1
+ """ReLU — pure @triton.jit kernel."""
2
+
3
+ import triton
4
+ import triton.language as tl
5
+
6
+ @triton.jit
7
+ def relu_forward_kernel(
8
+ input_ptr, output_ptr,
9
+ n_elements,
10
+ BLOCK_SIZE: tl.constexpr,
11
+ ):
12
+ pid = tl.program_id(0).to(tl.int64)
13
+ offset = pid.to(tl.int64) * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE) # 64-bit from the program id: the product itself wraps past 2^31 elements (register 58)
14
+ mask = offset < n_elements
15
+
16
+ x = tl.load(input_ptr + offset, mask=mask)
17
+ out = tl.maximum(0, x)
18
+ tl.store(output_ptr + offset, out, mask=mask)
@@ -0,0 +1,46 @@
1
+ """Remainder (modulo) — pure @triton.jit kernel.
2
+
3
+ torch.remainder / Python `%` define the result to follow the sign of the
4
+ DIVISOR: remainder(a, b) = a - floor(a / b) * b, so the result lies in [0, b)
5
+ for b > 0 (e.g. remainder(-0.1, 1) = 0.9). Triton's `%` operator on floats is C
6
+ `fmod` (trunc division), which follows the sign of the DIVIDEND (fmod(-0.1, 1) =
7
+ -0.1). Using `%` silently broke any negative-input modulo — surfaced by the
8
+ Kokoro SineGen phase wrap `(f0*harmonics/sr) % 1`, where the predictor's
9
+ unconstrained (sometimes negative) F0 produced negative phases that never
10
+ wrapped into [0,1), degrading the harmonic source. The floor formula matches
11
+ torch for floats and for integers (the result is integer-valued, cast back
12
+ cleanly); x/y promotes to float so `floor` is well-defined for int inputs too.
13
+ """
14
+
15
+ import triton
16
+ import triton.language as tl
17
+
18
+ @triton.jit
19
+ def remainder_forward_kernel(
20
+ x_ptr, y_ptr, output_ptr,
21
+ n_elements,
22
+ BLOCK_SIZE: tl.constexpr,
23
+ ):
24
+ pid = tl.program_id(0).to(tl.int64)
25
+ offset = pid.to(tl.int64) * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE) # 64-bit from the program id: the product itself wraps past 2^31 elements (register 58)
26
+ mask = offset < n_elements
27
+
28
+ x = tl.load(x_ptr + offset, mask=mask)
29
+ y = tl.load(y_ptr + offset, mask=mask)
30
+ result = x - tl.math.floor((x / y).to(tl.float32)).to(x.dtype) * y
31
+ tl.store(output_ptr + offset, result, mask=mask)
32
+
33
+ @triton.jit
34
+ def remainder_scalar_kernel(
35
+ x_ptr, output_ptr,
36
+ n_elements,
37
+ divisor,
38
+ BLOCK_SIZE: tl.constexpr,
39
+ ):
40
+ pid = tl.program_id(0).to(tl.int64)
41
+ offset = pid.to(tl.int64) * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE) # 64-bit from the program id: the product itself wraps past 2^31 elements (register 58)
42
+ mask = offset < n_elements
43
+
44
+ x = tl.load(x_ptr + offset, mask=mask)
45
+ result = x - tl.math.floor((x / divisor).to(tl.float32)).to(x.dtype) * divisor
46
+ tl.store(output_ptr + offset, result, mask=mask)
@@ -0,0 +1,48 @@
1
+ """repeat_interleave — pure @triton.jit kernel.
2
+
3
+ Handles the tensor-repeats case: given a 1D repeats tensor and its cumsum,
4
+ writes indices so that element i is repeated repeats[i] times.
5
+
6
+ Example: repeats=[2,3,1], cumsum=[2,5,6] -> output=[0,0,1,1,1,2]
7
+
8
+ The self-int case (scalar repeats) is a stride trick handled in the wrapper.
9
+
10
+ Ported from FlagGems repeat_interleave.py. Stripped FlagGems decorators.
11
+ """
12
+
13
+ import triton
14
+ import triton.language as tl
15
+
16
+
17
+ @triton.jit
18
+ def repeat_interleave_tensor_kernel(
19
+ repeats_ptr,
20
+ cumsum_ptr,
21
+ out_ptr,
22
+ size,
23
+ BLOCK_SIZE: tl.constexpr,
24
+ ):
25
+ """Write source indices for tensor-based repeat_interleave.
26
+
27
+ Grid: (size,) — one program per input element.
28
+ Each program writes its index `pid` into repeats[pid] consecutive
29
+ positions starting at cumsum[pid] - repeats[pid].
30
+ """
31
+ pid = tl.program_id(0).to(tl.int64)
32
+ mask = pid < size
33
+ cumsum = tl.load(cumsum_ptr + pid, mask, other=0)
34
+ # The loop bound below must be 32-bit: the Metal induction lowering does
35
+ # not terminate on a 64-bit `scf.for` bound (it refuses rather than hang).
36
+ # `repeats` arrives i64 by torch default. The cast is safe -- a per-element
37
+ # repeat count of 2**31 would need an 8 GB output for ONE element, which
38
+ # the allocator refuses long before this loop -- and numerically inert on
39
+ # CUDA: same iterations, narrower type. Addressing stays wide: `out_offset`
40
+ # promotes back through `cumsum`.
41
+ repeats = tl.load(repeats_ptr + pid, mask, other=0).to(tl.int32)
42
+ out_offset = cumsum - repeats
43
+
44
+ base_ptr = out_ptr + out_offset
45
+ for start_k in range(0, repeats, BLOCK_SIZE):
46
+ offsets_k = start_k + tl.arange(0, BLOCK_SIZE)
47
+ mask_k = offsets_k < repeats
48
+ tl.store(base_ptr + offsets_k, pid, mask=mask_k)
@@ -0,0 +1,132 @@
1
+ """Repeat (tile) — pure @triton.jit kernel.
2
+
3
+ Copies input data into output with tiling via modular indexing.
4
+ For each output element, the source index is computed as:
5
+ src[i] = (output_idx[i] % input_shape[i]) for each dimension.
6
+
7
+ This is a rank-generic kernel that handles up to 6 dimensions.
8
+ Grid: (ceil(num_output_elements / BLOCK_SIZE),)
9
+ """
10
+
11
+ import triton
12
+ import triton.language as tl
13
+
14
+
15
+ @triton.jit
16
+ def repeat_1d_kernel(
17
+ in_ptr, out_ptr,
18
+ in_stride0,
19
+ out_stride0,
20
+ out_shape0,
21
+ in_shape0,
22
+ num_tasks,
23
+ BLOCK_SIZE: tl.constexpr,
24
+ ):
25
+ """Repeat kernel for 1D tensors."""
26
+ pid = tl.program_id(0).to(tl.int64)
27
+ tid = pid.to(tl.int64) * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE) # 64-bit from the program id: the product itself wraps past 2^31 elements (register 58)
28
+ mask = tid < num_tasks
29
+
30
+ i0 = tid
31
+
32
+ # Compute source index via modular indexing
33
+ in_offset = (i0 % in_shape0) * in_stride0
34
+ out_offset = i0 * out_stride0
35
+
36
+ val = tl.load(in_ptr + in_offset, mask=mask)
37
+ tl.store(out_ptr + out_offset, val, mask=mask)
38
+
39
+
40
+ @triton.jit
41
+ def repeat_2d_kernel(
42
+ in_ptr, out_ptr,
43
+ in_stride0, in_stride1,
44
+ out_stride0, out_stride1,
45
+ out_shape0, out_shape1,
46
+ in_shape0, in_shape1,
47
+ num_tasks,
48
+ BLOCK_SIZE: tl.constexpr,
49
+ ):
50
+ """Repeat kernel for 2D tensors."""
51
+ pid = tl.program_id(0).to(tl.int64)
52
+ tid = pid.to(tl.int64) * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE) # 64-bit from the program id: the product itself wraps past 2^31 elements (register 58)
53
+ mask = tid < num_tasks
54
+
55
+ # Decompose flat index into multi-index
56
+ i1 = tid % out_shape1
57
+ i0 = tid // out_shape1
58
+
59
+ # Source via modular indexing
60
+ in_offset = (i0 % in_shape0) * in_stride0 + (i1 % in_shape1) * in_stride1
61
+ out_offset = i0 * out_stride0 + i1 * out_stride1
62
+
63
+ val = tl.load(in_ptr + in_offset, mask=mask)
64
+ tl.store(out_ptr + out_offset, val, mask=mask)
65
+
66
+
67
+ @triton.jit
68
+ def repeat_3d_kernel(
69
+ in_ptr, out_ptr,
70
+ in_stride0, in_stride1, in_stride2,
71
+ out_stride0, out_stride1, out_stride2,
72
+ out_shape0, out_shape1, out_shape2,
73
+ in_shape0, in_shape1, in_shape2,
74
+ num_tasks,
75
+ BLOCK_SIZE: tl.constexpr,
76
+ ):
77
+ """Repeat kernel for 3D tensors."""
78
+ pid = tl.program_id(0).to(tl.int64)
79
+ tid = pid.to(tl.int64) * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE) # 64-bit from the program id: the product itself wraps past 2^31 elements (register 58)
80
+ mask = tid < num_tasks
81
+
82
+ i2 = tid % out_shape2
83
+ tmp = tid // out_shape2
84
+ i1 = tmp % out_shape1
85
+ i0 = tmp // out_shape1
86
+
87
+ in_offset = (
88
+ (i0 % in_shape0) * in_stride0
89
+ + (i1 % in_shape1) * in_stride1
90
+ + (i2 % in_shape2) * in_stride2
91
+ )
92
+ out_offset = i0 * out_stride0 + i1 * out_stride1 + i2 * out_stride2
93
+
94
+ val = tl.load(in_ptr + in_offset, mask=mask)
95
+ tl.store(out_ptr + out_offset, val, mask=mask)
96
+
97
+
98
+ @triton.jit
99
+ def repeat_4d_kernel(
100
+ in_ptr, out_ptr,
101
+ in_stride0, in_stride1, in_stride2, in_stride3,
102
+ out_stride0, out_stride1, out_stride2, out_stride3,
103
+ out_shape0, out_shape1, out_shape2, out_shape3,
104
+ in_shape0, in_shape1, in_shape2, in_shape3,
105
+ num_tasks,
106
+ BLOCK_SIZE: tl.constexpr,
107
+ ):
108
+ """Repeat kernel for 4D tensors."""
109
+ pid = tl.program_id(0).to(tl.int64)
110
+ tid = pid.to(tl.int64) * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE) # 64-bit from the program id: the product itself wraps past 2^31 elements (register 58)
111
+ mask = tid < num_tasks
112
+
113
+ i3 = tid % out_shape3
114
+ tmp = tid // out_shape3
115
+ i2 = tmp % out_shape2
116
+ tmp = tmp // out_shape2
117
+ i1 = tmp % out_shape1
118
+ i0 = tmp // out_shape1
119
+
120
+ in_offset = (
121
+ (i0 % in_shape0) * in_stride0
122
+ + (i1 % in_shape1) * in_stride1
123
+ + (i2 % in_shape2) * in_stride2
124
+ + (i3 % in_shape3) * in_stride3
125
+ )
126
+ out_offset = (
127
+ i0 * out_stride0 + i1 * out_stride1
128
+ + i2 * out_stride2 + i3 * out_stride3
129
+ )
130
+
131
+ val = tl.load(in_ptr + in_offset, mask=mask)
132
+ tl.store(out_ptr + out_offset, val, mask=mask)
@@ -0,0 +1,374 @@
1
+ """
2
+ S5 — DC-AE residual chain band-streamed execution.
3
+
4
+ Implements the runtime wrapper that absorbs a long residual chain
5
+ (detected by `OpLevelTilingEngine._detect_residual_chains`) into a
6
+ single band-streamed compute. Reduces per-band intermediate footprint
7
+ from 3× full-resolution buffers to 1× band-sized buffer.
8
+
9
+ The chain pattern (validated on Sana 4Kpx VAE DC-AE blocks):
10
+
11
+ T_base (fork output)
12
+ |
13
+ |--- (chain): conv -> silu -> conv -> permute -> rms_norm -> add -> permute
14
+ |
15
+ +--- merge_add: chain_output + T_base = output
16
+
17
+ For each band of H rows:
18
+ 1. Slice T_base [h_in_start:h_in_end] with halo for conv kernels
19
+ 2. Run the chain ops on the band (PyTorch ATen)
20
+ 3. Trim halo from chain output
21
+ 4. Add T_base band → write to output[h_start:h_end]
22
+
23
+ Live tensor footprint per band: T_base (full) + output (full, fill in
24
+ place) + ~1 band intermediate (small) → fits 16 GiB on Sana 4Kpx VAE
25
+ 4096² peak.
26
+
27
+ R34 conformant: pattern detection is structural (`fork → linear≥3 →
28
+ merge`), no model-name lookup. R30 dual-branch: compiled path uses
29
+ PyTorch ATen here; triton path port will add NBX equivalent.
30
+
31
+ S5 P-PRISM-NEVER-REFUSE v2 2026-05-13.
32
+ """
33
+ from __future__ import annotations
34
+
35
+ from typing import Any, Dict, List, Optional
36
+
37
+
38
+
39
+ class ChainSentinel:
40
+ """Zero-allocation sentinel returned by chain intermediate
41
+ interceptors. Carries no real data — the merge interceptor
42
+ reads the precomputed merge output from the chain registry.
43
+ """
44
+
45
+ __slots__ = ("chain_id", "shape", "dtype", "device")
46
+
47
+ def __init__(self, chain_id, shape, dtype, device):
48
+ self.chain_id = chain_id
49
+ self.shape = tuple(shape)
50
+ self.dtype = dtype
51
+ self.device = device
52
+
53
+ @property
54
+ def ndim(self):
55
+ return len(self.shape)
56
+
57
+ @property
58
+ def _nbytes(self):
59
+ return 0
60
+
61
+ def __repr__(self):
62
+ return f"ChainSentinel(chain_id={self.chain_id}, shape={self.shape})"
63
+
64
+
65
+ def resolve_chain_weights(
66
+ chain_spec: Dict[str, Any],
67
+ dag: Dict[str, Any],
68
+ weights: Dict[str, Any],
69
+ ) -> Dict[str, Any]:
70
+ """Look up the weight tensors each chain op needs.
71
+
72
+ Parses the chain ops' `input_tensor_ids` from the DAG, identifies
73
+ `param::*` references, and pulls the matching entries from the
74
+ executor's `_weights` dict.
75
+
76
+ Returns a dict shaped for `band_streamed_chain_torch`:
77
+ {
78
+ "conv1_weight": tensor, "conv1_bias": tensor or None,
79
+ "conv1_padding": [1, 1], "conv1_stride": [1, 1],
80
+ "conv1_dilation": [1, 1], "conv1_groups": 1,
81
+ "conv2_weight": tensor, "conv2_bias": tensor or None,
82
+ "conv2_padding": ..., (same fields)
83
+ "norm_weight": tensor, "norm_eps": 1e-6,
84
+ "post_norm_bias": tensor or None,
85
+ "permute_forward": [0, 2, 3, 1],
86
+ "permute_backward": [0, 3, 1, 2],
87
+ }
88
+
89
+ Returns None if any required weight cannot be resolved.
90
+ """
91
+ ops = dag.get("ops", {})
92
+ chain_uids = chain_spec["chain_uids"]
93
+ out: Dict[str, Any] = {
94
+ "conv1_weight": None, "conv1_bias": None,
95
+ "conv1_padding": [1, 1], "conv1_stride": [1, 1],
96
+ "conv1_dilation": [1, 1], "conv1_groups": 1,
97
+ "conv2_weight": None, "conv2_bias": None,
98
+ "conv2_padding": [1, 1], "conv2_stride": [1, 1],
99
+ "conv2_dilation": [1, 1], "conv2_groups": 1,
100
+ "norm_weight": None, "norm_eps": 1e-6,
101
+ "post_norm_bias": None,
102
+ "permute_forward": [0, 2, 3, 1],
103
+ "permute_backward": [0, 3, 1, 2],
104
+ }
105
+
106
+ conv_idx = 0
107
+ for uid in chain_uids:
108
+ op = ops.get(uid, {})
109
+ op_type = op.get("op_type", "")
110
+ in_tids = op.get("input_tensor_ids", [])
111
+ if op_type == "aten::convolution":
112
+ # input_tensor_ids: [activation, weight, optional bias]
113
+ if len(in_tids) >= 2:
114
+ w_tid = in_tids[1]
115
+ if isinstance(w_tid, str) and w_tid.startswith("param::"):
116
+ w = weights.get(w_tid[len("param::"):])
117
+ if w is None:
118
+ return {}
119
+ out[f"conv{conv_idx + 1}_weight"] = w
120
+ if len(in_tids) >= 3:
121
+ b_tid = in_tids[2]
122
+ if isinstance(b_tid, str) and b_tid.startswith("param::"):
123
+ out[f"conv{conv_idx + 1}_bias"] = weights.get(
124
+ b_tid[len("param::"):])
125
+ # Conv attrs from args: [act, w, b, stride, padding, dil,
126
+ # transposed, output_padding, groups]
127
+ attrs = op.get("attributes", {})
128
+ args = attrs.get("args", [])
129
+
130
+ def _get_list(arg):
131
+ if isinstance(arg, dict) and arg.get("type") == "list":
132
+ return [int(v) if isinstance(v, int) else int(
133
+ v.get("value", 1)) for v in arg.get("value", [])]
134
+ return None
135
+
136
+ def _get_scalar(arg):
137
+ if isinstance(arg, dict) and arg.get("type") == "scalar":
138
+ return arg.get("value")
139
+ return None
140
+
141
+ if len(args) >= 4:
142
+ v = _get_list(args[3])
143
+ if v:
144
+ out[f"conv{conv_idx + 1}_stride"] = v
145
+ if len(args) >= 5:
146
+ v = _get_list(args[4])
147
+ if v:
148
+ out[f"conv{conv_idx + 1}_padding"] = v
149
+ if len(args) >= 6:
150
+ v = _get_list(args[5])
151
+ if v:
152
+ out[f"conv{conv_idx + 1}_dilation"] = v
153
+ if len(args) >= 9:
154
+ v = _get_scalar(args[8])
155
+ if isinstance(v, int):
156
+ out[f"conv{conv_idx + 1}_groups"] = v
157
+ conv_idx += 1
158
+ elif op_type == "custom::rms_norm":
159
+ if len(in_tids) >= 2:
160
+ w_tid = in_tids[1]
161
+ if isinstance(w_tid, str) and w_tid.startswith("param::"):
162
+ w = weights.get(w_tid[len("param::"):])
163
+ if w is None:
164
+ return {}
165
+ out["norm_weight"] = w
166
+ attrs = op.get("attributes", {})
167
+ for arg in attrs.get("args", []):
168
+ if isinstance(arg, dict) and arg.get("type") == "scalar":
169
+ v = arg.get("value")
170
+ if isinstance(v, float):
171
+ out["norm_eps"] = v
172
+ break
173
+ elif op_type == "aten::add":
174
+ # Post-rms_norm bias-add: a learnable shift.
175
+ # input_tensor_ids: [activation, bias_param]
176
+ if len(in_tids) >= 2:
177
+ b_tid = in_tids[1]
178
+ if isinstance(b_tid, str) and b_tid.startswith("param::"):
179
+ out["post_norm_bias"] = weights.get(
180
+ b_tid[len("param::"):])
181
+ elif op_type == "aten::permute":
182
+ attrs = op.get("attributes", {})
183
+ args = attrs.get("args", [])
184
+ if len(args) >= 2 and isinstance(args[1], dict) \
185
+ and args[1].get("type") == "list":
186
+ perm = [int(v.get("value", 0)) if isinstance(v, dict)
187
+ else int(v) for v in args[1].get("value", [])]
188
+ if perm == [0, 2, 3, 1]:
189
+ out["permute_forward"] = perm
190
+ elif perm == [0, 3, 1, 2]:
191
+ out["permute_backward"] = perm
192
+
193
+ if out["conv1_weight"] is None or out["conv2_weight"] is None:
194
+ return {}
195
+ return out
196
+
197
+
198
+
199
+ # ---------------------------------------------------------------------------
200
+ # NBX-PURE TRITON variant — R33 zero-torch port of band_streamed_chain_torch.
201
+ # ---------------------------------------------------------------------------
202
+ # Same band-streaming algorithm, same correctness invariant (halo_carry),
203
+ # same memory shape. The only difference is the backend: every ATen op
204
+ # is replaced by its NBX wrapper from `nbxtensor.ops.wrappers`.
205
+ #
206
+ # P-TRITON-LIVE-WATERMARK-AUDIT 2026-05-14 L4: closes the R30 chain wrapper
207
+ # gap left open by commit c9d2581 ("future band_streamed_chain_nbx would
208
+ # close this gap"). On Sana 4Kpx 16g triton the L2 LIVE_DUMP showed two
209
+ # 4 GiB tensors at (1, 128, 4096, 4096) co-resident at add::89 because
210
+ # the chain wrapper was SKIP'd on triton — natural NBX dispatch keeps
211
+ # all chain intermediates fully materialized. With this wrapper the
212
+ # chain runs band-by-band on the triton arena tensors, peak transient
213
+ # drops to 1/tile_factor of the chain intermediate.
214
+
215
+
216
+ def band_streamed_chain_nbx(
217
+ t_base: "Any",
218
+ chain_weights: Dict[str, Any],
219
+ tile_factor: int,
220
+ halo: int,
221
+ ) -> "Any":
222
+ """NBXTensor band-streamed residual chain (R33-pure mirror of
223
+ `band_streamed_chain_torch`).
224
+
225
+ Args:
226
+ t_base: NBXTensor, the fork tensor (residual base). Mutated in
227
+ place to hold the merge output. Returned for caller convenience.
228
+ chain_weights: dict from `resolve_chain_weights` — same shape as
229
+ for the torch variant, but weight values are NBXTensor when
230
+ the executor is in triton mode.
231
+ tile_factor: number of bands along H.
232
+ halo: rows of halo on each side per band.
233
+
234
+ Returns: t_base (mutated).
235
+
236
+ R33: no `torch.*`, no `F.*`. All ops via
237
+ `nbxtensor.ops.wrappers` and NBXTensor methods.
238
+
239
+ Correctness invariant: halo_carry is a clone of the rows the NEXT
240
+ band needs as its top halo, captured BEFORE the current band's
241
+ `add_` overwrites them. The first band uses t_base directly because
242
+ no top halo has been overwritten yet.
243
+ """
244
+ from nbxtensor.tensor import NBXTensor
245
+ from nbxtensor.backend.runtime import set_device
246
+ from nbxtensor.ops.conv_wrappers import conv2d_wrapper
247
+ from nbxtensor.ops.elementwise_wrappers import silu as silu_w, add as add_w
248
+ from nbxtensor.ops.norm_wrappers import rms_norm as rms_norm_w
249
+
250
+ # P-TRITON-LIVE-WATERMARK-AUDIT L4b: explicit device sync at
251
+ # entry. P-TRITON-CHAIN-CPU-POINTER C1 2026-05-14: diagnostic
252
+ # NBX_CHAIN_DIAG showed 1024² and 2048² chains succeed but
253
+ # 4096² chains fail with "Pointer argument (at 0) cannot be
254
+ # accessed from Triton (cpu tensor?)" while t_base+weights all
255
+ # report dev=0 contig=True at chain entry. The failure must
256
+ # therefore happen at an intermediate allocation (slice +
257
+ # contiguous → 1 GiB band, conv2d output → 1 GiB) where the
258
+ # device-context drifts. C3 fix: call `set_device(t_base)`
259
+ # before EVERY conv2d_wrapper / rms_norm_w / add_w in the
260
+ # band loop — overhead is tiny (single cudaSetDevice per op)
261
+ # vs the chain crash.
262
+ set_device(t_base)
263
+
264
+ N, C, H, W = t_base.shape
265
+ from nbxtensor.ops.tiling_sizes import residual_chain_bands # the one band geometry (the census derives by it)
266
+ bands = residual_chain_bands(H, tile_factor, halo)
267
+ band_h = (H + tile_factor - 1) // tile_factor
268
+ # P-TRITON-CHAIN-CPU-POINTER C3c 2026-05-14: log halo / tile_factor /
269
+ # band_h / H so we can confirm the band_h+halo math matches what the
270
+ # diag CHAIN_STEP shows (e.g. 1030 = 1024 + 6 implies halo=6 not 2).
271
+ import os as _os_cd3
272
+ if _os_cd3.environ.get("NBX_CHAIN_DIAG", "0") == "1":
273
+ print(f" [CHAIN_GEOM H={H} band_h={band_h} halo={halo} "
274
+ f"tile_factor={tile_factor}]", flush=True)
275
+
276
+ halo_carry = None # type: Optional[NBXTensor]
277
+
278
+ for i, (h_start, h_end, h_in_start, h_in_end) in enumerate(bands):
279
+
280
+ # Build the input band.
281
+ # If we have a halo_carry AND the top-halo region [h_in_start,
282
+ # h_start) has been overwritten by the previous band's add_,
283
+ # take the top from halo_carry and the rest from t_base.
284
+ if halo_carry is not None and h_in_start < h_start:
285
+ top_size = h_start - h_in_start
286
+ top_band = halo_carry[:, :, -top_size:, :]
287
+ rest_band = t_base[:, :, h_start:h_in_end, :]
288
+ band = NBXTensor.cat([top_band, rest_band], dim=2).contiguous()
289
+ else:
290
+ band = t_base[:, :, h_in_start:h_in_end, :].contiguous()
291
+
292
+ # Save halo for next band BEFORE overwriting (clone detaches
293
+ # from t_base storage).
294
+ if i + 1 < tile_factor:
295
+ halo_save_size = min(halo, h_end - h_start)
296
+ halo_carry = t_base[:, :,
297
+ h_end - halo_save_size:h_end, :].clone()
298
+
299
+ # conv1 — anchor device per op (the band size at 4096² is
300
+ # 1 GiB; the allocator path inside NBXTensor.empty cudaSetDevice
301
+ # can drift Triton's active device).
302
+ set_device(band)
303
+ w1 = chain_weights["conv1_weight"]
304
+ b1 = chain_weights["conv1_bias"]
305
+ import os as _os_cd2
306
+ if _os_cd2.environ.get("NBX_CHAIN_DIAG", "0") == "1":
307
+ _bp = getattr(band, "_data_ptr", "?")
308
+ _bd = getattr(band, "_device_idx", "?")
309
+ _bc = band.is_contiguous() if hasattr(
310
+ band, 'is_contiguous') else "?"
311
+ print(f" [CHAIN_STEP i={i} h_start={h_start} h_end={h_end} "
312
+ f"h_in_start={h_in_start} h_in_end={h_in_end} "
313
+ f"conv1_pre band ptr={_bp} dev={_bd} "
314
+ f"contig={_bc} shape={tuple(band.shape)}]",
315
+ flush=True)
316
+ band = conv2d_wrapper(
317
+ band, w1, b1,
318
+ stride=tuple(chain_weights["conv1_stride"]),
319
+ padding=tuple(chain_weights["conv1_padding"]),
320
+ dilation=tuple(chain_weights["conv1_dilation"]),
321
+ groups=chain_weights["conv1_groups"],
322
+ )
323
+
324
+ # silu
325
+ set_device(band)
326
+ band = silu_w(band)
327
+
328
+ # conv2
329
+ set_device(band)
330
+ w2 = chain_weights["conv2_weight"]
331
+ b2 = chain_weights["conv2_bias"]
332
+ band = conv2d_wrapper(
333
+ band, w2, b2,
334
+ stride=tuple(chain_weights["conv2_stride"]),
335
+ padding=tuple(chain_weights["conv2_padding"]),
336
+ dilation=tuple(chain_weights["conv2_dilation"]),
337
+ groups=chain_weights["conv2_groups"],
338
+ )
339
+
340
+ # permute NCHW → NHWC (R33-pure NBXTensor.permute)
341
+ band = band.permute(*chain_weights["permute_forward"]).contiguous()
342
+
343
+ # rms_norm over last (feature) dim
344
+ set_device(band)
345
+ norm_w = chain_weights["norm_weight"]
346
+ eps = float(chain_weights.get("norm_eps", 1e-6))
347
+ band = rms_norm_w(band, norm_w, eps)
348
+
349
+ # post-norm bias shift (if any)
350
+ post_bias = chain_weights.get("post_norm_bias")
351
+ if post_bias is not None:
352
+ set_device(band)
353
+ band = add_w(band, post_bias)
354
+
355
+ # permute NHWC → NCHW
356
+ band = band.permute(*chain_weights["permute_backward"]).contiguous()
357
+
358
+ # Trim halo from chain output, then add to t_base in place via
359
+ # __setitem__ + add. NBX add_inplace_nbx requires identical
360
+ # shapes AND contiguous target, but t_base[:, :, h_start:h_end, :]
361
+ # is a non-contig view (slicing on dim 2) — so we use the
362
+ # `add_w` + setitem pattern: materialize the band-sized sum,
363
+ # write it back. The setitem path uses _strided_scatter for
364
+ # the non-contig dst and a single contiguous src copy.
365
+ trim_top = h_start - h_in_start
366
+ trim_h = h_end - h_start
367
+ band_out = band[:, :, trim_top:trim_top + trim_h, :]
368
+ t_base_slice = t_base[:, :, h_start:h_end, :]
369
+ # add returns a new contiguous tensor; setitem writes back.
370
+ set_device(t_base)
371
+ t_base[:, :, h_start:h_end, :] = add_w(t_base_slice, band_out)
372
+
373
+ return t_base
374
+
@@ -0,0 +1,68 @@
1
+ """RMSNorm — pure @triton.jit kernel. Ported from attorch (MIT)."""
2
+
3
+ import triton
4
+ import triton.language as tl
5
+ from triton import next_power_of_2
6
+
7
+ from nbxtensor.ops._configs import nbx_autotune, row_program_configs, prune_row_programs
8
+
9
+
10
+ # rows per program and warps: the certified configuration of the key (workstream 1), the key the derived census forms
11
+ # (`launch_keys.rms_norm_launches`)
12
+ @nbx_autotune(configs=row_program_configs(), key=['BATCH_BUCKET', 'FEAT_BUCKET', 'scale_by_weight', 'SATURATE_F16'],
13
+ prune_configs_by={'early_config_prune': prune_row_programs}, cache_results=True)
14
+ @triton.heuristics({
15
+ 'BLOCK_SIZE_FEAT': lambda args: next_power_of_2(args['feat_dim']),
16
+ })
17
+ @triton.jit
18
+ def rms_norm_forward_kernel(
19
+ input_ptr, weight_ptr,
20
+ output_ptr,
21
+ batch_dim, feat_dim, BATCH_BUCKET, FEAT_BUCKET,
22
+ input_batch_stride, input_feat_stride,
23
+ output_batch_stride, output_feat_stride,
24
+ eps,
25
+ scale_by_weight: tl.constexpr,
26
+ BLOCK_SIZE_BATCH: tl.constexpr,
27
+ BLOCK_SIZE_FEAT: tl.constexpr,
28
+ SATURATE_F16: tl.constexpr = False, # the protected fp16 store: finite values clamp to ±65504
29
+ ):
30
+ """RMS normalization forward.
31
+
32
+ input: [batch_dim, feat_dim]
33
+ weight: [feat_dim] (optional)
34
+ output: [batch_dim, feat_dim]
35
+ """
36
+ batch_pid = tl.program_id(0).to(tl.int64)
37
+
38
+ batch_offset = batch_pid * BLOCK_SIZE_BATCH + tl.arange(0, BLOCK_SIZE_BATCH)
39
+ feat_offset = tl.arange(0, BLOCK_SIZE_FEAT)
40
+
41
+ batch_mask = batch_offset < batch_dim
42
+ feat_mask = feat_offset < feat_dim
43
+
44
+ input_ptr += (input_batch_stride * batch_offset[:, None] +
45
+ input_feat_stride * feat_offset[None, :])
46
+ output_ptr += (output_batch_stride * batch_offset[:, None] +
47
+ output_feat_stride * feat_offset[None, :])
48
+
49
+ inp = tl.load(input_ptr,
50
+ mask=batch_mask[:, None] & feat_mask[None, :]).to(tl.float32)
51
+ inv_rms = tl.rsqrt(tl.sum(inp * inp, axis=1) / feat_dim + eps)
52
+ output = inp * inv_rms[:, None]
53
+
54
+ if scale_by_weight:
55
+ weight = tl.load(weight_ptr + feat_offset, mask=feat_mask)
56
+ output *= weight
57
+
58
+ if SATURATE_F16:
59
+ # The store narrows to fp16: the same protected conversion the dtype
60
+ # engine's cast copy applied when this kernel stored fp32 and the wrap
61
+ # cast the result (copy_kernel's expression) — an fp16 stream with
62
+ # outliers past 65504 (VibeVoice's Qwen2, 2026-09-08) clamps instead
63
+ # of overflowing to inf.
64
+ is_finite = (output == output) & (output != float("inf")) & (output != float("-inf"))
65
+ clamped = tl.minimum(tl.maximum(output, -65504.0), 65504.0)
66
+ output = tl.where(is_finite, clamped, output)
67
+ tl.store(output_ptr, output,
68
+ mask=batch_mask[:, None] & feat_mask[None, :])