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,1032 @@
|
|
|
1
|
+
"""Shape and copy wrappers: concatenation, stacking, padding, flips, rolls, repeats, triangles, pixel (un)shuffle, upsampling, broadcasting. Cut out of wrappers.py by family (M2, 2026-10-29), unchanged; shared launch layer and run context stay in wrappers.py."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import triton
|
|
7
|
+
from nbxtensor.ops.autotune_bucket import bucket_of as _bucket_of
|
|
8
|
+
from nbxtensor.ops import launch_keys as _lk
|
|
9
|
+
from nbxtensor.tensor import NBXTensor
|
|
10
|
+
from nbxtensor.dtype.nbx_dtype import NBXDtype, dtype_size
|
|
11
|
+
from nbxtensor.memory.allocator import DeviceAllocator
|
|
12
|
+
from nbxtensor.backend.runtime import set_device
|
|
13
|
+
from nbxtensor.shape import MAX_NDIM as _NBX_MAX_NDIM, broadcast_shapes, max_linear_offset
|
|
14
|
+
from nbxtensor.dtype.itemsize import canonical_name
|
|
15
|
+
from nbxtensor.dtype.promotion import binary_result, float_math_input
|
|
16
|
+
from nbxtensor.dtype.nbx_dtype import parse_dtype
|
|
17
|
+
from nbxtensor.memory.allocator import DeviceOOMError
|
|
18
|
+
from nbxtensor.backend.capabilities import fa_min_tile as _fa_min_tile
|
|
19
|
+
from nbxtensor.backend.capabilities import reduce_tile_max as _reduce_tile_max
|
|
20
|
+
from nbxtensor.backend.faults import device_fault_buffer, device_fault_code_cached, fault_channel
|
|
21
|
+
from nbxtensor.tensor import _upload_int64_array as _nbx_upload_int64, _saturating_cast as _nbx_saturating_cast
|
|
22
|
+
from nbxtensor.ops._configs import sdpa_block_ceiling as _sdpa_block_ceiling
|
|
23
|
+
from nbxtensor.ops._configs import sdpa_launch_meta as _sdpa_launch_meta
|
|
24
|
+
from nbxtensor.ops._configs import matrix_unit as _matrix_unit, matrix_unit_mm_tile as _matrix_unit_mm_tile
|
|
25
|
+
from nbxtensor.ops._configs import largest_tile_within_smem as _largest_tile_within_smem
|
|
26
|
+
from nbxtensor.backend import launcher as _nbx_launcher
|
|
27
|
+
from nbxtensor.backend.launcher import install as _install_launcher
|
|
28
|
+
from nbxtensor.ops.relu import relu_forward_kernel
|
|
29
|
+
from nbxtensor.ops.silu import silu_forward_kernel
|
|
30
|
+
from nbxtensor.ops.gelu import gelu_forward_kernel
|
|
31
|
+
from nbxtensor.ops.sigmoid import sigmoid_forward_kernel
|
|
32
|
+
from nbxtensor.ops.tanh import tanh_forward_kernel
|
|
33
|
+
from nbxtensor.ops.hardsigmoid import hardsigmoid_forward_kernel
|
|
34
|
+
from nbxtensor.ops.hardswish import hardswish_forward_kernel
|
|
35
|
+
from nbxtensor.ops.leaky_relu import leaky_relu_forward_kernel
|
|
36
|
+
from nbxtensor.ops.elu import elu_forward_kernel
|
|
37
|
+
from nbxtensor.ops.mish import mish_forward_kernel
|
|
38
|
+
from nbxtensor.ops.selu import selu_forward_kernel
|
|
39
|
+
from nbxtensor.ops.neg import neg_forward_kernel
|
|
40
|
+
from nbxtensor.ops.exp import exp_forward_kernel
|
|
41
|
+
from nbxtensor.ops.sin import sin_forward_kernel
|
|
42
|
+
from nbxtensor.ops.cos import cos_forward_kernel
|
|
43
|
+
from nbxtensor.ops.rsqrt import rsqrt_forward_kernel
|
|
44
|
+
from nbxtensor.ops.sqrt import sqrt_forward_kernel
|
|
45
|
+
from nbxtensor.ops.abs import abs_forward_kernel
|
|
46
|
+
from nbxtensor.ops.log import log_forward_kernel
|
|
47
|
+
from nbxtensor.ops.reciprocal import reciprocal_forward_kernel
|
|
48
|
+
from nbxtensor.ops.pow import pow_forward_kernel
|
|
49
|
+
from nbxtensor.ops.clamp import clamp_forward_kernel
|
|
50
|
+
from nbxtensor.ops.erf import erf_forward_kernel
|
|
51
|
+
from nbxtensor.ops.copy import copy_forward_kernel
|
|
52
|
+
from nbxtensor.ops.add import add_forward_kernel, add_scalar_kernel, add_scalar_dev_kernel, add_bias_broadcast_kernel
|
|
53
|
+
from nbxtensor.ops.binary_strided import add_strided_nd_kernel, mul_strided_nd_kernel, sub_strided_nd_kernel, div_strided_nd_kernel, add_scalar_strided_nd_kernel, mul_scalar_strided_nd_kernel
|
|
54
|
+
from nbxtensor.ops.mul import mul_forward_kernel, mul_scalar_kernel, mul_scalar_dev_kernel
|
|
55
|
+
from nbxtensor.ops.div import div_forward_kernel, div_scalar_kernel, div_scalar_dev_kernel, int_div_kernel
|
|
56
|
+
from nbxtensor.ops.sub import sub_forward_kernel, rsub_forward_kernel
|
|
57
|
+
from nbxtensor.ops.where import where_forward_kernel
|
|
58
|
+
from nbxtensor.ops.maximum import maximum_forward_kernel
|
|
59
|
+
from nbxtensor.ops.minimum import minimum_forward_kernel
|
|
60
|
+
from nbxtensor.ops.masked_fill import masked_fill_forward_kernel
|
|
61
|
+
from nbxtensor.ops.gt import gt_forward_kernel, gt_scalar_kernel
|
|
62
|
+
from nbxtensor.ops.ge import ge_forward_kernel, ge_scalar_kernel
|
|
63
|
+
from nbxtensor.ops.lt import lt_forward_kernel, lt_scalar_kernel
|
|
64
|
+
from nbxtensor.ops.eq import eq_forward_kernel, eq_scalar_kernel
|
|
65
|
+
from nbxtensor.ops.ne import ne_forward_kernel, ne_scalar_kernel
|
|
66
|
+
from nbxtensor.ops.layernorm import layer_norm_forward_kernel
|
|
67
|
+
from nbxtensor.ops.rmsnorm import rms_norm_forward_kernel
|
|
68
|
+
from nbxtensor.ops.softmax import softmax_forward_kernel, softmax_forward_looped_kernel
|
|
69
|
+
from nbxtensor.ops.matmul import matmul_kernel, addmm_kernel
|
|
70
|
+
from nbxtensor.ops._autotune_policy import NBX_FORCE_FP32_ACCUM
|
|
71
|
+
from nbxtensor.ops.fused_moe import fused_moe_kernel, silu_and_mul_kernel, silu_mul_split_kernel
|
|
72
|
+
from nbxtensor.ops.dtype_convert import bf16_to_fp16_kernel
|
|
73
|
+
from nbxtensor.ops.embedding import embedding_kernel, EMBEDDING_OOB
|
|
74
|
+
from nbxtensor.ops.sum import sum_forward_kernel
|
|
75
|
+
from nbxtensor.ops.mean import mean_forward_kernel
|
|
76
|
+
from nbxtensor.ops.amax import amax_forward_kernel
|
|
77
|
+
from nbxtensor.ops.glu import glu_forward_kernel
|
|
78
|
+
from nbxtensor.ops.le import le_forward_kernel, le_scalar_kernel
|
|
79
|
+
from nbxtensor.ops.softplus import softplus_forward_kernel
|
|
80
|
+
from nbxtensor.ops.dropout import dropout_inference_kernel
|
|
81
|
+
from nbxtensor.ops.upsample_nearest2d import upsample_nearest2d_kernel
|
|
82
|
+
from nbxtensor.ops.groupnorm import group_norm_forward_kernel
|
|
83
|
+
from nbxtensor.ops.index_select import index_select_kernel, INDEX_SELECT_OOB
|
|
84
|
+
from nbxtensor.ops.triu import triu_kernel, triu_batch_kernel
|
|
85
|
+
from nbxtensor.ops.tril import tril_kernel, tril_batch_kernel
|
|
86
|
+
from nbxtensor.ops.argmax import argmax_kernel_1, argmax_kernel_2, argmax_kernel_inner
|
|
87
|
+
from nbxtensor.ops.argmin import argmin_kernel_1, argmin_kernel_2, argmin_kernel
|
|
88
|
+
from nbxtensor.ops.conv2d import conv2d_forward_kernel
|
|
89
|
+
from nbxtensor.ops.depthwise_conv2d import depthwise_conv2d_kernel
|
|
90
|
+
from nbxtensor.ops.batch_norm import batch_norm_forward_kernel
|
|
91
|
+
from nbxtensor.ops.cumsum import scan_part_sum_kernel, add_base_sum_kernel
|
|
92
|
+
from nbxtensor.ops.scatter_op import scatter_kernel, scatter_add_kernel, scatter_reduce_amax_kernel, scatter_reduce_amin_kernel
|
|
93
|
+
from nbxtensor.ops.gather_op import gather_kernel
|
|
94
|
+
from nbxtensor.ops.avg_pool2d import avg_pool2d_forward_kernel
|
|
95
|
+
from nbxtensor.ops.max_pool2d import max_pool2d_forward_kernel
|
|
96
|
+
from nbxtensor.ops.max_pool3d import max_pool3d_forward_kernel
|
|
97
|
+
from nbxtensor.ops.cross_entropy import cross_entropy_loss_forward_kernel
|
|
98
|
+
from nbxtensor.ops.exp2 import exp2_forward_kernel
|
|
99
|
+
from nbxtensor.ops.tan import tan_forward_kernel
|
|
100
|
+
from nbxtensor.ops.celu import celu_forward_kernel
|
|
101
|
+
from nbxtensor.ops.log_sigmoid import log_sigmoid_forward_kernel
|
|
102
|
+
from nbxtensor.ops.isfinite import isfinite_forward_kernel
|
|
103
|
+
from nbxtensor.ops.isinf import isinf_forward_kernel
|
|
104
|
+
from nbxtensor.ops.isnan import isnan_forward_kernel
|
|
105
|
+
from nbxtensor.ops.nan_to_num import nan_to_num_forward_kernel
|
|
106
|
+
from nbxtensor.ops.threshold import threshold_forward_kernel
|
|
107
|
+
from nbxtensor.ops.floor import floor_forward_kernel, ceil_forward_kernel, round_forward_kernel, trunc_forward_kernel
|
|
108
|
+
from nbxtensor.ops.addcdiv import addcdiv_forward_kernel
|
|
109
|
+
from nbxtensor.ops.addcmul import addcmul_forward_kernel
|
|
110
|
+
from nbxtensor.ops.all_reduce import all_kernel_mid, all_kernel_result, all_kernel_dim
|
|
111
|
+
from nbxtensor.ops.any_reduce import any_kernel_mid, any_kernel_result, any_kernel_dim
|
|
112
|
+
from nbxtensor.ops.bitwise_and import bitwise_and_forward_kernel
|
|
113
|
+
from nbxtensor.ops.bitwise_or import bitwise_or_forward_kernel
|
|
114
|
+
from nbxtensor.ops.bitwise_not import bitwise_not_forward_kernel
|
|
115
|
+
from nbxtensor.ops.logical_and import logical_and_forward_kernel
|
|
116
|
+
from nbxtensor.ops.logical_or import logical_or_forward_kernel
|
|
117
|
+
from nbxtensor.ops.logical_not import logical_not_forward_kernel
|
|
118
|
+
from nbxtensor.ops.lerp import lerp_tensor_forward_kernel, lerp_scalar_head_kernel, lerp_scalar_tail_kernel
|
|
119
|
+
from nbxtensor.ops.dot_op import dot_kernel_small, dot_kernel_partial, dot_kernel_reduce
|
|
120
|
+
from nbxtensor.ops.flip_op import flip_1d_kernel, flip_strided_kernel
|
|
121
|
+
from nbxtensor.ops.cat_op import cat_copy_kernel_4
|
|
122
|
+
from nbxtensor.ops.fill_op import fill_kernel
|
|
123
|
+
from nbxtensor.ops.arange_op import arange_kernel
|
|
124
|
+
from nbxtensor.ops.prod import prod_kernel_mid, prod_kernel_result, prod_kernel
|
|
125
|
+
from nbxtensor.ops.min_reduce import min_kernel_mid, min_kernel_result, min_kernel
|
|
126
|
+
from nbxtensor.ops.max_reduce import max_kernel_mid, max_kernel_result, max_kernel
|
|
127
|
+
from nbxtensor.ops.baddbmm_op import baddbmm_kernel
|
|
128
|
+
from nbxtensor.ops.addmv_op import addmv_kernel
|
|
129
|
+
from nbxtensor.ops.mse_loss import mse_loss_partial_kernel, mse_loss_reduce_kernel, mse_loss_none_kernel
|
|
130
|
+
from nbxtensor.ops.nllloss import nll_loss_forward_kernel
|
|
131
|
+
from nbxtensor.ops.std import std_map_kernel, std_reduce_kernel, std_dim_kernel
|
|
132
|
+
from nbxtensor.ops.var import var_kernel_1, var_kernel_2, var_welford_kernel
|
|
133
|
+
from nbxtensor.ops.index_add import index_add_gather_kernel
|
|
134
|
+
from nbxtensor.ops.index_put_op import index_put_kernel, INDEX_PUT_OOB
|
|
135
|
+
from nbxtensor.ops.sort_op import (radix_sort_histogram_kernel,
|
|
136
|
+
radix_sort_scatter_kernel,
|
|
137
|
+
radix_sort_tile_counts_kernel,
|
|
138
|
+
radix_sort_tile_prefix_kernel)
|
|
139
|
+
from nbxtensor.ops.rope import rope_forward_kernel
|
|
140
|
+
from nbxtensor.ops.pixel_shuffle import (
|
|
141
|
+
pixel_shuffle_kernel,
|
|
142
|
+
pixel_shuffle_broadcast_aware_kernel,
|
|
143
|
+
)
|
|
144
|
+
from nbxtensor.ops.pixel_unshuffle import pixel_unshuffle_kernel
|
|
145
|
+
from nbxtensor.ops.upsample_bilinear2d import upsample_bilinear2d_kernel
|
|
146
|
+
from nbxtensor.ops.adaptive_avg_pool2d import adaptive_avg_pool2d_kernel
|
|
147
|
+
from nbxtensor.ops.conv_depthwise2d import conv_depthwise2d_kernel
|
|
148
|
+
from nbxtensor.ops.scaled_softmax import scaled_softmax_kernel
|
|
149
|
+
from nbxtensor.ops.vector_norm import (
|
|
150
|
+
l2_norm_kernel, l1_norm_kernel, linf_norm_kernel, l0_norm_kernel, lp_norm_kernel,
|
|
151
|
+
l2_norm_pass1_kernel, l2_norm_pass2_kernel,
|
|
152
|
+
linf_norm_pass1_kernel, linf_norm_pass2_kernel,
|
|
153
|
+
)
|
|
154
|
+
from nbxtensor.ops.addr import addr_kernel
|
|
155
|
+
from nbxtensor.ops.logical_xor import logical_xor_kernel
|
|
156
|
+
from nbxtensor.ops.bitwise_left_shift import bitwise_left_shift_kernel
|
|
157
|
+
from nbxtensor.ops.bitwise_right_shift import bitwise_right_shift_kernel
|
|
158
|
+
from nbxtensor.ops.rand_op import rand_kernel, randn_kernel
|
|
159
|
+
from nbxtensor.ops.clamp_min import clamp_min_forward_kernel
|
|
160
|
+
from nbxtensor.ops.conv_transpose2d import conv_transpose2d_kernel
|
|
161
|
+
from nbxtensor.ops.cummax import scan_part_max_kernel
|
|
162
|
+
from nbxtensor.ops.cummin import scan_part_min_kernel
|
|
163
|
+
from nbxtensor.ops.count_nonzero import count_nonzero_kernel
|
|
164
|
+
from nbxtensor.ops.trace_op import trace_kernel
|
|
165
|
+
from nbxtensor.ops.linspace_op import linspace_kernel
|
|
166
|
+
from nbxtensor.ops.full_op import full_kernel
|
|
167
|
+
from nbxtensor.ops.stack_op import stack_copy_kernel
|
|
168
|
+
from nbxtensor.ops.repeat_op import repeat_1d_kernel
|
|
169
|
+
from nbxtensor.ops.upsample_nearest3d import upsample_nearest3d_kernel
|
|
170
|
+
from nbxtensor.ops.weight_norm import weight_norm_kernel_first, weight_norm_kernel_last
|
|
171
|
+
from nbxtensor.ops.repeat_interleave import repeat_interleave_tensor_kernel
|
|
172
|
+
from nbxtensor.ops.elementwise_launch import ew_meta as _ew_meta, ew_grid as _ew_grid
|
|
173
|
+
from nbxtensor.ops import tiling_sizes as _ts
|
|
174
|
+
import math
|
|
175
|
+
from nbxtensor.ops import elementwise_wrappers as _ew
|
|
176
|
+
from nbxtensor.ops import linalg_wrappers as _la
|
|
177
|
+
from nbxtensor.ops import reduction_wrappers as _red
|
|
178
|
+
from nbxtensor.ops import wrappers as _core
|
|
179
|
+
_TRIU_MBS, _TRIU_NBS = 64, 512 # triu / tril 2D
|
|
180
|
+
_TRIU_BATCH_BS, _TRIU_MN_BS = 32, 1024 # triu / tril batch
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def grid_sampler_2d_wrapper(inp, grid, interpolation_mode=0,
|
|
184
|
+
padding_mode=0, align_corners=False):
|
|
185
|
+
"""aten::grid_sampler_2d — pure Triton 2D grid sampler.
|
|
186
|
+
|
|
187
|
+
ATen integer mode encoding: interpolation 0=bilinear, 1=nearest,
|
|
188
|
+
2=bicubic; padding 0=zeros, 1=border, 2=reflection. Implemented:
|
|
189
|
+
bilinear+bicubic x zeros+border x both align flags (the GLM-4.1V /
|
|
190
|
+
Qwen-VL pos-embed adaptation uses bicubic+border+align_corners=False);
|
|
191
|
+
ZERO FALLBACK on the rest. fp32 coordinate math and accumulation
|
|
192
|
+
(ATen opmath), output cast back to the input dtype."""
|
|
193
|
+
from nbxtensor.ops.grid_sampler import grid_sampler_2d_kernel
|
|
194
|
+
|
|
195
|
+
interpolation_mode = int(interpolation_mode)
|
|
196
|
+
padding_mode = int(padding_mode)
|
|
197
|
+
if interpolation_mode not in (0, 2):
|
|
198
|
+
raise RuntimeError(
|
|
199
|
+
"ZERO FALLBACK: grid_sampler_2d interpolation_mode="
|
|
200
|
+
f"{interpolation_mode} not implemented (0=bilinear, 2=bicubic).")
|
|
201
|
+
if padding_mode not in (0, 1):
|
|
202
|
+
raise RuntimeError(
|
|
203
|
+
"ZERO FALLBACK: grid_sampler_2d padding_mode="
|
|
204
|
+
f"{padding_mode} not implemented (0=zeros, 1=border).")
|
|
205
|
+
|
|
206
|
+
inp = inp.contiguous()
|
|
207
|
+
grid = grid.contiguous()
|
|
208
|
+
N, C, H, W = inp.shape
|
|
209
|
+
gN, oH, oW, two = grid.shape
|
|
210
|
+
out_spatial = oH * oW
|
|
211
|
+
out32 = NBXTensor.empty((N, C, oH, oW), dtype=NBXDtype.float32,
|
|
212
|
+
device=inp.device)
|
|
213
|
+
inp32 = inp.to(NBXDtype.float32)
|
|
214
|
+
grid32 = grid.to(NBXDtype.float32)
|
|
215
|
+
|
|
216
|
+
BLOCK_C = min(triton.next_power_of_2(max(C, 1)), 256)
|
|
217
|
+
launch_grid = (out_spatial, triton.cdiv(C, BLOCK_C), N)
|
|
218
|
+
set_device(inp32)
|
|
219
|
+
grid_sampler_2d_kernel[launch_grid](
|
|
220
|
+
inp32, grid32, out32,
|
|
221
|
+
C, H, W, out_spatial,
|
|
222
|
+
C * H * W, H * W, W, 1,
|
|
223
|
+
out_spatial * 2, 2, 1,
|
|
224
|
+
C * out_spatial, out_spatial, 1,
|
|
225
|
+
MODE=interpolation_mode,
|
|
226
|
+
PAD_BORDER=padding_mode,
|
|
227
|
+
ALIGN=1 if align_corners else 0,
|
|
228
|
+
BLOCK_C=BLOCK_C,
|
|
229
|
+
)
|
|
230
|
+
return out32.to(inp.dtype) if inp.dtype != NBXDtype.float32 else out32
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def copy_to(x, dtype: object) :
|
|
234
|
+
x = x.contiguous()
|
|
235
|
+
output = NBXTensor.empty_like(x, dtype=dtype)
|
|
236
|
+
set_device(x)
|
|
237
|
+
copy_forward_kernel[_ew._1d_grid(x.numel())](x, output, x.numel(), **_ew_meta(x.numel()))
|
|
238
|
+
return output
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def upsample_nearest1d_wrapper(
|
|
242
|
+
x, output_size, scales=None
|
|
243
|
+
) :
|
|
244
|
+
"""Upsample nearest 1D via 2D: [N,C,L] → unsqueeze → [N,C,1,L] → upsample2d → squeeze."""
|
|
245
|
+
x_2d = x.unsqueeze(2) # [N, C, 1, L]
|
|
246
|
+
if isinstance(output_size, (list, tuple)):
|
|
247
|
+
out_size_2d = [1, output_size[0]] if len(output_size) else [1, None]
|
|
248
|
+
else:
|
|
249
|
+
out_size_2d = [1, output_size]
|
|
250
|
+
# aten::upsample_nearest1d.vec passes scale_factors as a 1-element LIST
|
|
251
|
+
# ([scale]); the 2D wrapper's scalar scales_w path does `float(scales_w)`,
|
|
252
|
+
# which raises on a list. Unwrap to a scalar. When a scale is present the 2D
|
|
253
|
+
# wrapper recomputes OW = IW * scale from the LIVE input — exactly what a
|
|
254
|
+
# variable-length audio vocoder (HiFiGAN/iSTFTNet/DAC/S3Gen) needs so the
|
|
255
|
+
# output tracks the runtime token count rather than the baked trace length.
|
|
256
|
+
if isinstance(scales, (list, tuple)):
|
|
257
|
+
scale_w = scales[0] if len(scales) else None
|
|
258
|
+
else:
|
|
259
|
+
scale_w = scales
|
|
260
|
+
out_2d = upsample_nearest2d_wrapper(x_2d, out_size_2d, scales_h=None, scales_w=scale_w)
|
|
261
|
+
return out_2d.squeeze(2)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def upsample_nearest2d_wrapper(
|
|
265
|
+
x, output_size, scales_h=None, scales_w=None
|
|
266
|
+
) :
|
|
267
|
+
"""Upsample nearest 2D. Wrapper from FlagGems.
|
|
268
|
+
|
|
269
|
+
PyTorch's traced graph stores both `output_size` (concrete trace
|
|
270
|
+
value) and `scales_h/w` (the upsampling ratio). When the runtime
|
|
271
|
+
input size differs from the trace size — Sana 4Kpx: trace 64×64
|
|
272
|
+
latent → runtime 128×128, and every cascading decoder upsample
|
|
273
|
+
inherits the doubling — `output_size` no longer matches
|
|
274
|
+
`IH * scales_h`. Native PyTorch recomputes from the live input
|
|
275
|
+
when scale factors are present; the wrapper must do the same so
|
|
276
|
+
the cascade scales correctly. When `scales_h/w` is None we keep
|
|
277
|
+
the literal `output_size` (path used by audio paths that don't
|
|
278
|
+
rebind spatial dims).
|
|
279
|
+
"""
|
|
280
|
+
assert x.ndim == 4
|
|
281
|
+
N, C, IH, IW = x.shape
|
|
282
|
+
if isinstance(output_size, (list, tuple)):
|
|
283
|
+
OH, OW = output_size[0], output_size[1]
|
|
284
|
+
else:
|
|
285
|
+
OH, OW = output_size, output_size
|
|
286
|
+
|
|
287
|
+
# Recompute output size from runtime input when scale factors are
|
|
288
|
+
# given. Bit-identical when trace == runtime; corrects the cascade
|
|
289
|
+
# when they differ (Sana 4Kpx and any other graph traced at a
|
|
290
|
+
# smaller spatial size than runtime).
|
|
291
|
+
if scales_h is not None:
|
|
292
|
+
OH = int(IH * float(scales_h))
|
|
293
|
+
if scales_w is not None:
|
|
294
|
+
OW = int(IW * float(scales_w))
|
|
295
|
+
|
|
296
|
+
reciprocal_scale_h = (1.0 / scales_h) if scales_h is not None else (IH / OH)
|
|
297
|
+
reciprocal_scale_w = (1.0 / scales_w) if scales_w is not None else (IW / OW)
|
|
298
|
+
|
|
299
|
+
output = NBXTensor.empty((N, C, OH, OW), device=x.device, dtype=x.dtype)
|
|
300
|
+
total_threads = OH * OW
|
|
301
|
+
grid = (
|
|
302
|
+
triton.cdiv(total_threads, _ew_meta(total_threads)['BLOCK_SIZE']),
|
|
303
|
+
triton.cdiv(N * C, 4),
|
|
304
|
+
)
|
|
305
|
+
set_device(output)
|
|
306
|
+
s_n, s_c, s_h, s_w = x.stride()
|
|
307
|
+
upsample_nearest2d_kernel[grid](
|
|
308
|
+
output, x, N, C, OH, OW, IH, IW, s_n, s_c, s_h, s_w,
|
|
309
|
+
reciprocal_scale_h, reciprocal_scale_w,
|
|
310
|
+
**_ew_meta(total_threads),
|
|
311
|
+
)
|
|
312
|
+
return output
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def triu_wrapper(x, diagonal: int = 0) :
|
|
316
|
+
"""Upper triangular. Wrapper from FlagGems."""
|
|
317
|
+
x = x.contiguous()
|
|
318
|
+
out = NBXTensor.empty_like(x)
|
|
319
|
+
assert x.ndim >= 2
|
|
320
|
+
M, N = x.shape[-2:]
|
|
321
|
+
|
|
322
|
+
if x.ndim == 2:
|
|
323
|
+
grid = (triton.cdiv(M, _TRIU_MBS),)
|
|
324
|
+
set_device(x)
|
|
325
|
+
triu_kernel[grid](x, out, M, N, diagonal,
|
|
326
|
+
M_BLOCK_SIZE=_TRIU_MBS, N_BLOCK_SIZE=_TRIU_NBS,
|
|
327
|
+
num_warps=4)
|
|
328
|
+
else:
|
|
329
|
+
batch = x.numel() // (M * N)
|
|
330
|
+
B = x.reshape(batch, M * N)
|
|
331
|
+
grid = (
|
|
332
|
+
triton.cdiv(batch, _TRIU_BATCH_BS),
|
|
333
|
+
triton.cdiv(M * N, _TRIU_MN_BS),
|
|
334
|
+
)
|
|
335
|
+
set_device(B)
|
|
336
|
+
triu_batch_kernel[grid](B, out.reshape(batch, M * N), batch, M * N, N, diagonal,
|
|
337
|
+
BATCH_BLOCK_SIZE=_TRIU_BATCH_BS, MN_BLOCK_SIZE=_TRIU_MN_BS,
|
|
338
|
+
num_warps=4)
|
|
339
|
+
return out
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def tril_wrapper(x, diagonal: int = 0) :
|
|
343
|
+
"""Lower triangular. Adapted from FlagGems triu."""
|
|
344
|
+
x = x.contiguous()
|
|
345
|
+
out = NBXTensor.empty_like(x)
|
|
346
|
+
assert x.ndim >= 2
|
|
347
|
+
M, N = x.shape[-2:]
|
|
348
|
+
|
|
349
|
+
if x.ndim == 2:
|
|
350
|
+
grid = (triton.cdiv(M, _TRIU_MBS),)
|
|
351
|
+
set_device(x)
|
|
352
|
+
tril_kernel[grid](x, out, M, N, diagonal,
|
|
353
|
+
M_BLOCK_SIZE=_TRIU_MBS, N_BLOCK_SIZE=_TRIU_NBS,
|
|
354
|
+
num_warps=4)
|
|
355
|
+
else:
|
|
356
|
+
batch = x.numel() // (M * N)
|
|
357
|
+
B = x.reshape(batch, M * N)
|
|
358
|
+
grid = (
|
|
359
|
+
triton.cdiv(batch, _TRIU_BATCH_BS),
|
|
360
|
+
triton.cdiv(M * N, _TRIU_MN_BS),
|
|
361
|
+
)
|
|
362
|
+
set_device(B)
|
|
363
|
+
tril_batch_kernel[grid](B, out.reshape(batch, M * N), batch, M * N, N, diagonal,
|
|
364
|
+
BATCH_BLOCK_SIZE=_TRIU_BATCH_BS, MN_BLOCK_SIZE=_TRIU_MN_BS,
|
|
365
|
+
num_warps=4)
|
|
366
|
+
return out
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
# ---------------------------------------------------------------------------
|
|
370
|
+
# Flip
|
|
371
|
+
# ---------------------------------------------------------------------------
|
|
372
|
+
|
|
373
|
+
def roll_wrapper(x, shifts, dims=None):
|
|
374
|
+
"""Circular shift along given dim(s) — `torch.roll` semantics.
|
|
375
|
+
|
|
376
|
+
R33-pure: decomposed into `narrow` + `NBXTensor.cat`, no new
|
|
377
|
+
Triton kernel. A roll by `s` on a dim of size `n` is
|
|
378
|
+
`cat([x[..., n-s:, ...], x[..., :n-s, ...]], dim)`. Used by
|
|
379
|
+
Swin-attention models (Swin2SR / SwinIR / HAT) for the cyclic
|
|
380
|
+
window shift.
|
|
381
|
+
"""
|
|
382
|
+
# Normalise shifts/dims to parallel lists (torch allows int or
|
|
383
|
+
# tuple for both; dims=None means roll over the flattened tensor).
|
|
384
|
+
if dims is None:
|
|
385
|
+
flat = x.contiguous().view(-1)
|
|
386
|
+
n = flat.shape[0]
|
|
387
|
+
s = int(shifts if isinstance(shifts, int) else shifts[0]) % n
|
|
388
|
+
if s == 0:
|
|
389
|
+
return x
|
|
390
|
+
rolled = NBXTensor.cat(
|
|
391
|
+
[flat.narrow(0, n - s, s), flat.narrow(0, 0, n - s)], dim=0)
|
|
392
|
+
return rolled.view(*x.shape)
|
|
393
|
+
|
|
394
|
+
if isinstance(shifts, int):
|
|
395
|
+
shifts = [shifts]
|
|
396
|
+
if isinstance(dims, int):
|
|
397
|
+
dims = [dims]
|
|
398
|
+
|
|
399
|
+
# Every rolled dim at once, written into ONE output: per dim the tail [n-s, n) lands at [0, s) and the head
|
|
400
|
+
# [0, n-s) at [s, n), so the result is 2^k blocks copied from x (read by its strides, `copy_`) into their places.
|
|
401
|
+
# Rolling one dim after the other made a whole intermediate per dim beside its input and output — HAT-S at 2048
|
|
402
|
+
# px on 16 GB: the window shift's second dim held three 2 304 MB maps where the op's price holds two (2026-10-22).
|
|
403
|
+
from itertools import product
|
|
404
|
+
moves = []
|
|
405
|
+
for shift, dim in zip(shifts, dims):
|
|
406
|
+
dim = dim % x.ndim
|
|
407
|
+
n = int(x.shape[dim])
|
|
408
|
+
s = int(shift) % n
|
|
409
|
+
if s:
|
|
410
|
+
moves.append([(dim, n - s, 0, s), (dim, 0, s, n - s)]) # (dim, from, to, length)
|
|
411
|
+
if not moves:
|
|
412
|
+
return x.contiguous()
|
|
413
|
+
out = NBXTensor.empty(tuple(x.shape), device=x.device, dtype=x.dtype)
|
|
414
|
+
for blocks in product(*moves):
|
|
415
|
+
src, dst = x, out
|
|
416
|
+
for dim, frm, to, length in blocks:
|
|
417
|
+
src = src.narrow(dim, frm, length)
|
|
418
|
+
dst = dst.narrow(dim, to, length)
|
|
419
|
+
dst.copy_(src)
|
|
420
|
+
return out
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
def flip_wrapper(x, dims) :
|
|
424
|
+
"""Reverse elements along the given dimension(s)."""
|
|
425
|
+
x = x.contiguous()
|
|
426
|
+
if isinstance(dims, int):
|
|
427
|
+
dims = [dims]
|
|
428
|
+
|
|
429
|
+
result = x
|
|
430
|
+
for dim in dims:
|
|
431
|
+
dim = dim % result.ndim
|
|
432
|
+
if result.ndim == 1:
|
|
433
|
+
output = NBXTensor.empty_like(result)
|
|
434
|
+
set_device(result)
|
|
435
|
+
flip_1d_kernel[_ew._1d_grid(result.numel())](
|
|
436
|
+
result, output, result.numel(),
|
|
437
|
+
**_ew_meta(result.numel()))
|
|
438
|
+
result = output
|
|
439
|
+
else:
|
|
440
|
+
output = NBXTensor.empty_like(result)
|
|
441
|
+
n_elements = result.numel()
|
|
442
|
+
dim_size = result.shape[dim]
|
|
443
|
+
# stride_dim = product of dims after flip dim
|
|
444
|
+
stride_dim = 1
|
|
445
|
+
for i in range(dim + 1, result.ndim):
|
|
446
|
+
stride_dim *= result.shape[i]
|
|
447
|
+
grid = _ew._1d_grid(n_elements)
|
|
448
|
+
set_device(result)
|
|
449
|
+
flip_strided_kernel[grid](
|
|
450
|
+
result, output, n_elements,
|
|
451
|
+
dim_size, stride_dim, stride_dim,
|
|
452
|
+
**_ew_meta(n_elements))
|
|
453
|
+
result = output
|
|
454
|
+
return result
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
# ---------------------------------------------------------------------------
|
|
458
|
+
# Gather
|
|
459
|
+
# ---------------------------------------------------------------------------
|
|
460
|
+
|
|
461
|
+
def broadcast_tensors_wrapper(*tensors):
|
|
462
|
+
"""aten::broadcast_tensors(Tensor[] tensors) -> Tensor[].
|
|
463
|
+
|
|
464
|
+
The TensorList arrives as a single list/tuple positional arg. Broadcast every
|
|
465
|
+
input to their common (numpy-style, right-aligned) shape and return them
|
|
466
|
+
UNPACKED — one output tensor per input — so the executor fills out_0, out_1,
|
|
467
|
+
... A bare ``lambda *t: t`` returned the nested list into out_0, so a
|
|
468
|
+
downstream consumer (lt / where / stack) received a Python list instead of an
|
|
469
|
+
NBXTensor (``'list' object has no attribute '_dtype'``).
|
|
470
|
+
"""
|
|
471
|
+
if len(tensors) == 1 and isinstance(tensors[0], (list, tuple)):
|
|
472
|
+
tensors = tuple(tensors[0])
|
|
473
|
+
if len(tensors) <= 1:
|
|
474
|
+
return tuple(tensors)
|
|
475
|
+
ndim = max(t.ndim for t in tensors)
|
|
476
|
+
out_shape = [1] * ndim
|
|
477
|
+
for t in tensors:
|
|
478
|
+
sh = (1,) * (ndim - t.ndim) + tuple(t.shape)
|
|
479
|
+
for i, s in enumerate(sh):
|
|
480
|
+
if s != 1:
|
|
481
|
+
if out_shape[i] != 1 and out_shape[i] != s:
|
|
482
|
+
raise RuntimeError(
|
|
483
|
+
f"broadcast_tensors: incompatible shapes at dim {i}: "
|
|
484
|
+
f"{out_shape[i]} vs {s}")
|
|
485
|
+
out_shape[i] = s
|
|
486
|
+
out_shape = tuple(out_shape)
|
|
487
|
+
return tuple(t if tuple(t.shape) == out_shape else t.expand(*out_shape)
|
|
488
|
+
for t in tensors)
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
# ===========================================================================
|
|
492
|
+
# PHASE 5 — spatial, RNG, remaining wrappers
|
|
493
|
+
# ===========================================================================
|
|
494
|
+
|
|
495
|
+
def pixel_shuffle_wrapper(x, upscale_factor: int) :
|
|
496
|
+
"""Pixel shuffle: [N,C*r*r,H,W] -> [N,C,H*r,W*r].
|
|
497
|
+
|
|
498
|
+
If `x` is a `BroadcastClonePyroxy` (returned by an upstream intercepted
|
|
499
|
+
aten.clone whose input is an NBX expand stride-0 view), reads through
|
|
500
|
+
the unmaterialized broadcast view via a stride-aware kernel and
|
|
501
|
+
eliminates the 8 GiB clone copy. P-SANA-4KPX-RUNTIME Fix F2 (Approche C).
|
|
502
|
+
"""
|
|
503
|
+
from nbxtensor.ops.fused_upsample_conv import BroadcastClonePyroxy
|
|
504
|
+
|
|
505
|
+
if isinstance(x, BroadcastClonePyroxy):
|
|
506
|
+
return _pixel_shuffle_broadcast_aware(x, upscale_factor)
|
|
507
|
+
|
|
508
|
+
N, C_in, H, W = x.shape
|
|
509
|
+
r = upscale_factor
|
|
510
|
+
C_out = C_in // (r * r)
|
|
511
|
+
OH, OW = H * r, W * r
|
|
512
|
+
x = x.contiguous()
|
|
513
|
+
output = NBXTensor.empty((N, C_out, OH, OW), device=x.device, dtype=x.dtype)
|
|
514
|
+
total = N * C_out * OH * OW
|
|
515
|
+
grid = _ew._1d_grid(total)
|
|
516
|
+
set_device(x)
|
|
517
|
+
pixel_shuffle_kernel[grid](
|
|
518
|
+
x, output, total,
|
|
519
|
+
C_out, H, W, r, OH, OW,
|
|
520
|
+
*x.stride(), *output.stride(),
|
|
521
|
+
**_ew_meta(total))
|
|
522
|
+
return output
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
def _pixel_shuffle_broadcast_aware(proxy, upscale_factor: int):
|
|
526
|
+
"""Read directly through an NBX expand stride-0 view, allocate clean
|
|
527
|
+
4D contiguous output, no clone materialization.
|
|
528
|
+
|
|
529
|
+
`proxy.bcast_view` is the expand output (5D NBXTensor with stride 0
|
|
530
|
+
on `proxy.bcast_dim`). Same data_ptr as the pre-expand tensor — NBX
|
|
531
|
+
expand is metadata-only (kernels/nbx_tensor.py:1581). The kernel reads
|
|
532
|
+
via 5D strides; the stride-0 dim aliases broadcast indices for free.
|
|
533
|
+
|
|
534
|
+
Layout assumption (matches DC-AE / Sana 4Kpx VAE pattern after
|
|
535
|
+
`unsqueeze(dim=2) -> expand(dim=2, B)`): the 5D view is laid out
|
|
536
|
+
(N, C_pre, B, H, W). bcast_dim is dim 2.
|
|
537
|
+
|
|
538
|
+
Output shape: (N, C_out, H*r, W*r) where C_out = (C_pre * B) // (r*r).
|
|
539
|
+
"""
|
|
540
|
+
view = proxy.bcast_view
|
|
541
|
+
bcast = proxy.bcast_factor
|
|
542
|
+
bcast_dim = proxy.bcast_dim
|
|
543
|
+
r = int(upscale_factor)
|
|
544
|
+
|
|
545
|
+
if view.ndim != 5 or bcast_dim != 2:
|
|
546
|
+
raise NotImplementedError(
|
|
547
|
+
f"_pixel_shuffle_broadcast_aware: only 5D layout (N,C,B,H,W) "
|
|
548
|
+
f"with bcast_dim=2 supported (matches NBX unsqueeze+expand "
|
|
549
|
+
f"DC-AE pattern). Got ndim={view.ndim} bcast_dim={bcast_dim}.")
|
|
550
|
+
|
|
551
|
+
N, C_pre, B_size, H, W = view.shape
|
|
552
|
+
if B_size != bcast:
|
|
553
|
+
raise AssertionError(
|
|
554
|
+
f"_pixel_shuffle_broadcast_aware: view dim 2 size {B_size} != "
|
|
555
|
+
f"bcast factor {bcast} from static DAG analysis")
|
|
556
|
+
C_in_view = C_pre * bcast
|
|
557
|
+
if C_in_view % (r * r) != 0:
|
|
558
|
+
raise AssertionError(
|
|
559
|
+
f"_pixel_shuffle_broadcast_aware: post-view channels {C_in_view} "
|
|
560
|
+
f"not divisible by r*r={r*r}")
|
|
561
|
+
C_out = C_in_view // (r * r)
|
|
562
|
+
OH, OW = H * r, W * r
|
|
563
|
+
|
|
564
|
+
output = NBXTensor.empty((N, C_out, OH, OW),
|
|
565
|
+
device=view.device, dtype=view.dtype)
|
|
566
|
+
total = N * C_out * OH * OW
|
|
567
|
+
grid = _ew._1d_grid(total)
|
|
568
|
+
set_device(view)
|
|
569
|
+
pixel_shuffle_broadcast_aware_kernel[grid](
|
|
570
|
+
view, output, total,
|
|
571
|
+
C_out, OH, OW, r, bcast,
|
|
572
|
+
*view.stride(), *output.stride(),
|
|
573
|
+
**_ew_meta(total))
|
|
574
|
+
return output
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
def pixel_unshuffle_wrapper(x, downscale_factor: int) :
|
|
578
|
+
"""Pixel unshuffle: [N,C,H*r,W*r] -> [N,C*r*r,H,W]."""
|
|
579
|
+
N, C, IH, IW = x.shape
|
|
580
|
+
r = downscale_factor
|
|
581
|
+
C_out = C * r * r
|
|
582
|
+
OH, OW = IH // r, IW // r
|
|
583
|
+
x = x.contiguous()
|
|
584
|
+
output = NBXTensor.empty((N, C_out, OH, OW), device=x.device, dtype=x.dtype)
|
|
585
|
+
total = N * C_out * OH * OW
|
|
586
|
+
grid = _ew._1d_grid(total)
|
|
587
|
+
set_device(x)
|
|
588
|
+
pixel_unshuffle_kernel[grid](
|
|
589
|
+
x, output, total,
|
|
590
|
+
C, IH, IW, r, C_out, OH, OW,
|
|
591
|
+
*x.stride(), *output.stride(),
|
|
592
|
+
**_ew_meta(total))
|
|
593
|
+
return output
|
|
594
|
+
|
|
595
|
+
|
|
596
|
+
# ===========================================================================
|
|
597
|
+
# PHASE 6: VIDEO + AUDIO WRAPPERS
|
|
598
|
+
# ===========================================================================
|
|
599
|
+
|
|
600
|
+
def upsample_nearest3d_wrapper(
|
|
601
|
+
x, output_size, scales_d=None, scales_h=None, scales_w=None
|
|
602
|
+
) :
|
|
603
|
+
"""Upsample nearest 3D: [N,C,D,H,W] -> [N,C,OD,OH,OW]."""
|
|
604
|
+
assert x.ndim == 5, f"Expected 5D input, got {x.ndim}D"
|
|
605
|
+
x = x.contiguous()
|
|
606
|
+
N, C, ID, IH, IW = x.shape
|
|
607
|
+
if isinstance(output_size, (list, tuple)):
|
|
608
|
+
OD, OH, OW = output_size[0], output_size[1], output_size[2]
|
|
609
|
+
else:
|
|
610
|
+
OD = OH = OW = output_size
|
|
611
|
+
|
|
612
|
+
reciprocal_scale_d = (1.0 / scales_d) if scales_d is not None else (ID / OD)
|
|
613
|
+
reciprocal_scale_h = (1.0 / scales_h) if scales_h is not None else (IH / OH)
|
|
614
|
+
reciprocal_scale_w = (1.0 / scales_w) if scales_w is not None else (IW / OW)
|
|
615
|
+
|
|
616
|
+
output = NBXTensor.empty((N, C, OD, OH, OW), device=x.device, dtype=x.dtype)
|
|
617
|
+
total_threads = OD * OH * OW
|
|
618
|
+
grid = (
|
|
619
|
+
triton.cdiv(total_threads, _ew_meta(total_threads)['BLOCK_SIZE']),
|
|
620
|
+
triton.cdiv(N * C, 4),
|
|
621
|
+
)
|
|
622
|
+
set_device(output)
|
|
623
|
+
upsample_nearest3d_kernel[grid](
|
|
624
|
+
output, x, N, C, OD, OH, OW, ID, IH, IW,
|
|
625
|
+
reciprocal_scale_d, reciprocal_scale_h, reciprocal_scale_w,
|
|
626
|
+
**_ew_meta(total_threads),
|
|
627
|
+
)
|
|
628
|
+
return output
|
|
629
|
+
|
|
630
|
+
|
|
631
|
+
def repeat_interleave_self_int_wrapper(
|
|
632
|
+
inp, repeats: int, dim: int = 0, output_size: int = None
|
|
633
|
+
) :
|
|
634
|
+
"""repeat_interleave with scalar repeats: stride trick + copy.
|
|
635
|
+
|
|
636
|
+
[1,2,3] with repeats=2 -> [1,1,2,2,3,3]
|
|
637
|
+
"""
|
|
638
|
+
if dim < 0:
|
|
639
|
+
dim = dim + inp.ndim
|
|
640
|
+
inp_shape = list(inp.shape)
|
|
641
|
+
inp_stride = list(inp.stride())
|
|
642
|
+
output_shape = list(inp.shape)
|
|
643
|
+
output_shape[dim] *= repeats
|
|
644
|
+
|
|
645
|
+
if repeats == 0:
|
|
646
|
+
return NBXTensor.empty(output_shape, dtype=inp.dtype, device=inp.device)
|
|
647
|
+
|
|
648
|
+
# Use expand + clone to implement the stride trick
|
|
649
|
+
view_shape = inp_shape[:dim + 1] + [repeats] + inp_shape[dim + 1:]
|
|
650
|
+
view_stride = inp_stride[:dim + 1] + [0] + inp_stride[dim + 1:]
|
|
651
|
+
expanded = lambda t, s, st: t.as_strided(s, st)(inp, view_shape, view_stride)
|
|
652
|
+
return expanded.reshape(output_shape).contiguous()
|
|
653
|
+
|
|
654
|
+
|
|
655
|
+
def repeat_interleave_tensor_wrapper(
|
|
656
|
+
repeats, output_size: int = None
|
|
657
|
+
) :
|
|
658
|
+
"""repeat_interleave with tensor repeats: returns index tensor.
|
|
659
|
+
|
|
660
|
+
repeats=[2,3,1] -> [0,0,1,1,1,2]
|
|
661
|
+
"""
|
|
662
|
+
assert repeats.ndim == 1, "repeats must be a 1D tensor"
|
|
663
|
+
# NBXTensor has no .cumsum()/[-1] — use the cumsum wrapper + select/item
|
|
664
|
+
# (the wrapper was never exercised in triton before Kokoro's alignment).
|
|
665
|
+
cumsum = _red.cumsum_wrapper(repeats, 0)
|
|
666
|
+
result_size = int(cumsum.select(0, -1).item())
|
|
667
|
+
|
|
668
|
+
out = NBXTensor.empty((result_size,), dtype=repeats.dtype, device=repeats.device)
|
|
669
|
+
size = repeats.size(0)
|
|
670
|
+
|
|
671
|
+
BLOCK_SIZE = 32
|
|
672
|
+
set_device(repeats)
|
|
673
|
+
repeat_interleave_tensor_kernel[(size,)](
|
|
674
|
+
repeats, cumsum, out, size, BLOCK_SIZE=BLOCK_SIZE, num_warps=1,
|
|
675
|
+
)
|
|
676
|
+
return out
|
|
677
|
+
|
|
678
|
+
|
|
679
|
+
def repeat_interleave_self_tensor_wrapper(
|
|
680
|
+
inp, repeats, dim: int = 0, output_size: int = None
|
|
681
|
+
) :
|
|
682
|
+
"""repeat_interleave with tensor repeats applied to input.
|
|
683
|
+
|
|
684
|
+
If repeats is a scalar tensor, delegates to self_int version.
|
|
685
|
+
Otherwise builds index tensor and uses index_select.
|
|
686
|
+
"""
|
|
687
|
+
if dim is None:
|
|
688
|
+
inp = inp.flatten()
|
|
689
|
+
dim = 0
|
|
690
|
+
if dim < 0:
|
|
691
|
+
dim = dim + inp.ndim
|
|
692
|
+
|
|
693
|
+
if repeats.ndim == 0 or (repeats.ndim == 1 and repeats.size(0) == 1):
|
|
694
|
+
return repeat_interleave_self_int_wrapper(
|
|
695
|
+
inp, repeats.item(), dim=dim, output_size=output_size
|
|
696
|
+
)
|
|
697
|
+
|
|
698
|
+
indices = repeat_interleave_tensor_wrapper(repeats)
|
|
699
|
+
return inp
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
def repeat_interleave_wrapper(*args, **kwargs):
|
|
703
|
+
"""aten::repeat_interleave dispatcher — routes by args, since the bare
|
|
704
|
+
op_type cannot distinguish the overloads:
|
|
705
|
+
repeat_interleave(repeats: Tensor) 1 arg -> .Tensor (index build)
|
|
706
|
+
repeat_interleave(self, repeats: int, dim) int repeats -> .self_int
|
|
707
|
+
repeat_interleave(self, repeats: Tensor, dim) Tensor reps -> .self_Tensor
|
|
708
|
+
Kokoro's predictor alignment uses the 1-arg Tensor variant
|
|
709
|
+
(repeat_interleave(pred_dur) -> interleaved indices, length = sum(pred_dur));
|
|
710
|
+
the dispatch previously hardcoded self_int and dropped the `repeats` arg.
|
|
711
|
+
"""
|
|
712
|
+
if len(args) == 1:
|
|
713
|
+
return repeat_interleave_tensor_wrapper(args[0], **kwargs)
|
|
714
|
+
if isinstance(args[1], NBXTensor):
|
|
715
|
+
return repeat_interleave_self_tensor_wrapper(*args, **kwargs)
|
|
716
|
+
return repeat_interleave_self_int_wrapper(*args, **kwargs)
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
# ===========================================================================
|
|
720
|
+
# PADDING OPS — via Triton kernels
|
|
721
|
+
# ===========================================================================
|
|
722
|
+
|
|
723
|
+
def constant_pad_nd_wrapper(x, pad_list, value: float = 0.0) :
|
|
724
|
+
"""constant_pad_nd via Triton kernel."""
|
|
725
|
+
from nbxtensor.ops.pad_op import constant_pad_2d_kernel, constant_pad_1d_kernel, constant_pad_nd_kernel
|
|
726
|
+
x = _core._ensure_cuda(x).contiguous()
|
|
727
|
+
|
|
728
|
+
ndim = x.ndim
|
|
729
|
+
pad_len = len(pad_list)
|
|
730
|
+
|
|
731
|
+
# Parse pad list: [left, right, top, bottom, ...]
|
|
732
|
+
# Pads from last dim backwards (ATen convention)
|
|
733
|
+
pad_before = [0] * ndim
|
|
734
|
+
pad_after = [0] * ndim
|
|
735
|
+
for i in range(pad_len // 2):
|
|
736
|
+
dim_idx = ndim - 1 - i
|
|
737
|
+
pad_before[dim_idx] = int(pad_list[2 * i])
|
|
738
|
+
pad_after[dim_idx] = int(pad_list[2 * i + 1])
|
|
739
|
+
|
|
740
|
+
out_shape = list(x.shape)
|
|
741
|
+
for i in range(ndim):
|
|
742
|
+
out_shape[i] += pad_before[i] + pad_after[i]
|
|
743
|
+
|
|
744
|
+
if ndim > 5:
|
|
745
|
+
raise NotImplementedError(f"constant_pad_nd: {ndim}-D input; the one-pass kernel takes up to 5 dims")
|
|
746
|
+
output = NBXTensor.empty(out_shape, dtype=x.dtype, device=x.device)
|
|
747
|
+
total = output.numel()
|
|
748
|
+
|
|
749
|
+
if total == 0:
|
|
750
|
+
return output
|
|
751
|
+
|
|
752
|
+
from nbxtensor.tensor import _index_wide
|
|
753
|
+
_wide = _index_wide(total, max_linear_offset(x.shape, x.stride()), max_linear_offset(output.shape, output.stride()))
|
|
754
|
+
|
|
755
|
+
if ndim >= 4 and pad_len == 4:
|
|
756
|
+
# 4D: use optimized 2D kernel (N,C,H,W)
|
|
757
|
+
batch_channels = 1
|
|
758
|
+
for d in range(ndim - 2):
|
|
759
|
+
batch_channels *= x.shape[d]
|
|
760
|
+
in_h, in_w = x.shape[-2], x.shape[-1]
|
|
761
|
+
out_h, out_w = out_shape[-2], out_shape[-1]
|
|
762
|
+
constant_pad_2d_kernel[_ew._1d_grid(total)](
|
|
763
|
+
x, output, total,
|
|
764
|
+
in_h, in_w, out_h, out_w,
|
|
765
|
+
batch_channels,
|
|
766
|
+
x.stride(-4) if ndim >= 4 else 0,
|
|
767
|
+
x.stride(-3) if ndim >= 3 else 0,
|
|
768
|
+
x.stride(-2), x.stride(-1),
|
|
769
|
+
output.stride(-4) if ndim >= 4 else 0,
|
|
770
|
+
output.stride(-3) if ndim >= 3 else 0,
|
|
771
|
+
output.stride(-2), output.stride(-1),
|
|
772
|
+
pad_before[-1], pad_before[-2],
|
|
773
|
+
float(value),
|
|
774
|
+
**_ew_meta(total), WIDE=_wide,
|
|
775
|
+
)
|
|
776
|
+
elif pad_len == 2:
|
|
777
|
+
batch_size = 1
|
|
778
|
+
for d in range(ndim - 1):
|
|
779
|
+
batch_size *= x.shape[d]
|
|
780
|
+
in_size = x.shape[-1]
|
|
781
|
+
out_size = out_shape[-1]
|
|
782
|
+
constant_pad_1d_kernel[_ew._1d_grid(total)](
|
|
783
|
+
x, output, total,
|
|
784
|
+
in_size, out_size, batch_size,
|
|
785
|
+
pad_before[-1],
|
|
786
|
+
float(value),
|
|
787
|
+
**_ew_meta(total), WIDE=_wide,
|
|
788
|
+
)
|
|
789
|
+
else:
|
|
790
|
+
# General N-D constant pad in ONE pass (any dims, a middle temporal dim of a 5-D [B,C,T,H,W] causal pad
|
|
791
|
+
# included): every output element reads its input element or the value. The former path padded one dim at
|
|
792
|
+
# a time through `cat`, holding one output-sized copy per padded dim beside an unused output buffer: 3 extra
|
|
793
|
+
# outputs on Wan2.1's causal pad (6,182 MB beside a 2,060 MB result, 2026-10-17), unpriced by any plan.
|
|
794
|
+
dims_in = [1] * (5 - ndim) + list(x.shape)
|
|
795
|
+
dims_out = [1] * (5 - ndim) + list(out_shape)
|
|
796
|
+
strides = [0] * (5 - ndim) + [x.stride(i) for i in range(ndim)]
|
|
797
|
+
before = [0] * (5 - ndim) + list(pad_before)
|
|
798
|
+
constant_pad_nd_kernel[_ew._1d_grid(total)](
|
|
799
|
+
x, output, total,
|
|
800
|
+
*dims_in, *dims_out, *strides, *before,
|
|
801
|
+
float(value),
|
|
802
|
+
**_ew_meta(total), WIDE=_wide,
|
|
803
|
+
)
|
|
804
|
+
|
|
805
|
+
return output
|
|
806
|
+
|
|
807
|
+
|
|
808
|
+
def pad_wrapper(x, pad_list, mode: str = "constant",
|
|
809
|
+
value: float = 0.0) :
|
|
810
|
+
"""F.pad via Triton — routes by mode + padded-dim count (len(pad_list)//2).
|
|
811
|
+
|
|
812
|
+
`aten::pad` is the generic functional pad; PyTorch carries the mode as an
|
|
813
|
+
arg ('constant'/'reflect'/'replicate') rather than lowering to the
|
|
814
|
+
`aten::reflection_padNd` op, so the per-rank kernels must be reached from
|
|
815
|
+
here too. The reflection/replication wrappers below are R33-pure
|
|
816
|
+
(flip + narrow + NBXTensor.cat — no new kernel), so reflect/replicate are
|
|
817
|
+
real Triton paths, not torch fallbacks. The padded-dim count is the last-
|
|
818
|
+
dim-first PyTorch convention: 2 entries → 1 dim, 4 → 2 dims.
|
|
819
|
+
"""
|
|
820
|
+
if mode == "constant":
|
|
821
|
+
return constant_pad_nd_wrapper(x, pad_list, value)
|
|
822
|
+
ndim_padded = len(pad_list) // 2
|
|
823
|
+
if mode in ("reflect", "reflection"):
|
|
824
|
+
if ndim_padded == 1:
|
|
825
|
+
return reflection_pad1d_wrapper(x, pad_list)
|
|
826
|
+
if ndim_padded == 2:
|
|
827
|
+
return reflection_pad2d_wrapper(x, pad_list)
|
|
828
|
+
if ndim_padded == 3:
|
|
829
|
+
return reflection_pad3d_wrapper(x, pad_list)
|
|
830
|
+
raise RuntimeError(
|
|
831
|
+
f"[--triton mode] reflection pad over {ndim_padded} dims has no "
|
|
832
|
+
f"Triton wrapper (1D/2D/3D only). pad_list={pad_list}."
|
|
833
|
+
)
|
|
834
|
+
if mode in ("replicate", "replication"):
|
|
835
|
+
if ndim_padded == 1:
|
|
836
|
+
return replication_pad1d_wrapper(x, pad_list)
|
|
837
|
+
if ndim_padded == 2:
|
|
838
|
+
return replication_pad2d_wrapper(x, pad_list)
|
|
839
|
+
if ndim_padded == 3:
|
|
840
|
+
return replication_pad3d_wrapper(x, pad_list)
|
|
841
|
+
raise RuntimeError(
|
|
842
|
+
f"[--triton mode] replication pad over {ndim_padded} dims has no "
|
|
843
|
+
f"Triton wrapper (1D/2D/3D only). pad_list={pad_list}."
|
|
844
|
+
)
|
|
845
|
+
raise RuntimeError(
|
|
846
|
+
f"[--triton mode] pad mode='{mode}' not implemented. "
|
|
847
|
+
f"Supported: constant, reflect (1D/2D), replicate (1D/2D)."
|
|
848
|
+
)
|
|
849
|
+
|
|
850
|
+
|
|
851
|
+
def reflection_pad1d_wrapper(x, pad_list) :
|
|
852
|
+
"""Reflection pad 1D — `F.pad(mode='reflect')` on the last dim.
|
|
853
|
+
|
|
854
|
+
R33-pure: narrow + flip + cat, the width-axis case of
|
|
855
|
+
reflection_pad2d_wrapper (no new kernel — flip is a Triton kernel, cat and
|
|
856
|
+
narrow are Triton-backed). Reflection excludes the edge element (PyTorch
|
|
857
|
+
`reflect`): a left pad of p mirrors elements [1 .. p] reversed, a right pad
|
|
858
|
+
mirrors [L-1-p .. L-2] reversed. Used by vocoder conv/iSTFT pre-pad.
|
|
859
|
+
"""
|
|
860
|
+
pad_list = [int(v) for v in pad_list]
|
|
861
|
+
left, right = (pad_list + [0, 0])[:2]
|
|
862
|
+
out = x.contiguous()
|
|
863
|
+
L = out.shape[-1]
|
|
864
|
+
parts = []
|
|
865
|
+
if left > 0:
|
|
866
|
+
parts.append(flip_wrapper(out.narrow(-1, 1, left), [-1]))
|
|
867
|
+
parts.append(out)
|
|
868
|
+
if right > 0:
|
|
869
|
+
parts.append(flip_wrapper(out.narrow(-1, L - 1 - right, right), [-1]))
|
|
870
|
+
if len(parts) > 1:
|
|
871
|
+
out = NBXTensor.cat(parts, dim=-1).contiguous()
|
|
872
|
+
return out
|
|
873
|
+
|
|
874
|
+
|
|
875
|
+
def reflection_pad2d_wrapper(x, pad_list) :
|
|
876
|
+
"""Reflection pad 2D — `F.pad(mode='reflect')` semantics.
|
|
877
|
+
|
|
878
|
+
R33-pure: decomposed into `narrow` + `flip` + `NBXTensor.cat`,
|
|
879
|
+
no new Triton kernel (flip is already a Triton kernel; cat and
|
|
880
|
+
narrow are Triton-backed). Reflection excludes the edge pixel
|
|
881
|
+
itself (PyTorch `reflect`, not `replicate`/`symmetric`): a left
|
|
882
|
+
pad of `p` mirrors columns `[1 .. p]` reversed, a right pad
|
|
883
|
+
mirrors columns `[W-1-p .. W-2]` reversed. Same on the H axis,
|
|
884
|
+
applied to the width-padded intermediate.
|
|
885
|
+
|
|
886
|
+
Used by Swin-attention SR models (Swin2SR / SwinIR / HAT) for
|
|
887
|
+
the input feature reflection pad.
|
|
888
|
+
"""
|
|
889
|
+
pad_list = [int(v) for v in pad_list]
|
|
890
|
+
# torch convention: last-dim-first → [W_left, W_right, H_top, H_bot]
|
|
891
|
+
left, right, top, bottom = (pad_list + [0, 0, 0, 0])[:4]
|
|
892
|
+
out = x.contiguous()
|
|
893
|
+
|
|
894
|
+
# --- Width axis (dim=-1) ---
|
|
895
|
+
W = out.shape[-1]
|
|
896
|
+
parts = []
|
|
897
|
+
if left > 0:
|
|
898
|
+
parts.append(flip_wrapper(out.narrow(-1, 1, left), [-1]))
|
|
899
|
+
parts.append(out)
|
|
900
|
+
if right > 0:
|
|
901
|
+
parts.append(flip_wrapper(out.narrow(-1, W - 1 - right, right), [-1]))
|
|
902
|
+
if len(parts) > 1:
|
|
903
|
+
out = NBXTensor.cat(parts, dim=-1).contiguous()
|
|
904
|
+
|
|
905
|
+
# --- Height axis (dim=-2), on the width-padded tensor ---
|
|
906
|
+
H = out.shape[-2]
|
|
907
|
+
parts = []
|
|
908
|
+
if top > 0:
|
|
909
|
+
parts.append(flip_wrapper(out.narrow(-2, 1, top), [-2]))
|
|
910
|
+
parts.append(out)
|
|
911
|
+
if bottom > 0:
|
|
912
|
+
parts.append(flip_wrapper(out.narrow(-2, H - 1 - bottom, bottom), [-2]))
|
|
913
|
+
if len(parts) > 1:
|
|
914
|
+
out = NBXTensor.cat(parts, dim=-2).contiguous()
|
|
915
|
+
|
|
916
|
+
return out
|
|
917
|
+
|
|
918
|
+
|
|
919
|
+
def _reflect_pad_axis(out, axis, before, after):
|
|
920
|
+
"""Reflect (mirror, excluding the edge element — PyTorch `reflect`)
|
|
921
|
+
`before`/`after` slices along `axis` and cat. R33-pure: narrow + flip +
|
|
922
|
+
NBXTensor.cat (no new kernel), the per-axis core of reflection_pad2d_wrapper.
|
|
923
|
+
"""
|
|
924
|
+
if before <= 0 and after <= 0:
|
|
925
|
+
return out
|
|
926
|
+
L = out.shape[axis]
|
|
927
|
+
parts = []
|
|
928
|
+
if before > 0:
|
|
929
|
+
parts.append(flip_wrapper(out.narrow(axis, 1, before), [axis]))
|
|
930
|
+
parts.append(out)
|
|
931
|
+
if after > 0:
|
|
932
|
+
parts.append(flip_wrapper(out.narrow(axis, L - 1 - after, after), [axis]))
|
|
933
|
+
return NBXTensor.cat(parts, dim=axis).contiguous()
|
|
934
|
+
|
|
935
|
+
|
|
936
|
+
def reflection_pad3d_wrapper(x, pad_list) :
|
|
937
|
+
"""Reflection pad 3D (last three dims) — F.pad(mode='reflect'). R33-pure
|
|
938
|
+
narrow+flip+cat (no new kernel). Used by the SANA-Video / 5D-video VAE
|
|
939
|
+
reflection pad on [B, C, D, H, W]; previously mis-routed to the 2D wrapper
|
|
940
|
+
(correct only when the depth pad is 0)."""
|
|
941
|
+
pad_list = [int(v) for v in pad_list]
|
|
942
|
+
# torch convention: [W_left, W_right, H_top, H_bot, D_front, D_back]
|
|
943
|
+
wl, wr, ht, hb, df, db = (pad_list + [0, 0, 0, 0, 0, 0])[:6]
|
|
944
|
+
out = _reflect_pad_axis(x.contiguous(), -1, wl, wr)
|
|
945
|
+
out = _reflect_pad_axis(out, -2, ht, hb)
|
|
946
|
+
return _reflect_pad_axis(out, -3, df, db)
|
|
947
|
+
|
|
948
|
+
|
|
949
|
+
def _replication_pad_last(x, pad_list, n_axes: int):
|
|
950
|
+
"""Replication pad (PyTorch `replicate`) of the last `n_axes` dims, `pad_list` in torch's last-dim-first order
|
|
951
|
+
([W_left, W_right, H_top, H_bot, D_front, D_back]), in ONE pass over the output with the input read through its
|
|
952
|
+
strides (`replication_pad_nd_kernel`). The former narrow + expand + cat held a contiguous copy of the input and one
|
|
953
|
+
output-sized tensor per padded axis: on mochi-1-preview's VAE (3 GB activations) up to three of them beside the
|
|
954
|
+
result, priced by no plan (2026-10-28)."""
|
|
955
|
+
from nbxtensor.ops.pad_op import replication_pad_nd_kernel
|
|
956
|
+
from nbxtensor.tensor import _index_wide
|
|
957
|
+
pads = ([int(v) for v in pad_list] + [0] * (2 * n_axes))[:2 * n_axes]
|
|
958
|
+
ndim = len(x.shape)
|
|
959
|
+
if ndim > 5 or ndim < n_axes:
|
|
960
|
+
raise NotImplementedError(f"replication pad of {n_axes} dims on a {ndim}-D input: the one-pass kernel takes "
|
|
961
|
+
f"{n_axes} to 5 dims")
|
|
962
|
+
before = [0] * ndim
|
|
963
|
+
for k in range(n_axes):
|
|
964
|
+
before[ndim - 1 - k] = pads[2 * k]
|
|
965
|
+
out_shape = list(x.shape)
|
|
966
|
+
for k in range(n_axes):
|
|
967
|
+
out_shape[ndim - 1 - k] += pads[2 * k] + pads[2 * k + 1]
|
|
968
|
+
output = NBXTensor.empty(out_shape, dtype=x.dtype, device=x.device)
|
|
969
|
+
total = output.numel()
|
|
970
|
+
if total == 0:
|
|
971
|
+
return output
|
|
972
|
+
_wide = _index_wide(total, max_linear_offset(x.shape, x.stride()),
|
|
973
|
+
max_linear_offset(output.shape, output.stride()))
|
|
974
|
+
pad5 = 5 - ndim
|
|
975
|
+
set_device(x)
|
|
976
|
+
replication_pad_nd_kernel[_ew._1d_grid(total)](
|
|
977
|
+
x, output, total,
|
|
978
|
+
*([1] * pad5 + list(x.shape)), *([1] * pad5 + out_shape),
|
|
979
|
+
*([0] * pad5 + [x.stride(i) for i in range(ndim)]), *([0] * pad5 + before),
|
|
980
|
+
**_ew_meta(total), WIDE=_wide,
|
|
981
|
+
)
|
|
982
|
+
return output
|
|
983
|
+
|
|
984
|
+
|
|
985
|
+
def replication_pad1d_wrapper(x, pad_list) :
|
|
986
|
+
"""Replication pad 1D (last dim) — F.pad(mode='replicate'), one pass (`_replication_pad_last`)."""
|
|
987
|
+
return _replication_pad_last(x, pad_list, 1)
|
|
988
|
+
|
|
989
|
+
|
|
990
|
+
def replication_pad2d_wrapper(x, pad_list) :
|
|
991
|
+
"""Replication pad 2D (last two dims) — F.pad(mode='replicate'), one pass (`_replication_pad_last`)."""
|
|
992
|
+
return _replication_pad_last(x, pad_list, 2)
|
|
993
|
+
|
|
994
|
+
|
|
995
|
+
def replication_pad3d_wrapper(x, pad_list) :
|
|
996
|
+
"""Replication pad 3D (last three dims) — F.pad(mode='replicate'), one pass (`_replication_pad_last`). Used by
|
|
997
|
+
the Mochi / 5D-video VAE decoder edge pad on [B, C, D, H, W]."""
|
|
998
|
+
return _replication_pad_last(x, pad_list, 3)
|
|
999
|
+
_wide = _index_wide(total, max_linear_offset(x.shape, x.stride()),
|
|
1000
|
+
max_linear_offset(output.shape, output.stride()))
|
|
1001
|
+
pad5 = 5 - ndim
|
|
1002
|
+
set_device(x)
|
|
1003
|
+
replication_pad_nd_kernel[_ew._1d_grid(total)](
|
|
1004
|
+
x, output, total,
|
|
1005
|
+
*([1] * pad5 + list(x.shape)), *([1] * pad5 + out_shape),
|
|
1006
|
+
*([0] * pad5 + [x.stride(i) for i in range(ndim)]), *([0] * pad5 + before),
|
|
1007
|
+
**_ew_meta(total), WIDE=_wide,
|
|
1008
|
+
)
|
|
1009
|
+
return output
|
|
1010
|
+
|
|
1011
|
+
|
|
1012
|
+
# ===========================================================================
|
|
1013
|
+
# INTERPOLATE — generic dispatch
|
|
1014
|
+
# ===========================================================================
|
|
1015
|
+
|
|
1016
|
+
def interpolate_wrapper(x, size=None, scale_factor=None,
|
|
1017
|
+
mode: str = "nearest", align_corners=None, **kwargs) :
|
|
1018
|
+
"""F.interpolate via Triton upsample kernels."""
|
|
1019
|
+
if mode == "nearest":
|
|
1020
|
+
if x.ndim == 3:
|
|
1021
|
+
return upsample_nearest1d_wrapper(x, size, scale_factor)
|
|
1022
|
+
elif x.ndim == 4:
|
|
1023
|
+
return upsample_nearest2d_wrapper(x, size, scale_factor)
|
|
1024
|
+
elif x.ndim == 5:
|
|
1025
|
+
return upsample_nearest3d_wrapper(x, size, scale_factor)
|
|
1026
|
+
elif mode == "bilinear":
|
|
1027
|
+
return _la.upsample_bilinear2d_wrapper(x, size, align_corners, scale_factor)
|
|
1028
|
+
elif mode == "linear":
|
|
1029
|
+
return _la.upsample_linear1d_wrapper(x, size, align_corners, scale_factor)
|
|
1030
|
+
raise RuntimeError(
|
|
1031
|
+
f"[--triton mode] interpolate mode='{mode}' not implemented for {x.ndim}D input."
|
|
1032
|
+
)
|