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,223 @@
|
|
|
1
|
+
"""Shared seeded CPU fp64 draw frontier (R30).
|
|
2
|
+
|
|
3
|
+
ONE code path draws sampled tokens for BOTH engines: logits cross the
|
|
4
|
+
boundary as fp64 numpy arrays (D2H at the caller), the vendor-faithful
|
|
5
|
+
filter chain (repetition penalty -> temperature -> top-k -> top-p) and
|
|
6
|
+
the draw run in CPU fp64, and the uniform stream comes from one seeded
|
|
7
|
+
generator. Compiled and triton therefore produce bit-identical draws
|
|
8
|
+
whenever the incoming logits agree; near-ties remain the only residual
|
|
9
|
+
class, adjudicated by margins (NBX_DECODE_TOPK doctrine).
|
|
10
|
+
|
|
11
|
+
Torch-free by construction: numpy is CPU glue, legal in both modes
|
|
12
|
+
(R33/R34), so this module is importable from core/ AND triton/ without
|
|
13
|
+
duplication. Precedent: the dual_ar flow's byte-identical duplicated
|
|
14
|
+
`_sample_token_np` pair — this module is that prototype promoted to a
|
|
15
|
+
single shared frontier. Scope: activated by a registry-declared speech
|
|
16
|
+
sampling contract; existing zoo samplers are untouched (their byte
|
|
17
|
+
gates hold by construction).
|
|
18
|
+
|
|
19
|
+
Filter semantics mirror the transformers LogitsProcessor chain:
|
|
20
|
+
- repetition penalty: seen ids with logit > 0 divided by the penalty,
|
|
21
|
+
logit <= 0 multiplied by it (RepetitionPenaltyLogitsProcessor).
|
|
22
|
+
- top-k: THRESHOLD keep — every logit >= the k-th highest survives
|
|
23
|
+
(ties at the threshold may keep more than k, exactly like
|
|
24
|
+
TopKLogitsWarper's `< topk(...)[-1]` mask).
|
|
25
|
+
- top-p: smallest set of highest-probability tokens whose cumulative
|
|
26
|
+
probability reaches top_p, at least one token kept
|
|
27
|
+
(TopPLogitsWarper); ties broken by ascending vocab index for
|
|
28
|
+
run-to-run determinism.
|
|
29
|
+
- draw: inverse-CDF walk over the filtered, renormalized fp64 probs in
|
|
30
|
+
vocab-index order against one uniform from the stream. The draw
|
|
31
|
+
count per step is the cross-engine coupling contract: both engines
|
|
32
|
+
MUST consume draws in the same order.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
import json
|
|
36
|
+
import os
|
|
37
|
+
|
|
38
|
+
import numpy as np
|
|
39
|
+
|
|
40
|
+
__all__ = ["SeededDrawStream", "apply_repetition_penalty",
|
|
41
|
+
"seeded_gaussian"]
|
|
42
|
+
|
|
43
|
+
# NBX_DRAW_DIAG=<jsonl path>: per-draw top-4 candidate ids/logits + the
|
|
44
|
+
# top-2 margin + the chosen id, appended as one JSON line. The speech
|
|
45
|
+
# twin of NBX_DECODE_TOPK — at any cross-engine code divergence the
|
|
46
|
+
# FIRST differing line localizes the flip and its margin adjudicates
|
|
47
|
+
# near-tie vs large-margin (both engines instrumented by construction:
|
|
48
|
+
# this module IS the shared frontier). Default off, zero cost off.
|
|
49
|
+
_DIAG_PATH = os.environ.get("NBX_DRAW_DIAG")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def apply_repetition_penalty(logits: np.ndarray, seen_ids, penalty: float) -> np.ndarray:
|
|
53
|
+
"""RepetitionPenaltyLogitsProcessor semantics on fp64 logits (in place)."""
|
|
54
|
+
if not penalty or penalty == 1.0 or seen_ids is None:
|
|
55
|
+
return logits
|
|
56
|
+
ids = np.unique(np.asarray(list(seen_ids), dtype=np.int64))
|
|
57
|
+
if ids.size == 0:
|
|
58
|
+
return logits
|
|
59
|
+
ids = ids[(ids >= 0) & (ids < logits.shape[0])]
|
|
60
|
+
vals = logits[ids]
|
|
61
|
+
logits[ids] = np.where(vals > 0, vals / penalty, vals * penalty)
|
|
62
|
+
return logits
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class SeededDrawStream:
|
|
66
|
+
"""One seeded uniform stream; the draw ORDER is the R30 contract."""
|
|
67
|
+
|
|
68
|
+
def __init__(self, seed: int):
|
|
69
|
+
self._rng = np.random.default_rng(int(seed) & 0xFFFFFFFFFFFFFFFF)
|
|
70
|
+
self.draws = 0
|
|
71
|
+
|
|
72
|
+
def draw(self, logits_fp64, temperature: float = 1.0, top_k: int = 0,
|
|
73
|
+
top_p: float = 1.0, seen_ids=None,
|
|
74
|
+
repetition_penalty: float = 1.0) -> int:
|
|
75
|
+
"""Sample one token id from a single 1-D fp64 logits vector."""
|
|
76
|
+
z = np.array(logits_fp64, dtype=np.float64).reshape(-1)
|
|
77
|
+
apply_repetition_penalty(z, seen_ids, repetition_penalty)
|
|
78
|
+
_diag_rec = None
|
|
79
|
+
if _DIAG_PATH:
|
|
80
|
+
_t4 = np.argsort(z)[::-1][:4]
|
|
81
|
+
_diag_rec = {
|
|
82
|
+
"n": self.draws,
|
|
83
|
+
"top4": [[int(i), round(float(z[i]), 6)] for i in _t4],
|
|
84
|
+
"margin": round(float(z[_t4[0]] - z[_t4[1]]), 6)
|
|
85
|
+
if _t4.size > 1 else None,
|
|
86
|
+
}
|
|
87
|
+
# temp <= 0 is the GREEDY contract (argmax), never a silent
|
|
88
|
+
# unscaled multinomial — the Ming sampling-class trap (2026-07-27).
|
|
89
|
+
if temperature is not None and temperature <= 0:
|
|
90
|
+
_g = int(np.argmax(z))
|
|
91
|
+
if _diag_rec is not None:
|
|
92
|
+
_diag_rec["chosen"] = _g
|
|
93
|
+
with open(_DIAG_PATH, "a") as _f:
|
|
94
|
+
_f.write(json.dumps(_diag_rec) + "\n")
|
|
95
|
+
return _g
|
|
96
|
+
if temperature and temperature != 1.0:
|
|
97
|
+
z = z / float(temperature)
|
|
98
|
+
|
|
99
|
+
keep = np.ones(z.shape[0], dtype=bool)
|
|
100
|
+
if top_k and 0 < top_k < z.shape[0]:
|
|
101
|
+
kth = np.partition(z, -top_k)[-top_k]
|
|
102
|
+
keep &= z >= kth # threshold keep — ties survive (HF semantics)
|
|
103
|
+
|
|
104
|
+
# softmax over the surviving set only, fp64-stable
|
|
105
|
+
zk = np.where(keep, z, -np.inf)
|
|
106
|
+
zk = zk - zk.max()
|
|
107
|
+
p = np.exp(zk)
|
|
108
|
+
p /= p.sum()
|
|
109
|
+
|
|
110
|
+
if top_p and 0.0 < top_p < 1.0:
|
|
111
|
+
# descending prob, ties by ascending vocab index (lexsort keys
|
|
112
|
+
# are last-key-major): smallest high-prob set reaching top_p.
|
|
113
|
+
order = np.lexsort((np.arange(p.shape[0]), -p))
|
|
114
|
+
csum = np.cumsum(p[order])
|
|
115
|
+
cut = int(np.searchsorted(csum, top_p, side="left")) + 1
|
|
116
|
+
nucleus = order[:cut]
|
|
117
|
+
mask = np.zeros(p.shape[0], dtype=bool)
|
|
118
|
+
mask[nucleus] = True
|
|
119
|
+
p = np.where(mask, p, 0.0)
|
|
120
|
+
p /= p.sum()
|
|
121
|
+
|
|
122
|
+
u = self._rng.random()
|
|
123
|
+
self.draws += 1
|
|
124
|
+
chosen = int(np.searchsorted(np.cumsum(p), u,
|
|
125
|
+
side="right").clip(0, p.shape[0] - 1))
|
|
126
|
+
if _diag_rec is not None:
|
|
127
|
+
_diag_rec["chosen"] = chosen
|
|
128
|
+
with open(_DIAG_PATH, "a") as _f:
|
|
129
|
+
_f.write(json.dumps(_diag_rec) + "\n")
|
|
130
|
+
return chosen
|
|
131
|
+
|
|
132
|
+
def draw_chattts(self, logits_fp64, temperature: float, top_p: float,
|
|
133
|
+
top_k: int, min_tokens_to_keep: int = 3,
|
|
134
|
+
seen_ids=None, repetition_penalty: float = 1.0,
|
|
135
|
+
penalty_window: int = 16,
|
|
136
|
+
eos_masked: bool = False, eos_id: int = -1) -> int:
|
|
137
|
+
"""Vendor-exact ChatTTS-class chain (MiniCPM-o tts contract,
|
|
138
|
+
modeling generate :4425-4462 + gen_logits :4994-5008):
|
|
139
|
+
temperature -> window-frequency penalty -> TopP (min_keep) ->
|
|
140
|
+
TopK (min_keep) -> optional eos -inf mask (min_new_token) ->
|
|
141
|
+
softmax -> ONE multinomial from the stream. Same seeded stream,
|
|
142
|
+
same draw-order contract as draw() (R30 coupling)."""
|
|
143
|
+
z = np.array(logits_fp64, dtype=np.float64).reshape(-1)
|
|
144
|
+
if temperature is not None and temperature <= 0:
|
|
145
|
+
return int(np.argmax(z)) # greedy contract
|
|
146
|
+
if temperature and temperature != 1.0:
|
|
147
|
+
z = z / float(temperature)
|
|
148
|
+
z = _chattts_window_penalty(z, seen_ids, repetition_penalty,
|
|
149
|
+
penalty_window)
|
|
150
|
+
_mk = max(1, int(min_tokens_to_keep))
|
|
151
|
+
# TopP FIRST (the vendor warper order), HF keep-set semantics +
|
|
152
|
+
# min_tokens_to_keep floor; ties by ascending vocab index.
|
|
153
|
+
if top_p and 0.0 < top_p < 1.0:
|
|
154
|
+
zs = z - z.max()
|
|
155
|
+
pf = np.exp(zs)
|
|
156
|
+
pf /= pf.sum()
|
|
157
|
+
order = np.lexsort((np.arange(pf.shape[0]), -pf))
|
|
158
|
+
csum = np.cumsum(pf[order])
|
|
159
|
+
cut = max(int(np.searchsorted(csum, top_p, side="left")) + 1,
|
|
160
|
+
_mk)
|
|
161
|
+
mask = np.zeros(pf.shape[0], dtype=bool)
|
|
162
|
+
mask[order[:cut]] = True
|
|
163
|
+
z = np.where(mask, z, -np.inf)
|
|
164
|
+
# TopK with the min_tokens_to_keep floor (HF: k = max(k, mk)).
|
|
165
|
+
if top_k and top_k > 0:
|
|
166
|
+
_k = min(max(int(top_k), _mk), z.shape[0])
|
|
167
|
+
kth = np.partition(z, -_k)[-_k]
|
|
168
|
+
z = np.where(z >= kth, z, -np.inf)
|
|
169
|
+
if eos_masked and 0 <= eos_id < z.shape[0]:
|
|
170
|
+
z[eos_id] = -np.inf # min_new_token contract
|
|
171
|
+
_diag_rec = None
|
|
172
|
+
if _DIAG_PATH:
|
|
173
|
+
_t4 = np.argsort(z)[::-1][:4]
|
|
174
|
+
_diag_rec = {
|
|
175
|
+
"n": self.draws, "class": "chattts",
|
|
176
|
+
"top4": [[int(i), round(float(z[i]), 6)] for i in _t4],
|
|
177
|
+
"margin": round(float(z[_t4[0]] - z[_t4[1]]), 6)
|
|
178
|
+
if _t4.size > 1 else None,
|
|
179
|
+
}
|
|
180
|
+
zk = z - z[np.isfinite(z)].max()
|
|
181
|
+
p = np.exp(zk)
|
|
182
|
+
p[~np.isfinite(zk)] = 0.0
|
|
183
|
+
p /= p.sum()
|
|
184
|
+
u = self._rng.random()
|
|
185
|
+
self.draws += 1
|
|
186
|
+
chosen = int(np.searchsorted(np.cumsum(p), u,
|
|
187
|
+
side="right").clip(0, p.shape[0] - 1))
|
|
188
|
+
if _diag_rec is not None:
|
|
189
|
+
_diag_rec["chosen"] = chosen
|
|
190
|
+
with open(_DIAG_PATH, "a") as _f:
|
|
191
|
+
_f.write(json.dumps(_diag_rec) + "\n")
|
|
192
|
+
return chosen
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def seeded_gaussian(seed: int, shape) -> np.ndarray:
|
|
196
|
+
"""Seeded fp32 standard-normal draw — the latent-init twin of
|
|
197
|
+
SeededDrawStream. ONE stream (PCG64(seed), native-fp32 ziggurat) on
|
|
198
|
+
the CPU; both engines consume the SAME array, so generative
|
|
199
|
+
diffusion legs start from bit-identical noise whenever seed and
|
|
200
|
+
shape agree. This is the cross-engine coupling contract for
|
|
201
|
+
image/video latent init, exactly as the draw stream is for sampled
|
|
202
|
+
tokens: the engines may only diverge through compute numerics,
|
|
203
|
+
never through RNG provenance."""
|
|
204
|
+
return np.random.default_rng(int(seed)).standard_normal(
|
|
205
|
+
size=tuple(int(d) for d in shape), dtype=np.float32)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def _chattts_window_penalty(z: np.ndarray, seen_ids, penalty: float,
|
|
209
|
+
window: int) -> np.ndarray:
|
|
210
|
+
"""ChatTTS-class repetition penalty (vendor
|
|
211
|
+
CustomRepetitionPenaltyLogitsProcessorRepeat): alpha = penalty^freq
|
|
212
|
+
over the last `window` draws; negative logits multiply by alpha,
|
|
213
|
+
non-negative divide. Distinct from the HF processor (seen-set,
|
|
214
|
+
freq-blind) — declared per contract as repetition_penalty_class."""
|
|
215
|
+
if not penalty or penalty == 1.0 or not seen_ids:
|
|
216
|
+
return z
|
|
217
|
+
ids = np.asarray(list(seen_ids)[-int(window):], dtype=np.int64)
|
|
218
|
+
ids = ids[(ids >= 0) & (ids < z.shape[0])]
|
|
219
|
+
if ids.size == 0:
|
|
220
|
+
return z
|
|
221
|
+
freq = np.bincount(ids, minlength=z.shape[0]).astype(np.float64)
|
|
222
|
+
alpha = np.power(float(penalty), freq)
|
|
223
|
+
return np.where(z < 0, z * alpha, z / alpha)
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"""Shapes, strides and views as pure functions on integers.
|
|
2
|
+
|
|
3
|
+
Every rule a tensor's layout follows lives here once, and `Tensor` calls it: how many elements a shape holds,
|
|
4
|
+
the row-major strides of a shape, whether a layout is contiguous, the strides of a view (ATen's `computeStride`),
|
|
5
|
+
broadcasting, slice bounds, and the largest offset a strided layout reaches. Integers in, integers out: the
|
|
6
|
+
functions read no device, no dtype and no global state (R-NBXT 11), so a Rust core can take them over unchanged.
|
|
7
|
+
|
|
8
|
+
Strides are in ELEMENTS, never bytes.
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from typing import Optional, Sequence, Tuple
|
|
13
|
+
|
|
14
|
+
__all__ = ["numel", "contiguous_strides", "is_contiguous", "view_strides", "broadcast_shapes",
|
|
15
|
+
"broadcast_strides", "slice_bounds", "max_linear_offset", "MAX_NDIM"]
|
|
16
|
+
|
|
17
|
+
# PyTorch's bound on the rank an op iterates (aten/src/ATen/TensorIterator.h, `MAX_DIMS == 25`); a kernel launch
|
|
18
|
+
# beyond it is refused, never truncated.
|
|
19
|
+
MAX_NDIM = 25
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def numel(shape: Sequence[int]) -> int:
|
|
23
|
+
"""The number of elements of `shape`: the product of its extents, 1 for the empty shape (a scalar)."""
|
|
24
|
+
n = 1
|
|
25
|
+
for d in shape:
|
|
26
|
+
n *= int(d)
|
|
27
|
+
return n
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def contiguous_strides(shape: Sequence[int]) -> Tuple[int, ...]:
|
|
31
|
+
"""The row-major strides of `shape`, last dim fastest."""
|
|
32
|
+
if len(shape) == 0:
|
|
33
|
+
return ()
|
|
34
|
+
strides = [1] * len(shape)
|
|
35
|
+
for i in range(len(shape) - 2, -1, -1):
|
|
36
|
+
strides[i] = strides[i + 1] * shape[i + 1]
|
|
37
|
+
return tuple(strides)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def is_contiguous(shape: Sequence[int], strides: Sequence[int]) -> bool:
|
|
41
|
+
"""PyTorch's contiguity: the elements lie row-major without gaps; a dim of extent 1 may carry any stride (it is
|
|
42
|
+
never walked) and an empty tensor is contiguous. Comparing the strides to the canonical ones instead called a
|
|
43
|
+
decode-step view such as (1, 32, 64, 1) with strides (2048, 64, 1, 64) — a transposed single-token head block —
|
|
44
|
+
non-contiguous and copied it before every element-wise kernel (NeuroBrix's copy census of 2026-09-07)."""
|
|
45
|
+
expected = 1
|
|
46
|
+
for extent, stride in zip(reversed(shape), reversed(strides)):
|
|
47
|
+
if extent == 0:
|
|
48
|
+
return True
|
|
49
|
+
if extent == 1:
|
|
50
|
+
continue
|
|
51
|
+
if stride != expected:
|
|
52
|
+
return False
|
|
53
|
+
expected *= extent
|
|
54
|
+
return True
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def view_strides(old_shape: Sequence[int], old_strides: Sequence[int],
|
|
58
|
+
new_shape: Sequence[int]) -> Optional[list]:
|
|
59
|
+
"""The strides `new_shape` takes as a VIEW of a tensor laid out as (`old_shape`, `old_strides`), or None when no
|
|
60
|
+
view exists — ATen's own rule (aten/src/ATen/TensorUtils.cpp `computeStride`): the old dims are walked in chunks
|
|
61
|
+
of contiguous runs, and a new dim must fall inside one chunk."""
|
|
62
|
+
total = numel(old_shape)
|
|
63
|
+
if total == 0 or not old_shape:
|
|
64
|
+
return None
|
|
65
|
+
new_strides = [0] * len(new_shape)
|
|
66
|
+
view_d = len(new_shape) - 1
|
|
67
|
+
chunk_base = old_strides[-1]
|
|
68
|
+
tensor_numel = view_numel = 1
|
|
69
|
+
for tensor_d in range(len(old_shape) - 1, -1, -1):
|
|
70
|
+
tensor_numel *= old_shape[tensor_d]
|
|
71
|
+
if tensor_d == 0 or (old_shape[tensor_d - 1] != 1
|
|
72
|
+
and old_strides[tensor_d - 1] != tensor_numel * chunk_base):
|
|
73
|
+
while view_d >= 0 and (view_numel < tensor_numel or new_shape[view_d] == 1):
|
|
74
|
+
new_strides[view_d] = view_numel * chunk_base
|
|
75
|
+
view_numel *= new_shape[view_d]
|
|
76
|
+
view_d -= 1
|
|
77
|
+
if view_numel != tensor_numel:
|
|
78
|
+
return None
|
|
79
|
+
if tensor_d > 0:
|
|
80
|
+
chunk_base = old_strides[tensor_d - 1]
|
|
81
|
+
tensor_numel = view_numel = 1
|
|
82
|
+
return new_strides if view_d == -1 else None
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def broadcast_shapes(*shapes: Sequence[int]) -> Tuple[int, ...]:
|
|
86
|
+
"""The shape two or more shapes broadcast to (numpy's rule: right-aligned, an extent of 1 stretches); shapes
|
|
87
|
+
that do not broadcast are refused by name."""
|
|
88
|
+
if len(shapes) == 1:
|
|
89
|
+
return tuple(shapes[0])
|
|
90
|
+
result = tuple(shapes[0])
|
|
91
|
+
for s in shapes[1:]:
|
|
92
|
+
s = tuple(s)
|
|
93
|
+
ndim = max(len(result), len(s))
|
|
94
|
+
a = (1,) * (ndim - len(result)) + result
|
|
95
|
+
b = (1,) * (ndim - len(s)) + s
|
|
96
|
+
new = []
|
|
97
|
+
for sa, sb in zip(a, b):
|
|
98
|
+
if sa == sb:
|
|
99
|
+
new.append(sa)
|
|
100
|
+
elif sa == 1:
|
|
101
|
+
new.append(sb)
|
|
102
|
+
elif sb == 1:
|
|
103
|
+
new.append(sa)
|
|
104
|
+
else:
|
|
105
|
+
raise ValueError(f"Cannot broadcast {result} and {s}")
|
|
106
|
+
result = tuple(new)
|
|
107
|
+
return result
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def broadcast_strides(shape: Sequence[int], strides: Sequence[int],
|
|
111
|
+
target: Sequence[int]) -> Tuple[Tuple[int, ...], Tuple[int, ...]]:
|
|
112
|
+
"""(shape, strides) of the layout (`shape`, `strides`) EXPANDED to `target` without a copy: leading dims are
|
|
113
|
+
prepended with extent 1, a dim of extent 1 stretches with stride 0, an entry of -1 keeps the dim as it is
|
|
114
|
+
(ATen `expand`)."""
|
|
115
|
+
pad = len(target) - len(shape)
|
|
116
|
+
old_s = (1,) * pad + tuple(shape)
|
|
117
|
+
old_st = (0,) * pad + tuple(strides)
|
|
118
|
+
new_s, new_st = [], []
|
|
119
|
+
for i, s in enumerate(target):
|
|
120
|
+
if s == -1:
|
|
121
|
+
new_s.append(old_s[i])
|
|
122
|
+
new_st.append(old_st[i])
|
|
123
|
+
elif old_s[i] == 1:
|
|
124
|
+
new_s.append(s)
|
|
125
|
+
new_st.append(0)
|
|
126
|
+
else:
|
|
127
|
+
new_s.append(s)
|
|
128
|
+
new_st.append(old_st[i])
|
|
129
|
+
return tuple(new_s), tuple(new_st)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def slice_bounds(start: Optional[int], stop: Optional[int], size: int, step: Optional[int] = None) -> Tuple[int, int]:
|
|
133
|
+
"""(start, stop) of a slice over an axis of `size`, as torch and numpy read it: negative bounds count from the
|
|
134
|
+
end, and both bounds are CLAMPED to [0, size] — [50:80] over 60 rows is rows 50..59. Unclamped, a stop past the
|
|
135
|
+
extent read past the tensor's storage (CogVideoX's last VAE tiles in NeuroBrix, 2026-10-17). A step other than 1
|
|
136
|
+
is refused by name."""
|
|
137
|
+
if step not in (None, 1):
|
|
138
|
+
raise RuntimeError(f"ZERO FALLBACK: slicing with step {step} is not supported (narrow only)")
|
|
139
|
+
start = 0 if start is None else int(start)
|
|
140
|
+
stop = size if stop is None else int(stop)
|
|
141
|
+
if start < 0:
|
|
142
|
+
start += size
|
|
143
|
+
if stop < 0:
|
|
144
|
+
stop += size
|
|
145
|
+
start = min(max(start, 0), size)
|
|
146
|
+
stop = min(max(stop, start), size)
|
|
147
|
+
return start, stop
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def max_linear_offset(shape: Sequence[int], strides: Sequence[int]) -> int:
|
|
151
|
+
"""The largest element offset a strided layout reaches — what a kernel's index arithmetic must be wide enough
|
|
152
|
+
for."""
|
|
153
|
+
total = 0
|
|
154
|
+
for extent, stride in zip(shape, strides):
|
|
155
|
+
if extent > 0:
|
|
156
|
+
total += (int(extent) - 1) * abs(int(stride))
|
|
157
|
+
return total
|