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
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""Trace — pure @triton.jit kernel.
|
|
2
|
+
|
|
3
|
+
Sum of diagonal elements of a 2D matrix.
|
|
4
|
+
Single program iterates over the diagonal in blocks, accumulating in
|
|
5
|
+
float32 (or int64 for integer types) for numerical stability.
|
|
6
|
+
|
|
7
|
+
Extracted from FlagGems (Apache 2.0).
|
|
8
|
+
|
|
9
|
+
Grid: (1,)
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import triton
|
|
13
|
+
import triton.language as tl
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@triton.jit
|
|
17
|
+
def trace_kernel(
|
|
18
|
+
inp_ptr,
|
|
19
|
+
out_ptr,
|
|
20
|
+
num_diag,
|
|
21
|
+
stride0,
|
|
22
|
+
stride1,
|
|
23
|
+
BLOCK_SIZE: tl.constexpr,
|
|
24
|
+
):
|
|
25
|
+
"""Sum diagonal elements of a 2D matrix.
|
|
26
|
+
|
|
27
|
+
Iterates over the diagonal in blocks of BLOCK_SIZE, accumulating
|
|
28
|
+
partial sums. The diagonal stride is stride0 + stride1 (step to
|
|
29
|
+
move from (i,i) to (i+1,i+1)).
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
inp_ptr: input 2D matrix pointer
|
|
33
|
+
out_ptr: scalar output pointer
|
|
34
|
+
num_diag: min(M, N) — number of diagonal elements
|
|
35
|
+
stride0: row stride of input
|
|
36
|
+
stride1: column stride of input
|
|
37
|
+
"""
|
|
38
|
+
# Select accumulation dtype based on input type
|
|
39
|
+
inp_dtype = inp_ptr.type.element_ty
|
|
40
|
+
if inp_dtype.is_int():
|
|
41
|
+
acc_dtype = tl.int64
|
|
42
|
+
other_val = 0
|
|
43
|
+
elif inp_dtype == tl.float64:
|
|
44
|
+
acc_dtype = tl.float64
|
|
45
|
+
other_val = 0.0
|
|
46
|
+
else:
|
|
47
|
+
acc_dtype = tl.float32
|
|
48
|
+
other_val = 0.0
|
|
49
|
+
|
|
50
|
+
acc = tl.zeros((BLOCK_SIZE,), dtype=acc_dtype)
|
|
51
|
+
|
|
52
|
+
diag_stride = stride0 + stride1
|
|
53
|
+
|
|
54
|
+
for i in range(0, tl.cdiv(num_diag, BLOCK_SIZE)):
|
|
55
|
+
block_start = i * BLOCK_SIZE
|
|
56
|
+
current_indices = block_start + tl.arange(0, BLOCK_SIZE)
|
|
57
|
+
mask = current_indices < num_diag
|
|
58
|
+
|
|
59
|
+
ptr_offsets = current_indices * diag_stride
|
|
60
|
+
vals = tl.load(inp_ptr + ptr_offsets, mask=mask, other=other_val)
|
|
61
|
+
acc += vals.to(acc_dtype)
|
|
62
|
+
|
|
63
|
+
final_sum = tl.sum(acc, axis=0)
|
|
64
|
+
tl.store(out_ptr, final_sum.to(out_ptr.type.element_ty))
|
nbxtensor/ops/tril.py
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""Lower triangular — pure @triton.jit kernels. Adapted from FlagGems triu.
|
|
2
|
+
|
|
3
|
+
tril_kernel: 2D version, iterates over N blocks per row.
|
|
4
|
+
tril_batch_kernel: batched version, handles N-D tensors flattened to (batch, M*N).
|
|
5
|
+
|
|
6
|
+
The only difference from triu: condition is >= (keep below diagonal) vs <= (keep above).
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import triton
|
|
10
|
+
import triton.language as tl
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@triton.jit(do_not_specialize=["diagonal"])
|
|
14
|
+
def tril_kernel(
|
|
15
|
+
X,
|
|
16
|
+
Y,
|
|
17
|
+
M,
|
|
18
|
+
N,
|
|
19
|
+
diagonal,
|
|
20
|
+
M_BLOCK_SIZE: tl.constexpr,
|
|
21
|
+
N_BLOCK_SIZE: tl.constexpr,
|
|
22
|
+
):
|
|
23
|
+
pid = tl.program_id(0).to(tl.int64)
|
|
24
|
+
row = pid * M_BLOCK_SIZE + tl.arange(0, M_BLOCK_SIZE)[:, None]
|
|
25
|
+
m_mask = row < M
|
|
26
|
+
X += row * N
|
|
27
|
+
Y += row * N
|
|
28
|
+
|
|
29
|
+
for n_offset in range(0, N, N_BLOCK_SIZE):
|
|
30
|
+
cols = n_offset + tl.arange(0, N_BLOCK_SIZE)[None, :]
|
|
31
|
+
n_mask = cols < N
|
|
32
|
+
mask = m_mask & n_mask
|
|
33
|
+
|
|
34
|
+
x = tl.load(X + cols, mask, other=0.0)
|
|
35
|
+
y = tl.where(row + diagonal >= cols, x, 0.0)
|
|
36
|
+
tl.store(Y + cols, y, mask=mask)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@triton.jit(do_not_specialize=["diagonal"])
|
|
40
|
+
def tril_batch_kernel(
|
|
41
|
+
X,
|
|
42
|
+
Y,
|
|
43
|
+
batch,
|
|
44
|
+
MN,
|
|
45
|
+
N,
|
|
46
|
+
diagonal,
|
|
47
|
+
BATCH_BLOCK_SIZE: tl.constexpr,
|
|
48
|
+
MN_BLOCK_SIZE: tl.constexpr,
|
|
49
|
+
):
|
|
50
|
+
batch_id = tl.program_id(0).to(tl.int64)
|
|
51
|
+
mn_id = tl.program_id(1).to(tl.int64)
|
|
52
|
+
row = batch_id * BATCH_BLOCK_SIZE + tl.arange(0, BATCH_BLOCK_SIZE)[:, None]
|
|
53
|
+
batch_mask = row < batch
|
|
54
|
+
X += row * MN
|
|
55
|
+
Y += row * MN
|
|
56
|
+
|
|
57
|
+
cols = mn_id * MN_BLOCK_SIZE + tl.arange(0, MN_BLOCK_SIZE)[None, :]
|
|
58
|
+
mn_mask = cols < MN
|
|
59
|
+
mask = batch_mask & mn_mask
|
|
60
|
+
x = tl.load(X + cols, mask, other=0.0)
|
|
61
|
+
m = cols // N
|
|
62
|
+
n = cols % N
|
|
63
|
+
y = tl.where(m + diagonal >= n, x, 0.0)
|
|
64
|
+
tl.store(Y + cols, y, mask=mask)
|
nbxtensor/ops/triu.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Upper triangular — pure @triton.jit kernels. Extracted from FlagGems.
|
|
2
|
+
|
|
3
|
+
triu_kernel: 2D version, iterates over N blocks per row.
|
|
4
|
+
triu_batch_kernel: batched version, handles N-D tensors flattened to (batch, M*N).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import triton
|
|
8
|
+
import triton.language as tl
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@triton.jit(do_not_specialize=["diagonal"])
|
|
12
|
+
def triu_kernel(
|
|
13
|
+
X,
|
|
14
|
+
Y,
|
|
15
|
+
M,
|
|
16
|
+
N,
|
|
17
|
+
diagonal,
|
|
18
|
+
M_BLOCK_SIZE: tl.constexpr,
|
|
19
|
+
N_BLOCK_SIZE: tl.constexpr,
|
|
20
|
+
):
|
|
21
|
+
pid = tl.program_id(0).to(tl.int64)
|
|
22
|
+
row = pid * M_BLOCK_SIZE + tl.arange(0, M_BLOCK_SIZE)[:, None]
|
|
23
|
+
m_mask = row < M
|
|
24
|
+
X += row * N
|
|
25
|
+
Y += row * N
|
|
26
|
+
|
|
27
|
+
for n_offset in range(0, N, N_BLOCK_SIZE):
|
|
28
|
+
cols = n_offset + tl.arange(0, N_BLOCK_SIZE)[None, :]
|
|
29
|
+
n_mask = cols < N
|
|
30
|
+
mask = m_mask & n_mask
|
|
31
|
+
|
|
32
|
+
x = tl.load(X + cols, mask, other=0.0)
|
|
33
|
+
y = tl.where(row + diagonal <= cols, x, 0.0)
|
|
34
|
+
tl.store(Y + cols, y, mask=mask)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@triton.jit(do_not_specialize=["diagonal"])
|
|
38
|
+
def triu_batch_kernel(
|
|
39
|
+
X,
|
|
40
|
+
Y,
|
|
41
|
+
batch,
|
|
42
|
+
MN,
|
|
43
|
+
N,
|
|
44
|
+
diagonal,
|
|
45
|
+
BATCH_BLOCK_SIZE: tl.constexpr,
|
|
46
|
+
MN_BLOCK_SIZE: tl.constexpr,
|
|
47
|
+
):
|
|
48
|
+
batch_id = tl.program_id(0).to(tl.int64)
|
|
49
|
+
mn_id = tl.program_id(1).to(tl.int64)
|
|
50
|
+
row = batch_id * BATCH_BLOCK_SIZE + tl.arange(0, BATCH_BLOCK_SIZE)[:, None]
|
|
51
|
+
batch_mask = row < batch
|
|
52
|
+
X += row * MN
|
|
53
|
+
Y += row * MN
|
|
54
|
+
|
|
55
|
+
cols = mn_id * MN_BLOCK_SIZE + tl.arange(0, MN_BLOCK_SIZE)[None, :]
|
|
56
|
+
mn_mask = cols < MN
|
|
57
|
+
mask = batch_mask & mn_mask
|
|
58
|
+
x = tl.load(X + cols, mask, other=0.0)
|
|
59
|
+
m = cols // N
|
|
60
|
+
n = cols % N
|
|
61
|
+
y = tl.where(m + diagonal <= n, x, 0.0)
|
|
62
|
+
tl.store(Y + cols, y, mask=mask)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""unfold_backward (overlap-add) — pure @triton.jit kernel.
|
|
2
|
+
|
|
3
|
+
aten::unfold_backward is the gradient of `Tensor.unfold`: it scatter-adds the
|
|
4
|
+
unfolded frames back into the original signal, so overlapping positions are
|
|
5
|
+
summed. This is exactly the iSTFT overlap-add (frames [.., N_frames, size] with
|
|
6
|
+
hop `step` → signal [.., L]).
|
|
7
|
+
|
|
8
|
+
For output position i: out[i] = Σ_{f} grad[f, j] where j = i - f*step and
|
|
9
|
+
0 <= j < size. The covering frames are f = i//step - fo for a small fo range
|
|
10
|
+
(~size/step frames overlap a given position).
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import triton
|
|
14
|
+
import triton.language as tl
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@triton.jit
|
|
18
|
+
def unfold_backward_1d_kernel(
|
|
19
|
+
grad_ptr, # (B, N_frames, size) contiguous
|
|
20
|
+
out_ptr, # (B, L) contiguous
|
|
21
|
+
N_frames, size, step, L,
|
|
22
|
+
MAX_OVERLAP: tl.constexpr,
|
|
23
|
+
BLOCK_SIZE: tl.constexpr,
|
|
24
|
+
):
|
|
25
|
+
pid_b = tl.program_id(0).to(tl.int64)
|
|
26
|
+
pid_l = tl.program_id(1).to(tl.int64)
|
|
27
|
+
offs = pid_l.to(tl.int64) * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE) # 64-bit from the program id (register 58)
|
|
28
|
+
mask = offs < L
|
|
29
|
+
acc = tl.zeros((BLOCK_SIZE,), dtype=tl.float32)
|
|
30
|
+
base = pid_b * (N_frames * size)
|
|
31
|
+
for fo in range(MAX_OVERLAP):
|
|
32
|
+
f = (offs // step) - fo
|
|
33
|
+
j = offs - f * step
|
|
34
|
+
valid = (f >= 0) & (f < N_frames) & (j >= 0) & (j < size) & mask
|
|
35
|
+
val = tl.load(grad_ptr + base + f * size + j, mask=valid, other=0.0)
|
|
36
|
+
acc += tl.where(valid, val, 0.0)
|
|
37
|
+
tl.store(out_ptr + pid_b * L + offs, acc, mask=mask)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""Unique — pure @triton.jit kernels.
|
|
2
|
+
|
|
3
|
+
NOTE: The full unique implementation (FlagGems) requires a multi-phase
|
|
4
|
+
pipeline (sort -> local-ne -> cumsum -> scatter -> fan-out) orchestrated
|
|
5
|
+
by Python wrapper code that allocates intermediate buffers and chains
|
|
6
|
+
multiple kernel launches. The core algorithmic kernels are extracted below.
|
|
7
|
+
|
|
8
|
+
These kernels assume the input is PRE-SORTED. The Python wrapper must:
|
|
9
|
+
1. Sort the input: sorted_data, sorted_indices = sort(input.ravel())
|
|
10
|
+
2. Launch simple_unique_flat_kernel (for small inputs) or the
|
|
11
|
+
local_ne -> global_cumsum pipeline (for large inputs)
|
|
12
|
+
3. Slice the output to [:unique_size]
|
|
13
|
+
|
|
14
|
+
Extracted from FlagGems (Apache 2.0).
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import triton
|
|
18
|
+
import triton.language as tl
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@triton.jit
|
|
22
|
+
def simple_unique_flat_kernel(
|
|
23
|
+
sorted_data_ptr,
|
|
24
|
+
sorted_indices_ptr,
|
|
25
|
+
data_out_ptr,
|
|
26
|
+
inverse_indices_ptr,
|
|
27
|
+
idx_ptr,
|
|
28
|
+
unique_size_ptr,
|
|
29
|
+
return_inverse: tl.constexpr,
|
|
30
|
+
return_counts: tl.constexpr,
|
|
31
|
+
num_tasks,
|
|
32
|
+
tile_size: tl.constexpr,
|
|
33
|
+
):
|
|
34
|
+
"""Single-block unique on pre-sorted data (for small inputs <= 8192).
|
|
35
|
+
|
|
36
|
+
Compares each element with its predecessor to detect boundaries,
|
|
37
|
+
uses cumsum for compacted output indices, then scatters unique values.
|
|
38
|
+
|
|
39
|
+
Grid: (1,)
|
|
40
|
+
"""
|
|
41
|
+
i0 = tl.arange(0, tile_size)
|
|
42
|
+
mask = i0 < num_tasks
|
|
43
|
+
|
|
44
|
+
# Load current and previous elements
|
|
45
|
+
a = tl.load(sorted_data_ptr + i0, mask=mask)
|
|
46
|
+
i0_prev = tl.where(i0 > 0, i0 - 1, 0)
|
|
47
|
+
b = tl.load(sorted_data_ptr + i0_prev, mask=mask)
|
|
48
|
+
|
|
49
|
+
# Detect unique boundaries: ne(a, prev(a)), first element always unique
|
|
50
|
+
ne_result = tl.where(i0 > 0, a != b, 0)
|
|
51
|
+
cumsum = tl.cumsum(ne_result)
|
|
52
|
+
|
|
53
|
+
# Write unique_size (last element's cumsum = num_unique - 1)
|
|
54
|
+
unique_size_mask = i0 == tile_size - 1
|
|
55
|
+
tl.store(unique_size_ptr + tl.zeros_like(i0), cumsum, mask=unique_size_mask)
|
|
56
|
+
|
|
57
|
+
# Scatter unique values to compacted output
|
|
58
|
+
tl.store(data_out_ptr + cumsum, a, mask=mask)
|
|
59
|
+
|
|
60
|
+
# Scatter inverse indices: original position -> compacted index
|
|
61
|
+
if return_inverse:
|
|
62
|
+
sorted_indices = tl.load(sorted_indices_ptr + i0, mask=mask)
|
|
63
|
+
tl.store(inverse_indices_ptr + sorted_indices, cumsum, mask=mask)
|
|
64
|
+
|
|
65
|
+
# Record boundary positions for count computation
|
|
66
|
+
if return_counts:
|
|
67
|
+
idx_mask = ((i0 == 0) | ne_result.to(tl.int1)) & mask
|
|
68
|
+
tl.store(idx_ptr + cumsum, i0, mask=idx_mask)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@triton.jit
|
|
72
|
+
def output_counts_kernel(
|
|
73
|
+
idx_ptr,
|
|
74
|
+
origin_num_tasks,
|
|
75
|
+
counts_ptr,
|
|
76
|
+
num_tasks,
|
|
77
|
+
tile_size: tl.constexpr,
|
|
78
|
+
):
|
|
79
|
+
"""Compute counts from boundary indices.
|
|
80
|
+
|
|
81
|
+
counts[i] = idx[i+1] - idx[i], with the last count going to the end.
|
|
82
|
+
|
|
83
|
+
Grid: (ceil(num_unique / tile_size),)
|
|
84
|
+
"""
|
|
85
|
+
pid = tl.program_id(0).to(tl.int64)
|
|
86
|
+
r = tl.arange(0, tile_size)
|
|
87
|
+
i0 = pid * tile_size + r
|
|
88
|
+
mask = i0 < num_tasks
|
|
89
|
+
|
|
90
|
+
idx = tl.load(idx_ptr + i0, mask=mask)
|
|
91
|
+
|
|
92
|
+
i0_next = i0 + 1
|
|
93
|
+
next_mask = i0_next < num_tasks
|
|
94
|
+
idx_next = tl.load(idx_ptr + i0_next, mask=next_mask)
|
|
95
|
+
|
|
96
|
+
counts = tl.where(i0_next < num_tasks, idx_next - idx, origin_num_tasks - idx)
|
|
97
|
+
tl.store(counts_ptr + i0, counts, mask=mask)
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""Bilinear 2D upsampling — pure @triton.jit kernel.
|
|
2
|
+
|
|
3
|
+
For each output pixel (n, c, oh, ow), compute source coordinates in
|
|
4
|
+
input space, find the 4 nearest input pixels, and bilinearly interpolate.
|
|
5
|
+
|
|
6
|
+
Supports align_corners=True (maps corner-to-corner) and align_corners=False
|
|
7
|
+
(maps center-to-center with half-pixel offset).
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import triton
|
|
11
|
+
import triton.language as tl
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@triton.jit
|
|
15
|
+
def upsample_bilinear2d_kernel(
|
|
16
|
+
input_ptr,
|
|
17
|
+
output_ptr,
|
|
18
|
+
N, C,
|
|
19
|
+
IH, IW,
|
|
20
|
+
OH, OW,
|
|
21
|
+
# Precomputed scale factors: how input coords map to output coords
|
|
22
|
+
# For align_corners=False: scale_h = IH / OH, scale_w = IW / OW
|
|
23
|
+
# For align_corners=True: scale_h = (IH-1)/(OH-1), scale_w = (IW-1)/(OW-1)
|
|
24
|
+
scale_h,
|
|
25
|
+
scale_w,
|
|
26
|
+
# 0.0 for align_corners=True, 0.5 for align_corners=False
|
|
27
|
+
offset,
|
|
28
|
+
BLOCK_X: tl.constexpr,
|
|
29
|
+
BLOCK_Y: tl.constexpr,
|
|
30
|
+
):
|
|
31
|
+
"""Bilinear interpolation upsampling.
|
|
32
|
+
|
|
33
|
+
Grid: (cdiv(OW, BLOCK_X), cdiv(OH, BLOCK_Y), N*C)
|
|
34
|
+
Each program handles a BLOCK_Y x BLOCK_X tile of output pixels for one (n, c).
|
|
35
|
+
"""
|
|
36
|
+
pid_x = tl.program_id(0).to(tl.int64)
|
|
37
|
+
pid_y = tl.program_id(1).to(tl.int64)
|
|
38
|
+
pid_nc = tl.program_id(2).to(tl.int64)
|
|
39
|
+
|
|
40
|
+
ow = pid_x * BLOCK_X + tl.arange(0, BLOCK_X) # [BLOCK_X]
|
|
41
|
+
oh = pid_y * BLOCK_Y + tl.arange(0, BLOCK_Y) # [BLOCK_Y]
|
|
42
|
+
|
|
43
|
+
# Map output coords to input coords (floating point)
|
|
44
|
+
# align_corners=False: src = (dst + 0.5) * scale - 0.5
|
|
45
|
+
# align_corners=True: src = dst * scale
|
|
46
|
+
src_h = (oh.to(tl.float32) + offset) * scale_h - offset # [BLOCK_Y]
|
|
47
|
+
src_w = (ow.to(tl.float32) + offset) * scale_w - offset # [BLOCK_X]
|
|
48
|
+
|
|
49
|
+
# Clamp to valid range
|
|
50
|
+
src_h = tl.maximum(src_h, 0.0)
|
|
51
|
+
src_w = tl.maximum(src_w, 0.0)
|
|
52
|
+
# IH/IW may arrive as a Python int (Triton-specialized) or a tl scalar
|
|
53
|
+
# depending on the call's shape — `.to()` fails on the former, float() on the
|
|
54
|
+
# latter. `* 1.0` promotes to float robustly for both.
|
|
55
|
+
src_h = tl.minimum(src_h, (IH - 1) * 1.0)
|
|
56
|
+
src_w = tl.minimum(src_w, (IW - 1) * 1.0)
|
|
57
|
+
|
|
58
|
+
# Floor and ceil indices
|
|
59
|
+
h0 = src_h.to(tl.int32) # [BLOCK_Y]
|
|
60
|
+
w0 = src_w.to(tl.int32) # [BLOCK_X]
|
|
61
|
+
h1 = tl.minimum(h0 + 1, IH - 1) # [BLOCK_Y]
|
|
62
|
+
w1 = tl.minimum(w0 + 1, IW - 1) # [BLOCK_X]
|
|
63
|
+
|
|
64
|
+
# Fractional parts (bilinear weights)
|
|
65
|
+
fh = src_h - h0.to(tl.float32) # [BLOCK_Y]
|
|
66
|
+
fw = src_w - w0.to(tl.float32) # [BLOCK_X]
|
|
67
|
+
|
|
68
|
+
# Bilinear weights for 4 corners
|
|
69
|
+
w_h0 = 1.0 - fh # [BLOCK_Y]
|
|
70
|
+
w_h1 = fh # [BLOCK_Y]
|
|
71
|
+
w_w0 = 1.0 - fw # [BLOCK_X]
|
|
72
|
+
w_w1 = fw # [BLOCK_X]
|
|
73
|
+
|
|
74
|
+
# Base offset for this (n, c) plane
|
|
75
|
+
base = pid_nc * IH * IW
|
|
76
|
+
|
|
77
|
+
# Masks
|
|
78
|
+
mask_h = oh < OH # [BLOCK_Y]
|
|
79
|
+
mask_w = ow < OW # [BLOCK_X]
|
|
80
|
+
mask_2d = mask_h[:, None] & mask_w[None, :] # [BLOCK_Y, BLOCK_X]
|
|
81
|
+
|
|
82
|
+
# Load 4 corner values
|
|
83
|
+
# top-left: input[n, c, h0, w0]
|
|
84
|
+
# top-right: input[n, c, h0, w1]
|
|
85
|
+
# bottom-left: input[n, c, h1, w0]
|
|
86
|
+
# bottom-right: input[n, c, h1, w1]
|
|
87
|
+
off_tl = base + h0[:, None] * IW + w0[None, :]
|
|
88
|
+
off_tr = base + h0[:, None] * IW + w1[None, :]
|
|
89
|
+
off_bl = base + h1[:, None] * IW + w0[None, :]
|
|
90
|
+
off_br = base + h1[:, None] * IW + w1[None, :]
|
|
91
|
+
|
|
92
|
+
v_tl = tl.load(input_ptr + off_tl, mask=mask_2d, other=0.0).to(tl.float32)
|
|
93
|
+
v_tr = tl.load(input_ptr + off_tr, mask=mask_2d, other=0.0).to(tl.float32)
|
|
94
|
+
v_bl = tl.load(input_ptr + off_bl, mask=mask_2d, other=0.0).to(tl.float32)
|
|
95
|
+
v_br = tl.load(input_ptr + off_br, mask=mask_2d, other=0.0).to(tl.float32)
|
|
96
|
+
|
|
97
|
+
# Bilinear interpolation
|
|
98
|
+
# result = w_h0 * (w_w0 * v_tl + w_w1 * v_tr) + w_h1 * (w_w0 * v_bl + w_w1 * v_br)
|
|
99
|
+
top = w_w0[None, :] * v_tl + w_w1[None, :] * v_tr
|
|
100
|
+
bot = w_w0[None, :] * v_bl + w_w1[None, :] * v_br
|
|
101
|
+
result = w_h0[:, None] * top + w_h1[:, None] * bot
|
|
102
|
+
|
|
103
|
+
# Store output
|
|
104
|
+
out_base = pid_nc * OH * OW
|
|
105
|
+
out_off = out_base + oh[:, None] * OW + ow[None, :]
|
|
106
|
+
tl.store(output_ptr + out_off, result, mask=mask_2d)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Upsample nearest 2D — pure @triton.jit kernel.
|
|
2
|
+
|
|
3
|
+
Extracted from FlagGems (FlagOpen/FlagGems) upsample_nearest2d.py.
|
|
4
|
+
Stripped FlagGems-specific decorators (@libentry, runtime heuristics).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import triton
|
|
8
|
+
import triton.language as tl
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@triton.jit
|
|
12
|
+
def upsample_nearest2d_kernel(
|
|
13
|
+
ptr_o,
|
|
14
|
+
ptr_i,
|
|
15
|
+
N,
|
|
16
|
+
C,
|
|
17
|
+
OH,
|
|
18
|
+
OW,
|
|
19
|
+
IH,
|
|
20
|
+
IW,
|
|
21
|
+
s_n,
|
|
22
|
+
s_c,
|
|
23
|
+
s_h,
|
|
24
|
+
s_w,
|
|
25
|
+
reciprocal_scale_h,
|
|
26
|
+
reciprocal_scale_w,
|
|
27
|
+
BLOCK_SIZE: tl.constexpr,
|
|
28
|
+
):
|
|
29
|
+
NC = N * C
|
|
30
|
+
nc_stride = tl.num_programs(axis=1)
|
|
31
|
+
nc_iter = (tl.program_id(axis=1).to(tl.int64)).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)
|
|
32
|
+
pid = tl.program_id(axis=0).to(tl.int64)
|
|
33
|
+
idx = 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)
|
|
34
|
+
ow = idx % OW
|
|
35
|
+
oh = idx // OW % OH
|
|
36
|
+
|
|
37
|
+
ih = tl.minimum((oh * reciprocal_scale_h).to(tl.int32), IH - 1)
|
|
38
|
+
iw = tl.minimum((ow * reciprocal_scale_w).to(tl.int32), IW - 1)
|
|
39
|
+
|
|
40
|
+
# The input is read through its strides: a first-frame branch feeds this op `x[:, :, 0]` of a
|
|
41
|
+
# 5-D activation, a view whose channel stride spans every frame — flat indexing read another
|
|
42
|
+
# channel's frames there (CogVideoX / Open-Sora frame 0). The output is fresh and contiguous.
|
|
43
|
+
offset_o = (nc_iter * OH + oh) * OW + ow
|
|
44
|
+
in_hw = ih.to(tl.int64) * s_h + iw.to(tl.int64) * s_w
|
|
45
|
+
dst_index_stride = nc_stride * OH * OW
|
|
46
|
+
while nc_iter < NC:
|
|
47
|
+
n = nc_iter // C
|
|
48
|
+
c = nc_iter % C
|
|
49
|
+
data = tl.load(ptr_i + n.to(tl.int64) * s_n + c.to(tl.int64) * s_c + in_hw)
|
|
50
|
+
tl.store(ptr_o + offset_o, data)
|
|
51
|
+
ptr_o += dst_index_stride
|
|
52
|
+
nc_iter += nc_stride
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Upsample nearest 3D — pure @triton.jit kernel.
|
|
2
|
+
|
|
3
|
+
3D nearest neighbor upsampling: [N,C,D,H,W] -> [N,C,D*s_d,H*s_h,W*s_w].
|
|
4
|
+
Adapted from our upsample_nearest2d.py by adding the depth dimension.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import triton
|
|
8
|
+
import triton.language as tl
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@triton.jit
|
|
12
|
+
def upsample_nearest3d_kernel(
|
|
13
|
+
ptr_o,
|
|
14
|
+
ptr_i,
|
|
15
|
+
N,
|
|
16
|
+
C,
|
|
17
|
+
OD,
|
|
18
|
+
OH,
|
|
19
|
+
OW,
|
|
20
|
+
ID,
|
|
21
|
+
IH,
|
|
22
|
+
IW,
|
|
23
|
+
reciprocal_scale_d,
|
|
24
|
+
reciprocal_scale_h,
|
|
25
|
+
reciprocal_scale_w,
|
|
26
|
+
BLOCK_SIZE: tl.constexpr,
|
|
27
|
+
):
|
|
28
|
+
"""Nearest-neighbor 3D upsample.
|
|
29
|
+
|
|
30
|
+
Grid: (cdiv(OD*OH*OW, BLOCK_SIZE), cdiv(N*C, 4))
|
|
31
|
+
Each program handles BLOCK_SIZE output pixels across one (n,c) slice,
|
|
32
|
+
iterating over (n,c) in strides of nc_stride.
|
|
33
|
+
"""
|
|
34
|
+
NC = N * C
|
|
35
|
+
nc_stride = tl.num_programs(axis=1)
|
|
36
|
+
nc_iter = (tl.program_id(axis=1).to(tl.int64)).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)
|
|
37
|
+
pid = tl.program_id(axis=0).to(tl.int64)
|
|
38
|
+
idx = 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)
|
|
39
|
+
|
|
40
|
+
# Decompose flat index -> (od, oh, ow)
|
|
41
|
+
ow = idx % OW
|
|
42
|
+
oh = (idx // OW) % OH
|
|
43
|
+
od = (idx // (OW * OH)) % OD
|
|
44
|
+
|
|
45
|
+
# Map output coords to input coords (nearest neighbor)
|
|
46
|
+
id_ = tl.minimum((od * reciprocal_scale_d).to(tl.int32), ID - 1)
|
|
47
|
+
ih = tl.minimum((oh * reciprocal_scale_h).to(tl.int32), IH - 1)
|
|
48
|
+
iw = tl.minimum((ow * reciprocal_scale_w).to(tl.int32), IW - 1)
|
|
49
|
+
|
|
50
|
+
# Compute offsets for contiguous [N, C, D, H, W] layout
|
|
51
|
+
offset_o = ((nc_iter * OD + od) * OH + oh) * OW + ow
|
|
52
|
+
offset_i = ((nc_iter * ID + id_) * IH + ih) * IW + iw
|
|
53
|
+
src_index_stride = nc_stride * ID * IH * IW
|
|
54
|
+
dst_index_stride = nc_stride * OD * OH * OW
|
|
55
|
+
|
|
56
|
+
while nc_iter < NC:
|
|
57
|
+
data = tl.load(ptr_i + offset_i)
|
|
58
|
+
tl.store(ptr_o + offset_o, data)
|
|
59
|
+
ptr_i += src_index_stride
|
|
60
|
+
ptr_o += dst_index_stride
|
|
61
|
+
nc_iter += nc_stride
|
nbxtensor/ops/var.py
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""Variance — pure @triton.jit kernels.
|
|
2
|
+
|
|
3
|
+
Welford online algorithm for numerically-stable variance.
|
|
4
|
+
Global reduction via two-pass and dim-specific Welford kernel.
|
|
5
|
+
Extracted from FlagGems var_mean (Apache-2.0).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import triton
|
|
9
|
+
import triton.language as tl
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# ---------------------------------------------------------------------------
|
|
13
|
+
# Welford combine function (used by tl.reduce)
|
|
14
|
+
# ---------------------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
@triton.jit
|
|
17
|
+
def welford_func(mean_x, count_x, M_x, mean_y, count_y, M_y):
|
|
18
|
+
"""Combine two Welford partial aggregates."""
|
|
19
|
+
count = count_x + count_y
|
|
20
|
+
_count = tl.maximum(count, 1)
|
|
21
|
+
mc_x = mean_x * count_x
|
|
22
|
+
mc_y = mean_y * count_y
|
|
23
|
+
mean = (mc_x + mc_y) / _count
|
|
24
|
+
M = M_x + mc_x * mean_x + M_y + mc_y * mean_y - count * mean * mean
|
|
25
|
+
return mean, count, M
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# ---------------------------------------------------------------------------
|
|
29
|
+
# Global reduction: two-pass (partial stats → combine)
|
|
30
|
+
# ---------------------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
@triton.jit
|
|
33
|
+
def var_kernel_1(
|
|
34
|
+
X,
|
|
35
|
+
Acc,
|
|
36
|
+
Average,
|
|
37
|
+
Count,
|
|
38
|
+
N,
|
|
39
|
+
BLOCK_N: tl.constexpr,
|
|
40
|
+
):
|
|
41
|
+
"""Pass 1: compute partial sum, sum-of-squares, and count per block."""
|
|
42
|
+
pid = tl.program_id(0).to(tl.int64)
|
|
43
|
+
offset = pid * BLOCK_N + tl.arange(0, BLOCK_N)
|
|
44
|
+
|
|
45
|
+
X = X + offset
|
|
46
|
+
Acc = Acc + pid
|
|
47
|
+
Average = Average + pid
|
|
48
|
+
Count = Count + pid
|
|
49
|
+
mask = offset < N
|
|
50
|
+
|
|
51
|
+
x = tl.load(X, mask, other=0.0).to(tl.float32)
|
|
52
|
+
|
|
53
|
+
count = tl.sum(mask.to(tl.float32))
|
|
54
|
+
average = tl.sum(x) / count
|
|
55
|
+
acc = tl.sum(x * x) - count * average * average
|
|
56
|
+
|
|
57
|
+
tl.store(Average, average)
|
|
58
|
+
tl.store(Acc, acc)
|
|
59
|
+
tl.store(Count, count)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@triton.jit(do_not_specialize=["correction"])
|
|
63
|
+
def var_kernel_2(
|
|
64
|
+
Acc,
|
|
65
|
+
Average,
|
|
66
|
+
Count,
|
|
67
|
+
Var,
|
|
68
|
+
N,
|
|
69
|
+
correction,
|
|
70
|
+
BLOCK_NUM,
|
|
71
|
+
BLOCK_N: tl.constexpr,
|
|
72
|
+
):
|
|
73
|
+
"""Pass 2: Welford-combine all blocks and output variance."""
|
|
74
|
+
offset = tl.arange(0, BLOCK_N)
|
|
75
|
+
mask = offset < BLOCK_NUM
|
|
76
|
+
Acc = Acc + offset
|
|
77
|
+
Average = Average + offset
|
|
78
|
+
Count = Count + offset
|
|
79
|
+
acc = tl.load(Acc, mask, other=0.0).to(tl.float32)
|
|
80
|
+
average = tl.load(Average, mask, other=0.0).to(tl.float32)
|
|
81
|
+
count = tl.load(Count, mask, other=0.0).to(tl.float32)
|
|
82
|
+
|
|
83
|
+
_mean, _, nvar = tl.reduce(
|
|
84
|
+
(average, count, acc), axis=0, combine_fn=welford_func
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
var = nvar / (N - correction)
|
|
88
|
+
tl.store(Var, var)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
# ---------------------------------------------------------------------------
|
|
92
|
+
# Dim-specific: Welford online variance along one axis
|
|
93
|
+
# ---------------------------------------------------------------------------
|
|
94
|
+
|
|
95
|
+
@triton.jit(do_not_specialize=["correction"])
|
|
96
|
+
def var_welford_kernel(
|
|
97
|
+
X,
|
|
98
|
+
Var,
|
|
99
|
+
M,
|
|
100
|
+
N,
|
|
101
|
+
correction,
|
|
102
|
+
BLOCK_M: tl.constexpr,
|
|
103
|
+
BLOCK_N: tl.constexpr,
|
|
104
|
+
):
|
|
105
|
+
"""Welford variance along compressed inner dim N.
|
|
106
|
+
|
|
107
|
+
X: [M, N] (dim-compressed) → Var: [M]
|
|
108
|
+
"""
|
|
109
|
+
pid = tl.program_id(0).to(tl.int64) * BLOCK_M + tl.arange(0, BLOCK_M)[:, None]
|
|
110
|
+
X = X + pid * N
|
|
111
|
+
Var = Var + pid
|
|
112
|
+
row_mask = pid < M
|
|
113
|
+
|
|
114
|
+
_mean = tl.zeros([BLOCK_M, BLOCK_N], dtype=tl.float32)
|
|
115
|
+
_acc = tl.zeros([BLOCK_M, BLOCK_N], dtype=tl.float32)
|
|
116
|
+
_count = tl.zeros([BLOCK_M, BLOCK_N], dtype=tl.float32)
|
|
117
|
+
for off in range(0, N, BLOCK_N):
|
|
118
|
+
cols = off + tl.arange(0, BLOCK_N)[None, :]
|
|
119
|
+
col_mask = cols < N
|
|
120
|
+
mask = row_mask & col_mask
|
|
121
|
+
|
|
122
|
+
x = tl.load(X + cols, mask, other=0.0).to(tl.float32)
|
|
123
|
+
|
|
124
|
+
count = _count + mask
|
|
125
|
+
cnt = tl.maximum(count, 1)
|
|
126
|
+
cur_mean = (_mean * _count + x) / cnt
|
|
127
|
+
_acc += (x - cur_mean) * (x - _mean) * mask
|
|
128
|
+
_mean = cur_mean
|
|
129
|
+
_count = count
|
|
130
|
+
|
|
131
|
+
_mean_r, _, acc_r = tl.reduce(
|
|
132
|
+
(_mean, _count, _acc), axis=1, combine_fn=welford_func
|
|
133
|
+
)
|
|
134
|
+
var = acc_r / (N - correction)
|
|
135
|
+
var = var[:, None]
|
|
136
|
+
tl.store(Var, var, row_mask)
|