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.
- nbxtensor/THIRD_PARTY_NOTICES.md +287 -0
- nbxtensor/__init__.py +17 -0
- nbxtensor/backend/__init__.py +1 -0
- nbxtensor/backend/capabilities.py +207 -0
- nbxtensor/backend/cpu/__init__.py +1 -0
- nbxtensor/backend/cpu/blas.py +102 -0
- nbxtensor/backend/cpu/pool.py +204 -0
- nbxtensor/backend/cpu_backend.py +162 -0
- nbxtensor/backend/device_facts.py +105 -0
- nbxtensor/backend/device_files.py +129 -0
- nbxtensor/backend/device_names.py +18 -0
- nbxtensor/backend/devices/amd/cdna.yml +228 -0
- nbxtensor/backend/devices/amd/cdna2.yml +228 -0
- nbxtensor/backend/devices/amd/cdna3.yml +227 -0
- nbxtensor/backend/devices/apple/apple_m1.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m1_max.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m1_pro.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m1_ultra.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m2.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m2_max.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m2_pro.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m2_ultra.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m3.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m3_max.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m3_pro.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m3_ultra.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m4.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m4_max.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m4_pro.yml +308 -0
- nbxtensor/backend/devices/apple/apple_m5.yml +269 -0
- nbxtensor/backend/devices/apple/apple_m5_max.yml +269 -0
- nbxtensor/backend/devices/apple/apple_m5_pro.yml +269 -0
- nbxtensor/backend/devices/apple/apple_m5_ultra.yml +269 -0
- nbxtensor/backend/devices/apple/apple_m6.yml +269 -0
- nbxtensor/backend/devices/apple/apple_silicon.yml +263 -0
- nbxtensor/backend/devices/nvidia/ampere.yml +214 -0
- nbxtensor/backend/devices/nvidia/hopper.yml +213 -0
- nbxtensor/backend/devices/nvidia/volta.yml +411 -0
- nbxtensor/backend/faults.py +151 -0
- nbxtensor/backend/host_memory.py +185 -0
- nbxtensor/backend/launcher.py +2350 -0
- nbxtensor/backend/launcher_contract.py +429 -0
- nbxtensor/backend/metal_backend.py +661 -0
- nbxtensor/backend/metal_device.py +1274 -0
- nbxtensor/backend/process_memory.py +73 -0
- nbxtensor/backend/replay_graph.py +322 -0
- nbxtensor/backend/runtime.py +409 -0
- nbxtensor/backend/triton_ext_driver.py +735 -0
- nbxtensor/dtype/__init__.py +1 -0
- nbxtensor/dtype/convert.py +107 -0
- nbxtensor/dtype/dtypes.yml +70 -0
- nbxtensor/dtype/itemsize.py +166 -0
- nbxtensor/dtype/nbx_dtype.py +72 -0
- nbxtensor/dtype/operands.py +158 -0
- nbxtensor/dtype/outputs.py +64 -0
- nbxtensor/dtype/policy.py +155 -0
- nbxtensor/dtype/policy.yml +51 -0
- nbxtensor/dtype/promotion.py +112 -0
- nbxtensor/host.py +55 -0
- nbxtensor/io/__init__.py +1 -0
- nbxtensor/io/read_rate.py +197 -0
- nbxtensor/io/safetensors.py +314 -0
- nbxtensor/memory/__init__.py +9 -0
- nbxtensor/memory/allocator.py +1988 -0
- nbxtensor/memory/arena.py +75 -0
- nbxtensor/memory/device_memory.py +150 -0
- nbxtensor/memory/device_transfer.py +154 -0
- nbxtensor/memory/layout.py +43 -0
- nbxtensor/memory/memory_pool.py +191 -0
- nbxtensor/memory/metal.py +96 -0
- nbxtensor/memory/oom_advice.py +91 -0
- nbxtensor/memory/pointer_tables.py +323 -0
- nbxtensor/memory/pool.py +507 -0
- nbxtensor/memory/shadow.py +43 -0
- nbxtensor/memory/slab.py +273 -0
- nbxtensor/memory/trace_replay.py +122 -0
- nbxtensor/memory/traces/sana-video-2b-720p.16g.2026-11-02.tsv +13610 -0
- nbxtensor/memory/vmm.py +118 -0
- nbxtensor/ops/__init__.py +1 -0
- nbxtensor/ops/_autotune_policy.py +90 -0
- nbxtensor/ops/_common.py +32 -0
- nbxtensor/ops/_configs.py +1041 -0
- nbxtensor/ops/_cost.py +231 -0
- nbxtensor/ops/abs.py +17 -0
- nbxtensor/ops/adaptive_avg_pool2d.py +161 -0
- nbxtensor/ops/add.py +96 -0
- nbxtensor/ops/addcdiv.py +29 -0
- nbxtensor/ops/addcmul.py +29 -0
- nbxtensor/ops/addmv_op.py +64 -0
- nbxtensor/ops/addr.py +68 -0
- nbxtensor/ops/all_reduce.py +83 -0
- nbxtensor/ops/amax.py +40 -0
- nbxtensor/ops/any_reduce.py +83 -0
- nbxtensor/ops/arange_op.py +27 -0
- nbxtensor/ops/argmax.py +107 -0
- nbxtensor/ops/argmin.py +93 -0
- nbxtensor/ops/atan2.py +71 -0
- nbxtensor/ops/attention_wrappers.py +1648 -0
- nbxtensor/ops/autotune_bucket.py +137 -0
- nbxtensor/ops/autotune_cache.py +430 -0
- nbxtensor/ops/autotune_certified.py +1262 -0
- nbxtensor/ops/autotune_refusals.py +380 -0
- nbxtensor/ops/autotune_settings.py +58 -0
- nbxtensor/ops/avg_pool2d.py +73 -0
- nbxtensor/ops/baddbmm_op.py +132 -0
- nbxtensor/ops/batch_norm.py +163 -0
- nbxtensor/ops/binary_strided.py +196 -0
- nbxtensor/ops/bitwise_and.py +26 -0
- nbxtensor/ops/bitwise_left_shift.py +47 -0
- nbxtensor/ops/bitwise_not.py +24 -0
- nbxtensor/ops/bitwise_or.py +26 -0
- nbxtensor/ops/bitwise_right_shift.py +47 -0
- nbxtensor/ops/bucketize.py +37 -0
- nbxtensor/ops/cat_op.py +87 -0
- nbxtensor/ops/celu.py +20 -0
- nbxtensor/ops/clamp.py +24 -0
- nbxtensor/ops/clamp_min.py +22 -0
- nbxtensor/ops/conv2d.py +265 -0
- nbxtensor/ops/conv2d_m8n8k4.py +165 -0
- nbxtensor/ops/conv_depthwise2d.py +154 -0
- nbxtensor/ops/conv_transpose2d.py +148 -0
- nbxtensor/ops/conv_wrappers.py +1482 -0
- nbxtensor/ops/copy.py +18 -0
- nbxtensor/ops/copy_op.py +39 -0
- nbxtensor/ops/cos.py +17 -0
- nbxtensor/ops/count_nonzero.py +64 -0
- nbxtensor/ops/cross_entropy.py +67 -0
- nbxtensor/ops/cummax.py +109 -0
- nbxtensor/ops/cummin.py +105 -0
- nbxtensor/ops/cumsum.py +244 -0
- nbxtensor/ops/decode_attn_vec.py +162 -0
- nbxtensor/ops/depthwise_conv2d.py +132 -0
- nbxtensor/ops/dequant_gemv.py +190 -0
- nbxtensor/ops/dft.py +67 -0
- nbxtensor/ops/dispatch.py +1228 -0
- nbxtensor/ops/div.py +75 -0
- nbxtensor/ops/dot_op.py +67 -0
- nbxtensor/ops/dropout.py +23 -0
- nbxtensor/ops/dtype_convert.py +42 -0
- nbxtensor/ops/elementwise_launch.py +81 -0
- nbxtensor/ops/elementwise_wrappers.py +2315 -0
- nbxtensor/ops/elu.py +20 -0
- nbxtensor/ops/embedding.py +69 -0
- nbxtensor/ops/eq.py +32 -0
- nbxtensor/ops/erf.py +18 -0
- nbxtensor/ops/exp.py +17 -0
- nbxtensor/ops/exp2.py +18 -0
- nbxtensor/ops/fft_op.py +125 -0
- nbxtensor/ops/fill_op.py +20 -0
- nbxtensor/ops/flash_attention.py +307 -0
- nbxtensor/ops/flash_attention_m8n8k4.py +384 -0
- nbxtensor/ops/flash_decode.py +78 -0
- nbxtensor/ops/flip_op.py +60 -0
- nbxtensor/ops/floor.py +90 -0
- nbxtensor/ops/full_op.py +24 -0
- nbxtensor/ops/fused_moe.py +417 -0
- nbxtensor/ops/fused_moe_m8n8k4.py +99 -0
- nbxtensor/ops/fused_upsample_conv.py +413 -0
- nbxtensor/ops/gather_op.py +52 -0
- nbxtensor/ops/ge.py +32 -0
- nbxtensor/ops/gelu.py +31 -0
- nbxtensor/ops/gemv_vec.py +80 -0
- nbxtensor/ops/glu.py +43 -0
- nbxtensor/ops/grid_sampler.py +145 -0
- nbxtensor/ops/group_norm_tiled.py +67 -0
- nbxtensor/ops/groupnorm.py +123 -0
- nbxtensor/ops/gt.py +32 -0
- nbxtensor/ops/hardsigmoid.py +18 -0
- nbxtensor/ops/hardswish.py +19 -0
- nbxtensor/ops/im2col.py +57 -0
- nbxtensor/ops/index_add.py +95 -0
- nbxtensor/ops/index_put_op.py +92 -0
- nbxtensor/ops/index_select.py +121 -0
- nbxtensor/ops/index_wrappers.py +770 -0
- nbxtensor/ops/isfinite.py +20 -0
- nbxtensor/ops/isinf.py +20 -0
- nbxtensor/ops/isnan.py +18 -0
- nbxtensor/ops/launch_keys.py +1054 -0
- nbxtensor/ops/launch_observer.py +54 -0
- nbxtensor/ops/layernorm.py +71 -0
- nbxtensor/ops/le.py +35 -0
- nbxtensor/ops/leaky_relu.py +19 -0
- nbxtensor/ops/lerp.py +76 -0
- nbxtensor/ops/linalg_wrappers.py +1370 -0
- nbxtensor/ops/linspace_op.py +47 -0
- nbxtensor/ops/log.py +17 -0
- nbxtensor/ops/log_sigmoid.py +23 -0
- nbxtensor/ops/logical_and.py +26 -0
- nbxtensor/ops/logical_not.py +24 -0
- nbxtensor/ops/logical_or.py +26 -0
- nbxtensor/ops/logical_xor.py +37 -0
- nbxtensor/ops/loss_wrappers.py +282 -0
- nbxtensor/ops/lt.py +32 -0
- nbxtensor/ops/masked_fill.py +21 -0
- nbxtensor/ops/matmul.py +377 -0
- nbxtensor/ops/matmul_m8n8k4.py +235 -0
- nbxtensor/ops/max_pool2d.py +74 -0
- nbxtensor/ops/max_pool3d.py +93 -0
- nbxtensor/ops/max_reduce.py +91 -0
- nbxtensor/ops/maximum.py +18 -0
- nbxtensor/ops/mean.py +40 -0
- nbxtensor/ops/min_reduce.py +91 -0
- nbxtensor/ops/minimum.py +18 -0
- nbxtensor/ops/mish.py +22 -0
- nbxtensor/ops/mma_m8n8k4.py +152 -0
- nbxtensor/ops/moe_align.py +195 -0
- nbxtensor/ops/moe_decode_vec.py +374 -0
- nbxtensor/ops/moe_device_residency.py +141 -0
- nbxtensor/ops/moe_wrappers.py +345 -0
- nbxtensor/ops/mse_loss.py +79 -0
- nbxtensor/ops/mul.py +51 -0
- nbxtensor/ops/nan_to_num.py +23 -0
- nbxtensor/ops/ne.py +32 -0
- nbxtensor/ops/neg.py +17 -0
- nbxtensor/ops/nllloss.py +124 -0
- nbxtensor/ops/nonzero.py +33 -0
- nbxtensor/ops/nonzero_op.py +62 -0
- nbxtensor/ops/norm_wrappers.py +579 -0
- nbxtensor/ops/ones_op.py +20 -0
- nbxtensor/ops/oracles/__init__.py +6 -0
- nbxtensor/ops/oracles/conv2d_fp64.py +450 -0
- nbxtensor/ops/pad_op.py +159 -0
- nbxtensor/ops/paged_decode_attn.py +215 -0
- nbxtensor/ops/pixel_shuffle.py +144 -0
- nbxtensor/ops/pixel_unshuffle.py +72 -0
- nbxtensor/ops/pow.py +137 -0
- nbxtensor/ops/prod.py +81 -0
- nbxtensor/ops/rand_op.py +52 -0
- nbxtensor/ops/random_wrappers.py +366 -0
- nbxtensor/ops/reciprocal.py +17 -0
- nbxtensor/ops/reduction_wrappers.py +845 -0
- nbxtensor/ops/relu.py +18 -0
- nbxtensor/ops/remainder.py +46 -0
- nbxtensor/ops/repeat_interleave.py +48 -0
- nbxtensor/ops/repeat_op.py +132 -0
- nbxtensor/ops/residual_chain.py +374 -0
- nbxtensor/ops/rmsnorm.py +68 -0
- nbxtensor/ops/rope.py +142 -0
- nbxtensor/ops/rsqrt.py +17 -0
- nbxtensor/ops/scaled_softmax.py +96 -0
- nbxtensor/ops/scatter_op.py +139 -0
- nbxtensor/ops/screen_oracle.py +479 -0
- nbxtensor/ops/selu.py +22 -0
- nbxtensor/ops/shape_wrappers.py +1032 -0
- nbxtensor/ops/sigmoid.py +19 -0
- nbxtensor/ops/silu.py +27 -0
- nbxtensor/ops/sin.py +17 -0
- nbxtensor/ops/softmax.py +169 -0
- nbxtensor/ops/softplus.py +27 -0
- nbxtensor/ops/sort_op.py +304 -0
- nbxtensor/ops/spectral_wrappers.py +481 -0
- nbxtensor/ops/sqrt.py +17 -0
- nbxtensor/ops/stack_op.py +84 -0
- nbxtensor/ops/std.py +113 -0
- nbxtensor/ops/strided_copy.py +200 -0
- nbxtensor/ops/sub.py +35 -0
- nbxtensor/ops/sum.py +40 -0
- nbxtensor/ops/tan.py +19 -0
- nbxtensor/ops/tanh.py +21 -0
- nbxtensor/ops/threshold.py +19 -0
- nbxtensor/ops/tiling.yml +91 -0
- nbxtensor/ops/tiling_policy.py +43 -0
- nbxtensor/ops/tiling_sizes.py +370 -0
- nbxtensor/ops/topk.py +267 -0
- nbxtensor/ops/trace_op.py +64 -0
- nbxtensor/ops/tril.py +64 -0
- nbxtensor/ops/triu.py +62 -0
- nbxtensor/ops/unfold_op.py +37 -0
- nbxtensor/ops/unique_op.py +97 -0
- nbxtensor/ops/upsample_bilinear2d.py +106 -0
- nbxtensor/ops/upsample_nearest2d.py +52 -0
- nbxtensor/ops/upsample_nearest3d.py +61 -0
- nbxtensor/ops/var.py +136 -0
- nbxtensor/ops/vector_norm.py +216 -0
- nbxtensor/ops/weight_norm.py +104 -0
- nbxtensor/ops/where.py +39 -0
- nbxtensor/ops/wrappers.py +825 -0
- nbxtensor/ops/zeros_op.py +20 -0
- nbxtensor/quant/__init__.py +1 -0
- nbxtensor/quant/quantized_tensor.py +187 -0
- nbxtensor/random/__init__.py +1 -0
- nbxtensor/random/mt_randn.py +154 -0
- nbxtensor/random/rng_pin.py +59 -0
- nbxtensor/random/rng_stream.py +118 -0
- nbxtensor/random/seeded_draw.py +223 -0
- nbxtensor/shape/__init__.py +157 -0
- nbxtensor/tensor.py +1867 -0
- nbxtensor-0.0.1.dist-info/METADATA +379 -0
- nbxtensor-0.0.1.dist-info/RECORD +291 -0
- nbxtensor-0.0.1.dist-info/WHEEL +4 -0
- nbxtensor-0.0.1.dist-info/licenses/LICENSE +189 -0
nbxtensor/ops/copy.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Copy / dtype cast — pure @triton.jit kernel."""
|
|
2
|
+
|
|
3
|
+
import triton
|
|
4
|
+
import triton.language as tl
|
|
5
|
+
|
|
6
|
+
@triton.jit
|
|
7
|
+
def copy_forward_kernel(
|
|
8
|
+
input_ptr, output_ptr,
|
|
9
|
+
n_elements,
|
|
10
|
+
BLOCK_SIZE: tl.constexpr,
|
|
11
|
+
):
|
|
12
|
+
"""Copy tensor (with implicit dtype conversion via pointer types)."""
|
|
13
|
+
pid = tl.program_id(0).to(tl.int64)
|
|
14
|
+
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)
|
|
15
|
+
mask = offset < n_elements
|
|
16
|
+
|
|
17
|
+
x = tl.load(input_ptr + offset, mask=mask)
|
|
18
|
+
tl.store(output_ptr + offset, x, mask=mask)
|
nbxtensor/ops/copy_op.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Copy — pure @triton.jit kernel.
|
|
2
|
+
|
|
3
|
+
Ported from FlagGems copy (Apache-2.0 license).
|
|
4
|
+
Copies elements from src to dst, with optional dtype conversion
|
|
5
|
+
handled by Triton's automatic casting on store.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import triton
|
|
9
|
+
import triton.language as tl
|
|
10
|
+
|
|
11
|
+
@triton.jit
|
|
12
|
+
def copy_kernel(
|
|
13
|
+
src_ptr, dst_ptr,
|
|
14
|
+
n_elements,
|
|
15
|
+
BLOCK_SIZE: tl.constexpr,
|
|
16
|
+
SATURATE_F16: tl.constexpr = False,
|
|
17
|
+
):
|
|
18
|
+
"""Copy src to dst. Dtype conversion happens automatically via Triton's
|
|
19
|
+
store when src and dst pointer types differ.
|
|
20
|
+
|
|
21
|
+
SATURATE_F16: protected float16 downcast — finite values beyond the
|
|
22
|
+
fp16 range clamp to ±65504 instead of overflowing to ±inf. This
|
|
23
|
+
mirrors the compiled DtypeEngine's hardware-protected conversion
|
|
24
|
+
contract (bf16/fp32 sentinel fills like finfo.min must survive a
|
|
25
|
+
V100 fp16 remap as finite extremes; an additive attention mask that
|
|
26
|
+
overflows to -inf poisons softmax rows — the DeepSeek-V2 wrong-token
|
|
27
|
+
incident). NaN and true ±inf inputs pass through unchanged.
|
|
28
|
+
"""
|
|
29
|
+
pid = tl.program_id(0).to(tl.int64)
|
|
30
|
+
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)
|
|
31
|
+
mask = offset < n_elements
|
|
32
|
+
|
|
33
|
+
data = tl.load(src_ptr + offset, mask=mask)
|
|
34
|
+
if SATURATE_F16:
|
|
35
|
+
f = data.to(tl.float32)
|
|
36
|
+
is_finite = (f == f) & (f != float("inf")) & (f != float("-inf"))
|
|
37
|
+
clamped = tl.minimum(tl.maximum(f, -65504.0), 65504.0)
|
|
38
|
+
data = tl.where(is_finite, clamped, f)
|
|
39
|
+
tl.store(dst_ptr + offset, data, mask=mask)
|
nbxtensor/ops/cos.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Cosine — pure @triton.jit kernel."""
|
|
2
|
+
|
|
3
|
+
import triton
|
|
4
|
+
import triton.language as tl
|
|
5
|
+
|
|
6
|
+
@triton.jit
|
|
7
|
+
def cos_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
|
+
tl.store(output_ptr + offset, tl.cos(x.to(tl.float32)), mask=mask)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""Count Nonzero — pure @triton.jit kernel.
|
|
2
|
+
|
|
3
|
+
Counts non-zero elements in a flattened tensor using atomic addition.
|
|
4
|
+
Each block counts its local non-zeros, then atomically adds to the output.
|
|
5
|
+
Extracted from FlagGems (Apache 2.0).
|
|
6
|
+
|
|
7
|
+
Grid: (ceil(numel / BLOCK_SIZE),)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import triton
|
|
11
|
+
import triton.language as tl
|
|
12
|
+
|
|
13
|
+
@triton.jit
|
|
14
|
+
def count_nonzero_kernel(
|
|
15
|
+
x_ptr,
|
|
16
|
+
out_ptr,
|
|
17
|
+
numel,
|
|
18
|
+
BLOCK_SIZE: tl.constexpr,
|
|
19
|
+
):
|
|
20
|
+
"""Count non-zero elements via block-local sum + atomic global add.
|
|
21
|
+
|
|
22
|
+
Each program loads a block of elements, compares != 0, sums the
|
|
23
|
+
boolean result, then atomically adds the count to the output scalar.
|
|
24
|
+
"""
|
|
25
|
+
pid = tl.program_id(0).to(tl.int64)
|
|
26
|
+
block_start = pid * BLOCK_SIZE
|
|
27
|
+
offsets = block_start + tl.arange(0, BLOCK_SIZE)
|
|
28
|
+
mask = offsets < numel
|
|
29
|
+
|
|
30
|
+
x = tl.load(x_ptr + offsets, mask=mask, other=0)
|
|
31
|
+
is_nonzero = (x != 0).to(tl.int64)
|
|
32
|
+
nonzero_count = tl.sum(is_nonzero, axis=0)
|
|
33
|
+
|
|
34
|
+
tl.atomic_add(out_ptr, nonzero_count)
|
|
35
|
+
|
|
36
|
+
@triton.jit
|
|
37
|
+
def count_nonzero_dim_kernel(
|
|
38
|
+
x_ptr,
|
|
39
|
+
out_ptr,
|
|
40
|
+
N,
|
|
41
|
+
numel,
|
|
42
|
+
BLOCK_SIZE: tl.constexpr,
|
|
43
|
+
):
|
|
44
|
+
"""Count non-zero elements along a dimension (after dim_compress).
|
|
45
|
+
|
|
46
|
+
Each program handles one row of the compressed tensor and iterates
|
|
47
|
+
over columns in blocks, accumulating the non-zero count.
|
|
48
|
+
|
|
49
|
+
x_ptr: flattened compressed input (M * N elements, reduction dim = N)
|
|
50
|
+
out_ptr: output of shape (M,)
|
|
51
|
+
"""
|
|
52
|
+
pid_x = tl.program_id(0).to(tl.int64)
|
|
53
|
+
|
|
54
|
+
nonzero_count = tl.zeros((), dtype=tl.int64)
|
|
55
|
+
for start_n in range(0, N, BLOCK_SIZE):
|
|
56
|
+
cols_offsets = start_n + tl.arange(0, BLOCK_SIZE)
|
|
57
|
+
offset = pid_x * N + cols_offsets
|
|
58
|
+
col_mask = (offset < numel) & (cols_offsets < N)
|
|
59
|
+
|
|
60
|
+
x = tl.load(x_ptr + offset, mask=col_mask, other=0)
|
|
61
|
+
is_nonzero = (x != 0).to(tl.int64)
|
|
62
|
+
nonzero_count += tl.sum(is_nonzero)
|
|
63
|
+
|
|
64
|
+
tl.store(out_ptr + pid_x, nonzero_count)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Cross entropy loss — pure @triton.jit kernel.
|
|
2
|
+
|
|
3
|
+
Extracted from attorch (BobMcDear/attorch) cross_entropy_loss_kernels.py.
|
|
4
|
+
Chosen over Liger (523 lines) for inference: simpler, pure, no training extras.
|
|
5
|
+
Forward only. Numerically stable log-sum-exp implementation.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import triton
|
|
9
|
+
import triton.language as tl
|
|
10
|
+
from triton import next_power_of_2
|
|
11
|
+
|
|
12
|
+
@triton.heuristics({
|
|
13
|
+
'BLOCK_SIZE_FEAT': lambda args: next_power_of_2(args['feat_dim']),
|
|
14
|
+
})
|
|
15
|
+
@triton.jit
|
|
16
|
+
def cross_entropy_loss_forward_kernel(
|
|
17
|
+
input_pointer, target_pointer, weight_pointer,
|
|
18
|
+
sum_weights_pointer, output_pointer,
|
|
19
|
+
batch_dim, feat_dim,
|
|
20
|
+
input_batch_stride, input_feat_stride,
|
|
21
|
+
weighted: tl.constexpr,
|
|
22
|
+
BLOCK_SIZE_BATCH: tl.constexpr,
|
|
23
|
+
BLOCK_SIZE_FEAT: tl.constexpr,
|
|
24
|
+
):
|
|
25
|
+
"""Cross entropy loss: -log(softmax(input)[target]).
|
|
26
|
+
|
|
27
|
+
Numerically stable via log-sum-exp trick.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
input_pointer: [batch_dim, feat_dim] logits
|
|
31
|
+
target_pointer: [batch_dim] integer class indices
|
|
32
|
+
weight_pointer: optional [feat_dim] class weights
|
|
33
|
+
output_pointer: [batch_dim/BLOCK_SIZE_BATCH] partial losses
|
|
34
|
+
"""
|
|
35
|
+
batch_pid = tl.program_id(axis=0).to(tl.int64)
|
|
36
|
+
|
|
37
|
+
batch_offset = batch_pid * BLOCK_SIZE_BATCH + tl.arange(0, BLOCK_SIZE_BATCH)
|
|
38
|
+
feat_offset = tl.arange(0, BLOCK_SIZE_FEAT)
|
|
39
|
+
|
|
40
|
+
batch_mask = batch_offset < batch_dim
|
|
41
|
+
feat_mask = feat_offset < feat_dim
|
|
42
|
+
|
|
43
|
+
target = tl.load(target_pointer + batch_offset, mask=batch_mask)
|
|
44
|
+
|
|
45
|
+
pred_pointer = (input_pointer +
|
|
46
|
+
input_feat_stride * target +
|
|
47
|
+
input_batch_stride * batch_offset)
|
|
48
|
+
input_pointer += (input_batch_stride * batch_offset[:, None] +
|
|
49
|
+
input_feat_stride * feat_offset[None, :])
|
|
50
|
+
|
|
51
|
+
input = tl.load(input_pointer, mask=batch_mask[:, None] & feat_mask[None, :],
|
|
52
|
+
other=-float('inf')).to(tl.float32)
|
|
53
|
+
pred = tl.load(pred_pointer, mask=batch_mask).to(tl.float32)
|
|
54
|
+
|
|
55
|
+
# Log-sum-exp: loss = log(sum(exp(x - max))) + max - pred
|
|
56
|
+
mx = tl.max(input, axis=1)
|
|
57
|
+
input -= mx[:, None]
|
|
58
|
+
loss = tl.log(tl.sum(tl.exp(input), axis=1)) - pred + mx
|
|
59
|
+
|
|
60
|
+
if weighted:
|
|
61
|
+
weight = tl.load(weight_pointer + target, mask=batch_mask).to(tl.float32)
|
|
62
|
+
loss *= weight
|
|
63
|
+
tl.store(sum_weights_pointer + batch_pid, tl.sum(weight))
|
|
64
|
+
else:
|
|
65
|
+
loss /= batch_dim
|
|
66
|
+
|
|
67
|
+
tl.store(output_pointer + batch_pid, tl.sum(loss))
|
nbxtensor/ops/cummax.py
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""Cumulative Maximum — pure @triton.jit kernels.
|
|
2
|
+
|
|
3
|
+
Computes running maximum along a dimension, returning both values and indices.
|
|
4
|
+
Uses scan-then-fan algorithm: each block computes a local cummax via
|
|
5
|
+
tl.associative_scan, then partial results are combined across blocks.
|
|
6
|
+
|
|
7
|
+
Extracted from FlagGems (Apache 2.0).
|
|
8
|
+
|
|
9
|
+
Three kernels for the scan-then-fan pipeline:
|
|
10
|
+
1. scan_part_max_kernel — local cummax within each block + partial max
|
|
11
|
+
2. add_base_max_kernel — fan-out: combine partial maxima with local results
|
|
12
|
+
3. cummax_loop_kernel — single-program loop variant for wide reductions
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import triton
|
|
16
|
+
import triton.language as tl
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@triton.jit
|
|
20
|
+
def _cummax_combine(val_a, idx_a, val_b, idx_b):
|
|
21
|
+
"""Associative combiner: keep (value, index) of the maximum."""
|
|
22
|
+
pick_b = val_b > val_a
|
|
23
|
+
# Tie-break right: if equal, keep the later (right) index
|
|
24
|
+
pick_b = pick_b | ((val_a == val_b) & (idx_b >= idx_a))
|
|
25
|
+
val_out = tl.where(pick_b, val_b, val_a)
|
|
26
|
+
idx_out = tl.where(pick_b, idx_b, idx_a)
|
|
27
|
+
return val_out, idx_out
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@triton.jit
|
|
31
|
+
def scan_part_max_kernel(
|
|
32
|
+
inp,
|
|
33
|
+
out,
|
|
34
|
+
out_indices,
|
|
35
|
+
partial_max,
|
|
36
|
+
partial_max_indices,
|
|
37
|
+
n_elements,
|
|
38
|
+
BLOCK_SIZE: tl.constexpr,
|
|
39
|
+
NEED_PARTIAL: tl.constexpr,
|
|
40
|
+
):
|
|
41
|
+
"""Block-local cumulative maximum with optional partial output.
|
|
42
|
+
|
|
43
|
+
Each block loads BLOCK_SIZE elements, computes cummax via associative
|
|
44
|
+
scan, stores results, and optionally writes the block-maximum for
|
|
45
|
+
the fan-out phase.
|
|
46
|
+
"""
|
|
47
|
+
pid = tl.program_id(0).to(tl.int64)
|
|
48
|
+
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)
|
|
49
|
+
mask = offset < n_elements
|
|
50
|
+
|
|
51
|
+
# Load input, use -inf for masked positions
|
|
52
|
+
inp_vals = tl.load(inp + offset, mask=mask, other=float('-inf'))
|
|
53
|
+
inp_vals = inp_vals.to(tl.float32)
|
|
54
|
+
indices = offset
|
|
55
|
+
|
|
56
|
+
# Associative scan for cummax
|
|
57
|
+
result, cummax_idx = tl.associative_scan(
|
|
58
|
+
(inp_vals, indices), 0, _cummax_combine
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
tl.store(out + offset, result, mask=mask)
|
|
62
|
+
tl.store(out_indices + offset, cummax_idx, mask=mask)
|
|
63
|
+
|
|
64
|
+
if tl.constexpr(NEED_PARTIAL):
|
|
65
|
+
# Reduce to find block maximum (tie-break right)
|
|
66
|
+
block_max = tl.max(inp_vals, axis=0)
|
|
67
|
+
# Find rightmost index with block_max value
|
|
68
|
+
is_max = inp_vals == block_max
|
|
69
|
+
max_idx = tl.max(tl.where(is_max, indices, -1), axis=0)
|
|
70
|
+
# Only one thread writes the partial
|
|
71
|
+
if tl.arange(0, BLOCK_SIZE)[0] == 0:
|
|
72
|
+
tl.store(partial_max + pid, block_max)
|
|
73
|
+
tl.store(partial_max_indices + pid, max_idx)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@triton.jit
|
|
77
|
+
def add_base_max_kernel(
|
|
78
|
+
out,
|
|
79
|
+
out_indices,
|
|
80
|
+
partial_max,
|
|
81
|
+
partial_max_indices,
|
|
82
|
+
n_elements,
|
|
83
|
+
BLOCK_SIZE: tl.constexpr,
|
|
84
|
+
):
|
|
85
|
+
"""Fan-out phase: combine partial maxima from prior blocks.
|
|
86
|
+
|
|
87
|
+
For each block (except the first), loads the cumulative partial max
|
|
88
|
+
from the previous block and merges with local results.
|
|
89
|
+
"""
|
|
90
|
+
pid = tl.program_id(0).to(tl.int64)
|
|
91
|
+
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)
|
|
92
|
+
mask = offset < n_elements
|
|
93
|
+
|
|
94
|
+
out_vals = tl.load(out + offset, mask=mask)
|
|
95
|
+
out_idx = tl.load(out_indices + offset, mask=mask)
|
|
96
|
+
|
|
97
|
+
if pid > 0:
|
|
98
|
+
prev_max = tl.load(partial_max + pid - 1)
|
|
99
|
+
prev_idx = tl.load(partial_max_indices + pid - 1)
|
|
100
|
+
|
|
101
|
+
# Merge: if previous partial max >= local, use previous
|
|
102
|
+
use_prev = (prev_max > out_vals) | (
|
|
103
|
+
(prev_max == out_vals) & (prev_idx >= out_idx)
|
|
104
|
+
)
|
|
105
|
+
final_vals = tl.where(use_prev, prev_max, out_vals)
|
|
106
|
+
final_idx = tl.where(use_prev, prev_idx, out_idx)
|
|
107
|
+
|
|
108
|
+
tl.store(out + offset, final_vals, mask=mask)
|
|
109
|
+
tl.store(out_indices + offset, final_idx, mask=mask)
|
nbxtensor/ops/cummin.py
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""Cumulative Minimum — pure @triton.jit kernels.
|
|
2
|
+
|
|
3
|
+
Computes running minimum along a dimension, returning both values and indices.
|
|
4
|
+
Uses scan-then-fan algorithm (mirror of cummax with minimum).
|
|
5
|
+
|
|
6
|
+
Extracted from FlagGems (Apache 2.0).
|
|
7
|
+
|
|
8
|
+
Three kernels:
|
|
9
|
+
1. scan_part_min_kernel — local cummin within each block + partial min
|
|
10
|
+
2. add_base_min_kernel — fan-out: combine partial minima with local results
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import triton
|
|
14
|
+
import triton.language as tl
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@triton.jit
|
|
18
|
+
def _cummin_combine(val_a, idx_a, val_b, idx_b):
|
|
19
|
+
"""Associative combiner: keep (value, index) of the minimum."""
|
|
20
|
+
pick_b = val_b < val_a
|
|
21
|
+
# Tie-break right: if equal, keep the later (right) index
|
|
22
|
+
pick_b = pick_b | ((val_a == val_b) & (idx_b >= idx_a))
|
|
23
|
+
val_out = tl.where(pick_b, val_b, val_a)
|
|
24
|
+
idx_out = tl.where(pick_b, idx_b, idx_a)
|
|
25
|
+
return val_out, idx_out
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@triton.jit
|
|
29
|
+
def scan_part_min_kernel(
|
|
30
|
+
inp,
|
|
31
|
+
out,
|
|
32
|
+
out_indices,
|
|
33
|
+
partial_min,
|
|
34
|
+
partial_min_indices,
|
|
35
|
+
n_elements,
|
|
36
|
+
BLOCK_SIZE: tl.constexpr,
|
|
37
|
+
NEED_PARTIAL: tl.constexpr,
|
|
38
|
+
):
|
|
39
|
+
"""Block-local cumulative minimum with optional partial output.
|
|
40
|
+
|
|
41
|
+
Each block loads BLOCK_SIZE elements, computes cummin via associative
|
|
42
|
+
scan, stores results, and optionally writes the block-minimum for
|
|
43
|
+
the fan-out phase.
|
|
44
|
+
"""
|
|
45
|
+
pid = tl.program_id(0).to(tl.int64)
|
|
46
|
+
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)
|
|
47
|
+
mask = offset < n_elements
|
|
48
|
+
|
|
49
|
+
# Load input, use +inf for masked positions
|
|
50
|
+
inp_vals = tl.load(inp + offset, mask=mask, other=float('inf'))
|
|
51
|
+
inp_vals = inp_vals.to(tl.float32)
|
|
52
|
+
indices = offset
|
|
53
|
+
|
|
54
|
+
# Associative scan for cummin
|
|
55
|
+
result, cummin_idx = tl.associative_scan(
|
|
56
|
+
(inp_vals, indices), 0, _cummin_combine
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
tl.store(out + offset, result, mask=mask)
|
|
60
|
+
tl.store(out_indices + offset, cummin_idx, mask=mask)
|
|
61
|
+
|
|
62
|
+
if tl.constexpr(NEED_PARTIAL):
|
|
63
|
+
# Reduce to find block minimum (tie-break right)
|
|
64
|
+
block_min = tl.min(inp_vals, axis=0)
|
|
65
|
+
is_min = inp_vals == block_min
|
|
66
|
+
min_idx = tl.max(tl.where(is_min, indices, -1), axis=0)
|
|
67
|
+
if tl.arange(0, BLOCK_SIZE)[0] == 0:
|
|
68
|
+
tl.store(partial_min + pid, block_min)
|
|
69
|
+
tl.store(partial_min_indices + pid, min_idx)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@triton.jit
|
|
73
|
+
def add_base_min_kernel(
|
|
74
|
+
out,
|
|
75
|
+
out_indices,
|
|
76
|
+
partial_min,
|
|
77
|
+
partial_min_indices,
|
|
78
|
+
n_elements,
|
|
79
|
+
BLOCK_SIZE: tl.constexpr,
|
|
80
|
+
):
|
|
81
|
+
"""Fan-out phase: combine partial minima from prior blocks.
|
|
82
|
+
|
|
83
|
+
For each block (except the first), loads the cumulative partial min
|
|
84
|
+
from the previous block and merges with local results.
|
|
85
|
+
"""
|
|
86
|
+
pid = tl.program_id(0).to(tl.int64)
|
|
87
|
+
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)
|
|
88
|
+
mask = offset < n_elements
|
|
89
|
+
|
|
90
|
+
out_vals = tl.load(out + offset, mask=mask)
|
|
91
|
+
out_idx = tl.load(out_indices + offset, mask=mask)
|
|
92
|
+
|
|
93
|
+
if pid > 0:
|
|
94
|
+
prev_min = tl.load(partial_min + pid - 1)
|
|
95
|
+
prev_idx = tl.load(partial_min_indices + pid - 1)
|
|
96
|
+
|
|
97
|
+
# Merge: if previous partial min <= local, use previous
|
|
98
|
+
use_prev = (prev_min < out_vals) | (
|
|
99
|
+
(prev_min == out_vals) & (prev_idx >= out_idx)
|
|
100
|
+
)
|
|
101
|
+
final_vals = tl.where(use_prev, prev_min, out_vals)
|
|
102
|
+
final_idx = tl.where(use_prev, prev_idx, out_idx)
|
|
103
|
+
|
|
104
|
+
tl.store(out + offset, final_vals, mask=mask)
|
|
105
|
+
tl.store(out_indices + offset, final_idx, mask=mask)
|
nbxtensor/ops/cumsum.py
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"""Cumulative sum — pure @triton.jit kernels. Extracted from FlagGems.
|
|
2
|
+
|
|
3
|
+
Two-pass scan-then-fan approach for large 1D cumsum:
|
|
4
|
+
scan_part_sum_kernel: per-block prefix sum + partial sums
|
|
5
|
+
add_base_sum_kernel: propagate partial sums across blocks
|
|
6
|
+
|
|
7
|
+
Multi-dimensional (A,B,C) variants:
|
|
8
|
+
scan_part_sum_abc_kernel: per-block scan along B dim
|
|
9
|
+
add_base_sum_abc_kernel: propagate partial sums along B dim
|
|
10
|
+
|
|
11
|
+
Row-wise persistent kernels:
|
|
12
|
+
reduce_then_scan_block_sum_kernel_row: block sums for row scan
|
|
13
|
+
reduce_then_scan_root_scan_kernel_row: persistent root scan
|
|
14
|
+
reduce_then_scan_block_scan_kernel_row: final block scan with prefix
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import triton
|
|
18
|
+
import triton.language as tl
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@tl.constexpr
|
|
22
|
+
def get_scan_accum_type(inp_dtype: tl.dtype) -> tl.dtype:
|
|
23
|
+
if inp_dtype.is_bf16() or inp_dtype.is_fp16():
|
|
24
|
+
return tl.float32
|
|
25
|
+
if inp_dtype.is_int():
|
|
26
|
+
return tl.int64
|
|
27
|
+
else:
|
|
28
|
+
return inp_dtype
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# --- 1D scan-then-fan kernels ---
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@triton.jit(do_not_specialize=["n_elements", "part_num"])
|
|
35
|
+
def scan_part_sum_kernel(
|
|
36
|
+
inp,
|
|
37
|
+
out,
|
|
38
|
+
partial_sum,
|
|
39
|
+
n_elements,
|
|
40
|
+
part_num,
|
|
41
|
+
BLOCK_SIZE: tl.constexpr,
|
|
42
|
+
):
|
|
43
|
+
pid = tl.program_id(0).to(tl.int64)
|
|
44
|
+
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)
|
|
45
|
+
mask = offset < n_elements
|
|
46
|
+
|
|
47
|
+
inp_ptrs = inp + offset
|
|
48
|
+
inp_vals = tl.load(inp_ptrs, mask=mask)
|
|
49
|
+
if (
|
|
50
|
+
tl.constexpr(inp_vals.dtype.is_int64())
|
|
51
|
+
or tl.constexpr(inp_vals.dtype.is_uint64())
|
|
52
|
+
) or tl.constexpr(inp_vals.dtype.is_fp64()):
|
|
53
|
+
inp_vals = inp_vals
|
|
54
|
+
elif tl.constexpr(inp_vals.dtype.is_int()):
|
|
55
|
+
inp_vals = inp_vals.to(tl.int32)
|
|
56
|
+
else:
|
|
57
|
+
inp_vals = inp_vals.to(tl.float32)
|
|
58
|
+
result = tl.cumsum(inp_vals, axis=0)
|
|
59
|
+
|
|
60
|
+
part_sum_via_sum = tl.sum(inp_vals)
|
|
61
|
+
|
|
62
|
+
out_ptrs = out + offset
|
|
63
|
+
tl.store(out_ptrs, result, mask=mask)
|
|
64
|
+
|
|
65
|
+
partial_sum_ptrs = partial_sum + pid
|
|
66
|
+
tl.store(partial_sum_ptrs, part_sum_via_sum)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@triton.jit(do_not_specialize=["n_elements", "part_num"])
|
|
70
|
+
def add_base_sum_kernel(
|
|
71
|
+
out,
|
|
72
|
+
partial_sum,
|
|
73
|
+
n_elements,
|
|
74
|
+
part_num,
|
|
75
|
+
BLOCK_SIZE: tl.constexpr,
|
|
76
|
+
):
|
|
77
|
+
pid = tl.program_id(0).to(tl.int64)
|
|
78
|
+
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)
|
|
79
|
+
mask = offset < n_elements
|
|
80
|
+
|
|
81
|
+
out_ptrs = out + offset
|
|
82
|
+
out_vals = tl.load(out_ptrs, mask=mask)
|
|
83
|
+
|
|
84
|
+
if pid > 0:
|
|
85
|
+
partial_sum_ptrs = partial_sum + pid - 1
|
|
86
|
+
last_part_sum_via_sum = tl.load(partial_sum_ptrs)
|
|
87
|
+
|
|
88
|
+
final_vals = out_vals + last_part_sum_via_sum
|
|
89
|
+
tl.store(out_ptrs, final_vals.to(out_vals.dtype), mask=mask)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
# --- Multi-dim (A,B,C) kernels ---
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@triton.jit(do_not_specialize=["part_num"])
|
|
96
|
+
def scan_part_sum_abc_kernel(
|
|
97
|
+
inp,
|
|
98
|
+
out,
|
|
99
|
+
partial_sum,
|
|
100
|
+
B,
|
|
101
|
+
C,
|
|
102
|
+
part_num,
|
|
103
|
+
BLOCK_SIZE: tl.constexpr,
|
|
104
|
+
):
|
|
105
|
+
pid_a = tl.program_id(0).to(tl.int64)
|
|
106
|
+
pid_b = tl.program_id(1).to(tl.int64)
|
|
107
|
+
pid_c = tl.program_id(2).to(tl.int64)
|
|
108
|
+
|
|
109
|
+
a_idx = pid_a
|
|
110
|
+
b_idx = pid_b.to(tl.int64) * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE) # 64-bit from the program id (register 58)
|
|
111
|
+
c_idx = pid_c
|
|
112
|
+
|
|
113
|
+
offset = a_idx * B * C + b_idx * C + c_idx
|
|
114
|
+
base_part_offset = a_idx * part_num * C + c_idx
|
|
115
|
+
part_offset = base_part_offset + pid_b * C
|
|
116
|
+
|
|
117
|
+
mask = b_idx < B
|
|
118
|
+
inp_ptrs = inp + offset
|
|
119
|
+
inp_vals = tl.load(inp_ptrs, mask=mask)
|
|
120
|
+
if (
|
|
121
|
+
tl.constexpr(inp_vals.dtype.is_int64())
|
|
122
|
+
or tl.constexpr(inp_vals.dtype.is_uint64())
|
|
123
|
+
) or tl.constexpr(inp_vals.dtype.is_fp64()):
|
|
124
|
+
inp_vals = inp_vals
|
|
125
|
+
elif tl.constexpr(inp_vals.dtype.is_int()):
|
|
126
|
+
inp_vals = inp_vals.to(tl.int32)
|
|
127
|
+
else:
|
|
128
|
+
inp_vals = inp_vals.to(tl.float32)
|
|
129
|
+
result = tl.cumsum(inp_vals, axis=0)
|
|
130
|
+
|
|
131
|
+
part_sum_via_sum = tl.sum(inp_vals)
|
|
132
|
+
|
|
133
|
+
out_ptrs = out + offset
|
|
134
|
+
tl.store(out_ptrs, result, mask=mask)
|
|
135
|
+
|
|
136
|
+
partial_sum_ptrs = partial_sum + part_offset
|
|
137
|
+
tl.store(partial_sum_ptrs, part_sum_via_sum)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
@triton.jit(do_not_specialize=["part_num"])
|
|
141
|
+
def add_base_sum_abc_kernel(
|
|
142
|
+
out,
|
|
143
|
+
partial_sum,
|
|
144
|
+
B,
|
|
145
|
+
C,
|
|
146
|
+
part_num,
|
|
147
|
+
BLOCK_SIZE: tl.constexpr,
|
|
148
|
+
):
|
|
149
|
+
pid_a = tl.program_id(0).to(tl.int64)
|
|
150
|
+
pid_b = tl.program_id(1).to(tl.int64)
|
|
151
|
+
pid_c = tl.program_id(2).to(tl.int64)
|
|
152
|
+
|
|
153
|
+
a_idx = pid_a
|
|
154
|
+
b_idx = pid_b.to(tl.int64) * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE) # 64-bit from the program id (register 58)
|
|
155
|
+
c_idx = pid_c
|
|
156
|
+
|
|
157
|
+
base_offset = a_idx * B * C + c_idx
|
|
158
|
+
offset = base_offset + b_idx * C
|
|
159
|
+
base_part_offset = a_idx * part_num * C + c_idx
|
|
160
|
+
last_part_offset = base_part_offset + (pid_b - 1) * C
|
|
161
|
+
|
|
162
|
+
mask = b_idx < B
|
|
163
|
+
out_ptrs = out + offset
|
|
164
|
+
out_vals = tl.load(out_ptrs, mask=mask)
|
|
165
|
+
|
|
166
|
+
if pid_b > 0:
|
|
167
|
+
partial_sum_ptrs = partial_sum + last_part_offset
|
|
168
|
+
last_part_sum_via_sum = tl.load(partial_sum_ptrs)
|
|
169
|
+
|
|
170
|
+
final_vals = out_vals + last_part_sum_via_sum
|
|
171
|
+
tl.store(out_ptrs, final_vals.to(out_vals.dtype), mask=mask)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
# --- Row-wise persistent scan kernels ---
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
@triton.jit
|
|
178
|
+
def reduce_then_scan_block_sum_kernel_row(
|
|
179
|
+
in_ptr,
|
|
180
|
+
block_sum_ptr,
|
|
181
|
+
N,
|
|
182
|
+
tiles_per_cta,
|
|
183
|
+
TILE_SIZE: tl.constexpr,
|
|
184
|
+
):
|
|
185
|
+
"""Block sum: each CTA reduces its assigned tiles into a single sum."""
|
|
186
|
+
pid_n = tl.program_id(1).to(tl.int64)
|
|
187
|
+
pid_m = tl.program_id(0).to(tl.int64)
|
|
188
|
+
num_programs_n = tl.num_programs(1)
|
|
189
|
+
block_offset = (pid_n * (tiles_per_cta * TILE_SIZE)).to(tl.int32) # loop bounds are 32-bit counts: the Metal lowering refuses a 64-bit scf.for bound (addressing stays 64-bit through the program ids)
|
|
190
|
+
block_end = min(block_offset + tiles_per_cta * TILE_SIZE, N).to(tl.int32)
|
|
191
|
+
|
|
192
|
+
acc_dtype: tl.constexpr = get_scan_accum_type(in_ptr.type.element_ty)
|
|
193
|
+
acc = tl.zeros((TILE_SIZE,), dtype=acc_dtype)
|
|
194
|
+
for start in range(block_offset, block_end, TILE_SIZE):
|
|
195
|
+
offsets = start + tl.arange(0, TILE_SIZE)
|
|
196
|
+
x = tl.load(in_ptr + pid_m * N + offsets, mask=offsets < N).to(acc_dtype)
|
|
197
|
+
acc += x
|
|
198
|
+
block_sum = tl.sum(acc, 0)
|
|
199
|
+
tl.store(
|
|
200
|
+
block_sum_ptr + pid_m * num_programs_n + pid_n, block_sum, cache_modifier=".cg"
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
@triton.jit
|
|
205
|
+
def reduce_then_scan_root_scan_kernel_row(in_ptr, out_ptr, N, TILE_SIZE: tl.constexpr):
|
|
206
|
+
"""Persistent scan of block sums (or small row)."""
|
|
207
|
+
pid = tl.program_id(0).to(tl.int64)
|
|
208
|
+
offsets = tl.arange(0, TILE_SIZE)
|
|
209
|
+
mask = offsets < N
|
|
210
|
+
acc_dtype: tl.constexpr = get_scan_accum_type(in_ptr.type.element_ty)
|
|
211
|
+
x = tl.load(in_ptr + pid * N + offsets, mask=mask, other=0).to(acc_dtype)
|
|
212
|
+
out = tl.cumsum(x, 0)
|
|
213
|
+
tl.store(out_ptr + pid * N + offsets, out, mask=mask)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
@triton.jit
|
|
217
|
+
def reduce_then_scan_block_scan_kernel_row(
|
|
218
|
+
in_ptr,
|
|
219
|
+
previous_sum_ptr,
|
|
220
|
+
out_ptr,
|
|
221
|
+
N,
|
|
222
|
+
num_tiles_n,
|
|
223
|
+
tiles_per_cta,
|
|
224
|
+
TILE_SIZE: tl.constexpr,
|
|
225
|
+
):
|
|
226
|
+
"""Final block scan: apply prefix from previous blocks, then local cumsum."""
|
|
227
|
+
pid_m = tl.program_id(0).to(tl.int64)
|
|
228
|
+
pid_n = tl.program_id(1).to(tl.int64)
|
|
229
|
+
block_offset = (pid_n * (tiles_per_cta * TILE_SIZE)).to(tl.int32) # loop bounds are 32-bit counts: the Metal lowering refuses a 64-bit scf.for bound (addressing stays 64-bit through the program ids)
|
|
230
|
+
block_end = min(block_offset + tiles_per_cta * TILE_SIZE, N).to(tl.int32)
|
|
231
|
+
acc_dtype: tl.constexpr = get_scan_accum_type(in_ptr.type.element_ty)
|
|
232
|
+
|
|
233
|
+
prefix = tl.load(
|
|
234
|
+
previous_sum_ptr + pid_m * num_tiles_n + pid_n - 1, mask=pid_n > 0, other=0
|
|
235
|
+
).to(acc_dtype)
|
|
236
|
+
for start in range(block_offset, block_end, TILE_SIZE):
|
|
237
|
+
offsets = start + tl.arange(0, TILE_SIZE)
|
|
238
|
+
mask = offsets < N
|
|
239
|
+
x = tl.load(in_ptr + pid_m * N + offsets, mask=mask).to(acc_dtype)
|
|
240
|
+
tile_scan = prefix + tl.cumsum(x, 0)
|
|
241
|
+
prefix += tl.sum(x, 0)
|
|
242
|
+
tl.store(
|
|
243
|
+
out_ptr + pid_m * N + offsets, tile_scan, mask=mask, cache_modifier=".cg"
|
|
244
|
+
)
|