flashrt-structures 0.2.0__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.
- flashrt_structures/__init__.py +174 -0
- flashrt_structures/adapters/__init__.py +55 -0
- flashrt_structures/adapters/diffusers_attention.py +237 -0
- flashrt_structures/adapters/diffusers_rotary_attention.py +239 -0
- flashrt_structures/adapters/factored_qk_norm_rope.py +252 -0
- flashrt_structures/adapters/factored_two_way_attention.py +99 -0
- flashrt_structures/adapters/gemma_attention.py +226 -0
- flashrt_structures/adapters/packed_qkv_rope.py +342 -0
- flashrt_structures/adapters/packed_stream_qk_norm_rope.py +376 -0
- flashrt_structures/adapters/qwen_per_head_qk_norm_rope.py +231 -0
- flashrt_structures/adapters/sglang_engine.py +207 -0
- flashrt_structures/adapters/transformers_attention_interface.py +73 -0
- flashrt_structures/adapters/transformers_gated_delta.py +152 -0
- flashrt_structures/adapters/transformers_gated_delta_fused.py +96 -0
- flashrt_structures/adapters/vllm_engine.py +424 -0
- flashrt_structures/adjudicate.py +85 -0
- flashrt_structures/aot.py +191 -0
- flashrt_structures/autobuild.py +2052 -0
- flashrt_structures/beta/__init__.py +43 -0
- flashrt_structures/beta/conform.py +94 -0
- flashrt_structures/beta/joins.py +113 -0
- flashrt_structures/beta/negotiate.py +84 -0
- flashrt_structures/beta/ports.py +140 -0
- flashrt_structures/decisions.py +80 -0
- flashrt_structures/discover.py +623 -0
- flashrt_structures/explain.py +70 -0
- flashrt_structures/frontdoor.py +572 -0
- flashrt_structures/gates.py +465 -0
- flashrt_structures/guard.py +421 -0
- flashrt_structures/handle.py +189 -0
- flashrt_structures/impls/__init__.py +219 -0
- flashrt_structures/impls/adaln_producer/__init__.py +8 -0
- flashrt_structures/impls/adaln_producer/broker.py +116 -0
- flashrt_structures/impls/adaln_producer/fused.py +388 -0
- flashrt_structures/impls/adarms_stack/__init__.py +8 -0
- flashrt_structures/impls/adarms_stack/fp8_chain.py +832 -0
- flashrt_structures/impls/adarms_stack/region.py +102 -0
- flashrt_structures/impls/attention_core/__init__.py +132 -0
- flashrt_structures/impls/attention_core/fa2_seqused.py +458 -0
- flashrt_structures/impls/attention_core/fa4_cute.py +154 -0
- flashrt_structures/impls/attention_core/fa4_fp8.py +178 -0
- flashrt_structures/impls/attention_core/masked_mha.py +158 -0
- flashrt_structures/impls/attention_core/two_way_fa2.py +220 -0
- flashrt_structures/impls/cadence_static/__init__.py +18 -0
- flashrt_structures/impls/cadence_static/buffers.py +122 -0
- flashrt_structures/impls/cadence_static/cross_attention.py +187 -0
- flashrt_structures/impls/chain_elements.py +89 -0
- flashrt_structures/impls/decode_loop/__init__.py +0 -0
- flashrt_structures/impls/decode_loop/fp8_kv.py +206 -0
- flashrt_structures/impls/decode_loop/mtp_speculative.py +245 -0
- flashrt_structures/impls/decode_loop/whole_step.py +852 -0
- flashrt_structures/impls/decoder_block/__init__.py +6 -0
- flashrt_structures/impls/decoder_block/attn_sublayer.py +110 -0
- flashrt_structures/impls/decoder_block/fused.py +167 -0
- flashrt_structures/impls/decoder_ffn/__init__.py +0 -0
- flashrt_structures/impls/decoder_ffn/fp8_static.py +310 -0
- flashrt_structures/impls/decoder_ffn/fp8_static.yaml +22 -0
- flashrt_structures/impls/decoder_ffn/w4a16_static.py +221 -0
- flashrt_structures/impls/decoder_ffn/w8a16_static.py +183 -0
- flashrt_structures/impls/dit_stack/__init__.py +11 -0
- flashrt_structures/impls/dit_stack/fp4_chain.py +417 -0
- flashrt_structures/impls/dit_stack/region.py +86 -0
- flashrt_structures/impls/fixed_iter/__init__.py +29 -0
- flashrt_structures/impls/fixed_iter/openpi.py +264 -0
- flashrt_structures/impls/fixed_iter/protocol.py +94 -0
- flashrt_structures/impls/gated_delta_core/__init__.py +3 -0
- flashrt_structures/impls/gated_delta_core/fused_layer.py +545 -0
- flashrt_structures/impls/gated_delta_core/hub_v3.py +152 -0
- flashrt_structures/impls/graph_lowering/__init__.py +27 -0
- flashrt_structures/impls/graph_lowering/pi052_denoise.py +179 -0
- flashrt_structures/impls/graph_lowering/protocol.py +76 -0
- flashrt_structures/impls/graph_lowering/qwen3_vl.py +364 -0
- flashrt_structures/impls/linear_proj/__init__.py +0 -0
- flashrt_structures/impls/linear_proj/fp8_static.py +270 -0
- flashrt_structures/impls/linear_proj/nvfp4_balance.py +131 -0
- flashrt_structures/impls/linear_proj/nvfp4_dynamic.py +182 -0
- flashrt_structures/impls/linear_proj/w8a16_static.py +230 -0
- flashrt_structures/impls/modnorm_qkv_chain/__init__.py +0 -0
- flashrt_structures/impls/modnorm_qkv_chain/fp8_ptok_table.py +291 -0
- flashrt_structures/impls/moe_experts/__init__.py +9 -0
- flashrt_structures/impls/moe_experts/nvfp4_dynamic.py +208 -0
- flashrt_structures/impls/moe_experts/nvfp4_w4a16.py +129 -0
- flashrt_structures/impls/norm_fused/__init__.py +3 -0
- flashrt_structures/impls/norm_fused/bf16.py +94 -0
- flashrt_structures/impls/norm_fused/fp8_producer.py +84 -0
- flashrt_structures/impls/patch_projection/__init__.py +3 -0
- flashrt_structures/impls/patch_projection/bf16_flat.py +139 -0
- flashrt_structures/impls/prefill_tower/__init__.py +10 -0
- flashrt_structures/impls/prefill_tower/fp8_chain.py +955 -0
- flashrt_structures/impls/prefill_tower/region.py +99 -0
- flashrt_structures/impls/qk_norm_rope/__init__.py +12 -0
- flashrt_structures/impls/qk_norm_rope/per_head_gqa.py +199 -0
- flashrt_structures/impls/qk_norm_rope/projection_bf16.py +165 -0
- flashrt_structures/impls/qkv_pack/__init__.py +5 -0
- flashrt_structures/impls/qkv_pack/bf16.py +110 -0
- flashrt_structures/impls/qkv_pack/fp8_static.py +435 -0
- flashrt_structures/impls/qkv_pack/nvfp4_balance.py +218 -0
- flashrt_structures/impls/qkv_rope/__init__.py +3 -0
- flashrt_structures/impls/qkv_rope/packed_bias_bf16.py +143 -0
- flashrt_structures/impls/step_table.py +113 -0
- flashrt_structures/impls/vision_ffn/__init__.py +0 -0
- flashrt_structures/impls/vision_ffn/fp8_static.py +261 -0
- flashrt_structures/impls/vision_ffn/nvfp4_balance.py +211 -0
- flashrt_structures/impls/vision_tower/__init__.py +7 -0
- flashrt_structures/impls/vision_tower/fp8_chain.py +533 -0
- flashrt_structures/impls/vision_tower/region.py +91 -0
- flashrt_structures/matrix.py +126 -0
- flashrt_structures/points.py +368 -0
- flashrt_structures/prequantized.py +131 -0
- flashrt_structures/quantize_on_adopt.py +94 -0
- flashrt_structures/recipe.py +438 -0
- flashrt_structures/regions.py +208 -0
- flashrt_structures/schemes.py +490 -0
- flashrt_structures/stages.py +298 -0
- flashrt_structures/storage.py +255 -0
- flashrt_structures/swap.py +398 -0
- flashrt_structures/workspace.py +110 -0
- flashrt_structures-0.2.0.dist-info/METADATA +140 -0
- flashrt_structures-0.2.0.dist-info/RECORD +122 -0
- flashrt_structures-0.2.0.dist-info/WHEEL +5 -0
- flashrt_structures-0.2.0.dist-info/licenses/LICENSE +202 -0
- flashrt_structures-0.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
"""The fused static-FP8 launch chain over a biased vision tower.
|
|
2
|
+
|
|
3
|
+
Per layer: LayerNorm→FP8 with the affine pair in the kernel, one
|
|
4
|
+
merged-QKV FP8 GEMM with the bias in the epilogue, dense per-call
|
|
5
|
+
attention (no cache, no mask — the patch sequence is full and
|
|
6
|
+
unpadded), and the output/down projections carry their bias *and*
|
|
7
|
+
the residual add in the GEMM epilogue — the native vision form,
|
|
8
|
+
kernel for kernel. The activation quantizer sites are calibrated on
|
|
9
|
+
the probe run against the pristine host.
|
|
10
|
+
|
|
11
|
+
The attention element is a ladder: the house FA4 entry probed at the
|
|
12
|
+
bound head shape first, plain SDPA as the floor — SDPA is a single
|
|
13
|
+
capture-safe primitive and this tower's attention is a small slice
|
|
14
|
+
of its time; the GEMM epilogues are where the native form wins.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import types
|
|
20
|
+
from typing import Any, Callable
|
|
21
|
+
|
|
22
|
+
import torch
|
|
23
|
+
|
|
24
|
+
from .. import KernelUnavailable, hub_kernel
|
|
25
|
+
from ...guard import GuardedSeam
|
|
26
|
+
from ..chain_elements import (
|
|
27
|
+
fp8_weight as _fp8_weight, gelu_tanh_like as _gelu_tanh_like)
|
|
28
|
+
|
|
29
|
+
GEMM_PACKAGE = "flashrt/fp8-gemm"
|
|
30
|
+
FUSE_PACKAGE = "flashrt/transformer-fused-ops"
|
|
31
|
+
GEMM_SYMBOLS = ("fp8_linear_bias_bf16", "fp8_linear_bias_residual_bf16",
|
|
32
|
+
"fp8_linear_bias_gelu_bf16")
|
|
33
|
+
FP4_GEMM_PACKAGE = "flashrt/fp4-gemm"
|
|
34
|
+
FP4_FUSE_PACKAGE = "flashrt/fp4-fused-ops"
|
|
35
|
+
|
|
36
|
+
#: the band table IS the recipe (house convention). The ``fp4`` row is
|
|
37
|
+
#: the native SigLIP preset: the FFN pair rides NVFP4 — the LN
|
|
38
|
+
#: producer emits packed FP4, FC1 fuses bias+GELU and emits packed FP4
|
|
39
|
+
#: straight into FC2's residual GEMM. The attention half stays FP8.
|
|
40
|
+
BANDS: dict[str, dict] = {
|
|
41
|
+
"fp8": {"packages": (), "precision_rank": 0},
|
|
42
|
+
"fp4": {"packages": (
|
|
43
|
+
(FP4_GEMM_PACKAGE, ("nvfp4_gemm_bias_bf16",
|
|
44
|
+
"nvfp4_gemm_bias_residual_bf16",
|
|
45
|
+
"quantize_fp4_sfa_bf16",
|
|
46
|
+
"pack_nvfp4_weight_bf16")),
|
|
47
|
+
(FP4_FUSE_PACKAGE, ("layer_norm_nvfp4_bf16",))),
|
|
48
|
+
"precision_rank": 1, "awq": 0.8},
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
FUSE_SYMBOLS = ("layer_norm_quant_fp8_static_bf16",
|
|
52
|
+
"quantize_fp8_static_bf16")
|
|
53
|
+
FA4_REPO = "flashrt/fa4-cute-runtime"
|
|
54
|
+
|
|
55
|
+
SMOKE_FLOOR = 0.97
|
|
56
|
+
FP8_MAX = 448.0
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def missing_symbols(band: str = "fp8") -> list[str]:
|
|
60
|
+
gaps: list[str] = []
|
|
61
|
+
for repo, symbols in ((GEMM_PACKAGE, GEMM_SYMBOLS),
|
|
62
|
+
(FUSE_PACKAGE, FUSE_SYMBOLS)
|
|
63
|
+
) + BANDS[band]["packages"]:
|
|
64
|
+
try:
|
|
65
|
+
kern = hub_kernel(repo, ">=1")
|
|
66
|
+
except KernelUnavailable:
|
|
67
|
+
gaps.append(repo)
|
|
68
|
+
continue
|
|
69
|
+
gaps.extend(f"{repo}:{s}" for s in symbols
|
|
70
|
+
if not hasattr(kern, s))
|
|
71
|
+
return gaps
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class BoundVisionFp8Chain(GuardedSeam, torch.nn.Module):
|
|
75
|
+
"""Bind-time state: FP8 weights with epilogue biases, buffers."""
|
|
76
|
+
|
|
77
|
+
_frt_can_fallback = False
|
|
78
|
+
|
|
79
|
+
def __init__(self) -> None:
|
|
80
|
+
super().__init__()
|
|
81
|
+
self.table: list[dict] = []
|
|
82
|
+
self.dims: dict = {}
|
|
83
|
+
self.buf: dict = {}
|
|
84
|
+
self.scaling = 1.0
|
|
85
|
+
self.out_ctor = None
|
|
86
|
+
self.out_dtype = None
|
|
87
|
+
self.kernels: dict = {}
|
|
88
|
+
self.band = "fp8"
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _stack_parts(stack):
|
|
92
|
+
layers = list(stack.layers)
|
|
93
|
+
attn = layers[0].self_attn
|
|
94
|
+
dim = attn.q_proj.in_features
|
|
95
|
+
heads = getattr(attn, "num_heads", None)
|
|
96
|
+
if not isinstance(heads, int):
|
|
97
|
+
head_dim = getattr(attn, "head_dim", None)
|
|
98
|
+
if not isinstance(head_dim, int):
|
|
99
|
+
raise ValueError("attention exposes neither num_heads "
|
|
100
|
+
"nor head_dim")
|
|
101
|
+
heads = dim // head_dim
|
|
102
|
+
hidden = layers[0].mlp.fc1.out_features
|
|
103
|
+
return layers, heads, dim // heads, dim, hidden
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _awq_scale(chan_amax: torch.Tensor, alpha: float) -> torch.Tensor:
|
|
107
|
+
"""Native per-input-channel AWQ pre-scale, verbatim:
|
|
108
|
+
s = (a / a.mean())^alpha clamped to [0.25, 4]."""
|
|
109
|
+
a = chan_amax.float().clamp(min=1e-6)
|
|
110
|
+
return (a / a.mean()).pow(alpha).clamp(min=0.25, max=4.0)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@torch.no_grad()
|
|
114
|
+
def _quantize(bound, layers, amax, chan=None) -> None:
|
|
115
|
+
alpha = BANDS[bound.band].get("awq", 0.0)
|
|
116
|
+
for i, ly in enumerate(layers):
|
|
117
|
+
attn, mlp = ly.self_attn, ly.mlp
|
|
118
|
+
a_qkv, a_o, a_fc1, a_fc2 = (amax[(i, s)] / FP8_MAX for s in
|
|
119
|
+
("qkv", "o", "fc1", "fc2"))
|
|
120
|
+
qkv_w = torch.cat([attn.q_proj.weight, attn.k_proj.weight,
|
|
121
|
+
attn.v_proj.weight], dim=0)
|
|
122
|
+
qkv_b = torch.cat([attn.q_proj.bias, attn.k_proj.bias,
|
|
123
|
+
attn.v_proj.bias], dim=0)
|
|
124
|
+
entry: dict[str, Any] = {}
|
|
125
|
+
fp4 = BANDS[bound.band]["packages"] != ()
|
|
126
|
+
pack4 = (bound.kernels["kg4"].pack_nvfp4_weight_bf16
|
|
127
|
+
if fp4 else None)
|
|
128
|
+
for name, w, bias, act in (
|
|
129
|
+
("qkv", qkv_w, None, a_qkv),
|
|
130
|
+
("o", attn.out_proj.weight, None, a_o),
|
|
131
|
+
("fc1", mlp.fc1.weight, mlp.fc1.bias, a_fc1),
|
|
132
|
+
("fc2", mlp.fc2.weight, mlp.fc2.bias, a_fc2)):
|
|
133
|
+
if fp4 and name in ("fc1", "fc2"):
|
|
134
|
+
# the padded pack carries SigLIP's logical 4304 as the
|
|
135
|
+
# physical aligned width; FC1's FP4 output is born at
|
|
136
|
+
# that width, so FC2 consumes it with zero glue. The
|
|
137
|
+
# native tier rides AWQ on the up (FC1) weight only:
|
|
138
|
+
# s into the columns, 1/s carried by the LN producer.
|
|
139
|
+
w = w.detach().to("cuda", torch.float32)
|
|
140
|
+
if (alpha and name == "fc1" and chan is not None
|
|
141
|
+
and (i, "fc1") in chan):
|
|
142
|
+
s = _awq_scale(chan[(i, "fc1")].to("cuda"), alpha)
|
|
143
|
+
w = w * s[None, :]
|
|
144
|
+
entry["inv_s_fc1"] = (1.0 / s).to(
|
|
145
|
+
torch.bfloat16).contiguous()
|
|
146
|
+
wp, wsf, pb, _ = pack4(
|
|
147
|
+
w.to(torch.bfloat16).contiguous(),
|
|
148
|
+
bias.detach().to("cuda", torch.bfloat16)
|
|
149
|
+
.contiguous(), mse=True)
|
|
150
|
+
entry[name] = (wp, wsf)
|
|
151
|
+
entry[f"{name}_b"] = pb
|
|
152
|
+
continue
|
|
153
|
+
packed, w_scale = _fp8_weight(w)
|
|
154
|
+
entry[name] = packed
|
|
155
|
+
entry[f"a_{name}"] = act * w_scale
|
|
156
|
+
for name, b in (("qkv_b", qkv_b), ("o_b", attn.out_proj.bias),
|
|
157
|
+
("fc1_b", mlp.fc1.bias), ("fc2_b", mlp.fc2.bias)):
|
|
158
|
+
if name in entry:
|
|
159
|
+
continue
|
|
160
|
+
entry[name] = b.detach().to("cuda", torch.bfloat16)
|
|
161
|
+
for name, norm in (("ln1", ly.layer_norm1),
|
|
162
|
+
("ln2", ly.layer_norm2)):
|
|
163
|
+
entry[f"{name}_w"] = norm.weight.detach().to(
|
|
164
|
+
"cuda", torch.bfloat16)
|
|
165
|
+
entry[f"{name}_b"] = norm.bias.detach().to(
|
|
166
|
+
"cuda", torch.bfloat16)
|
|
167
|
+
entry[f"{name}_eps"] = float(getattr(norm, "eps", 1e-6))
|
|
168
|
+
entry["sc_qkv"] = torch.tensor([a_qkv], device="cuda",
|
|
169
|
+
dtype=torch.float32)
|
|
170
|
+
entry["sc_o"] = torch.tensor([a_o], device="cuda",
|
|
171
|
+
dtype=torch.float32)
|
|
172
|
+
entry["sc_fc1"] = torch.tensor([a_fc1], device="cuda",
|
|
173
|
+
dtype=torch.float32)
|
|
174
|
+
entry["sc_fc2"] = torch.tensor([a_fc2], device="cuda",
|
|
175
|
+
dtype=torch.float32)
|
|
176
|
+
bound.table.append(entry)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _make_attend(bound, mode: str, kern):
|
|
180
|
+
nh, hd = bound.dims["nh"], bound.dims["hd"]
|
|
181
|
+
scaling = bound.scaling
|
|
182
|
+
if mode == "fa4_cute":
|
|
183
|
+
def attend(q, k, v):
|
|
184
|
+
out = torch.empty_like(q)
|
|
185
|
+
kern.forward_static(q, k, v, out, softmax_scale=scaling,
|
|
186
|
+
causal=False)
|
|
187
|
+
return out
|
|
188
|
+
return attend
|
|
189
|
+
|
|
190
|
+
def attend(q, k, v):
|
|
191
|
+
o = torch.nn.functional.scaled_dot_product_attention(
|
|
192
|
+
q.transpose(1, 2), k.transpose(1, 2), v.transpose(1, 2),
|
|
193
|
+
scale=scaling)
|
|
194
|
+
return o.transpose(1, 2)
|
|
195
|
+
return attend
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def _make_run(bound: BoundVisionFp8Chain):
|
|
199
|
+
kg = bound.kernels["kg"]
|
|
200
|
+
kf = bound.kernels["kf"]
|
|
201
|
+
attend = bound.kernels["attend"]
|
|
202
|
+
B, S, nh, hd, D, H = (bound.dims[k] for k in
|
|
203
|
+
("batch", "seq", "nh", "hd", "dim",
|
|
204
|
+
"hidden"))
|
|
205
|
+
b = bound.buf
|
|
206
|
+
table = bound.table
|
|
207
|
+
rf = torch.profiler.record_function
|
|
208
|
+
|
|
209
|
+
if BANDS[bound.band]["packages"] != ():
|
|
210
|
+
kg4 = bound.kernels["kg4"]
|
|
211
|
+
kf4 = bound.kernels["kf4"]
|
|
212
|
+
ln4 = kf4.layer_norm_nvfp4_bf16
|
|
213
|
+
gemm_res4 = kg4.nvfp4_gemm_bias_residual_bf16
|
|
214
|
+
quant4 = kg4.quantize_fp4_sfa_bf16
|
|
215
|
+
xp4, xsf4 = b["xp4"], b["xsf4"]
|
|
216
|
+
hp4, hsf4 = b["hp4"], b["hsf4"]
|
|
217
|
+
e0 = table[0]
|
|
218
|
+
# FC1 element ladder, bind-time facts (shape and device, never
|
|
219
|
+
# a device list): the fused FP4-out epilogue, then the fused
|
|
220
|
+
# bf16-GELU epilogue, then the plain bias GEMM with the GELU
|
|
221
|
+
# and quantize as separate elements.
|
|
222
|
+
def _try(fn, *args, **kw):
|
|
223
|
+
try:
|
|
224
|
+
fn(*args, **kw)
|
|
225
|
+
torch.cuda.synchronize()
|
|
226
|
+
return fn
|
|
227
|
+
except Exception: # noqa: BLE001 — next rung
|
|
228
|
+
return None
|
|
229
|
+
|
|
230
|
+
fused4 = getattr(kg4, "nvfp4_gemm_bias_gelu_nvfp4", None)
|
|
231
|
+
if fused4 is not None:
|
|
232
|
+
fused4 = _try(fused4, xp4, e0["fc1"][0], xsf4,
|
|
233
|
+
e0["fc1"][1], e0["fc1_b"],
|
|
234
|
+
out_packed=hp4, out_sfa=hsf4)
|
|
235
|
+
fusedb = getattr(kg4, "nvfp4_gemm_bias_gelu_bf16", None)
|
|
236
|
+
if fused4 is None and fusedb is not None:
|
|
237
|
+
fusedb = _try(fusedb, xp4, e0["fc1"][0], xsf4,
|
|
238
|
+
e0["fc1"][1], e0["fc1_b"], out=b["hid"])
|
|
239
|
+
else:
|
|
240
|
+
fusedb = None
|
|
241
|
+
|
|
242
|
+
if fused4 is not None:
|
|
243
|
+
def ffn(res, e):
|
|
244
|
+
ln4(res, e["ln2_w"], e["ln2_b"], e.get("inv_s_fc1"),
|
|
245
|
+
e["ln2_eps"], packed=xp4, sfa=xsf4)
|
|
246
|
+
fused4(xp4, e["fc1"][0], xsf4, e["fc1"][1],
|
|
247
|
+
e["fc1_b"], out_packed=hp4, out_sfa=hsf4)
|
|
248
|
+
gemm_res4(hp4, e["fc2"][0], hsf4, e["fc2"][1],
|
|
249
|
+
e["fc2_b"], res, out=res)
|
|
250
|
+
elif fusedb is not None:
|
|
251
|
+
def ffn(res, e):
|
|
252
|
+
ln4(res, e["ln2_w"], e["ln2_b"], e.get("inv_s_fc1"),
|
|
253
|
+
e["ln2_eps"], packed=xp4, sfa=xsf4)
|
|
254
|
+
fusedb(xp4, e["fc1"][0], xsf4, e["fc1"][1],
|
|
255
|
+
e["fc1_b"], out=b["hid"])
|
|
256
|
+
quant4(b["hid"], hp4, hsf4)
|
|
257
|
+
gemm_res4(hp4, e["fc2"][0], hsf4, e["fc2"][1],
|
|
258
|
+
e["fc2_b"], res, out=res)
|
|
259
|
+
else:
|
|
260
|
+
gemm_bias4 = kg4.nvfp4_gemm_bias_bf16
|
|
261
|
+
gelu = torch.nn.functional.gelu
|
|
262
|
+
|
|
263
|
+
def ffn(res, e):
|
|
264
|
+
ln4(res, e["ln2_w"], e["ln2_b"], e.get("inv_s_fc1"),
|
|
265
|
+
e["ln2_eps"], packed=xp4, sfa=xsf4)
|
|
266
|
+
gemm_bias4(xp4, e["fc1"][0], xsf4, e["fc1"][1],
|
|
267
|
+
e["fc1_b"], out=b["hid"])
|
|
268
|
+
quant4(gelu(b["hid"], approximate="tanh"), hp4, hsf4)
|
|
269
|
+
gemm_res4(hp4, e["fc2"][0], hsf4, e["fc2"][1],
|
|
270
|
+
e["fc2_b"], res, out=res)
|
|
271
|
+
else:
|
|
272
|
+
def ffn(res, e):
|
|
273
|
+
kf.layer_norm_quant_fp8_static_bf16(
|
|
274
|
+
res, e["ln2_w"], e["ln2_b"], e["sc_fc1"],
|
|
275
|
+
eps=e["ln2_eps"], out=b["xn8"])
|
|
276
|
+
kg.fp8_linear_bias_gelu_bf16(
|
|
277
|
+
b["xn8"], e["fc1"], e["fc1_b"], alpha=e["a_fc1"],
|
|
278
|
+
out=b["hid"])
|
|
279
|
+
kf.quantize_fp8_static_bf16(b["hid"], e["sc_fc2"],
|
|
280
|
+
out=b["h8"])
|
|
281
|
+
kg.fp8_linear_bias_residual_bf16(
|
|
282
|
+
b["h8"], e["fc2"], e["fc2_b"], res,
|
|
283
|
+
alpha=e["a_fc2"])
|
|
284
|
+
|
|
285
|
+
def run(x3d):
|
|
286
|
+
res = b["res"]
|
|
287
|
+
res.copy_(x3d.reshape(B * S, D))
|
|
288
|
+
for e in table:
|
|
289
|
+
with rf("vi:qkv"):
|
|
290
|
+
kf.layer_norm_quant_fp8_static_bf16(
|
|
291
|
+
res, e["ln1_w"], e["ln1_b"], e["sc_qkv"],
|
|
292
|
+
eps=e["ln1_eps"], out=b["xn8"])
|
|
293
|
+
kg.fp8_linear_bias_bf16(b["xn8"], e["qkv"], e["qkv_b"],
|
|
294
|
+
alpha=e["a_qkv"], out=b["qkv"])
|
|
295
|
+
with rf("vi:attn"):
|
|
296
|
+
q = b["qkv"][:, :D].view(B, S, nh, hd)
|
|
297
|
+
k = b["qkv"][:, D:2 * D].view(B, S, nh, hd)
|
|
298
|
+
v = b["qkv"][:, 2 * D:].view(B, S, nh, hd)
|
|
299
|
+
att = attend(q, k, v)
|
|
300
|
+
with rf("vi:o"):
|
|
301
|
+
kf.quantize_fp8_static_bf16(
|
|
302
|
+
att.reshape(B * S, D), e["sc_o"], out=b["o8"])
|
|
303
|
+
kg.fp8_linear_bias_residual_bf16(
|
|
304
|
+
b["o8"], e["o"], e["o_b"], res, alpha=e["a_o"])
|
|
305
|
+
with rf("vi:ffn"):
|
|
306
|
+
ffn(res, e)
|
|
307
|
+
return bound.out_ctor(
|
|
308
|
+
last_hidden_state=res.view(B, S, D)
|
|
309
|
+
.to(bound.out_dtype).clone())
|
|
310
|
+
|
|
311
|
+
return run
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def bind_vision_fp8_chain(model, root: str,
|
|
315
|
+
probe: Callable[[], Any],
|
|
316
|
+
band: str = "fp8") -> dict:
|
|
317
|
+
"""Bind the chain onto the tower at ``root``; adapter contract out."""
|
|
318
|
+
try:
|
|
319
|
+
kg = hub_kernel(GEMM_PACKAGE, ">=1")
|
|
320
|
+
kf = hub_kernel(FUSE_PACKAGE, ">=1")
|
|
321
|
+
kg4 = kf4 = None
|
|
322
|
+
if BANDS[band]["packages"]:
|
|
323
|
+
kg4 = hub_kernel(FP4_GEMM_PACKAGE, ">=1")
|
|
324
|
+
kf4 = hub_kernel(FP4_FUSE_PACKAGE, ">=1")
|
|
325
|
+
except KernelUnavailable as exc:
|
|
326
|
+
return {"refused": f"vision_{band}_chain: {exc}"}
|
|
327
|
+
gaps = missing_symbols(band=band)
|
|
328
|
+
if gaps:
|
|
329
|
+
return {"refused": f"vision_fp8_chain missing: "
|
|
330
|
+
f"{', '.join(gaps)}"}
|
|
331
|
+
|
|
332
|
+
stack = model.get_submodule(root) if root else model
|
|
333
|
+
layers, nh, hd, dim, hidden = _stack_parts(stack)
|
|
334
|
+
if not _gelu_tanh_like(layers[0].mlp.activation_fn
|
|
335
|
+
if hasattr(layers[0].mlp, "activation_fn")
|
|
336
|
+
else layers[0].mlp.act_fn):
|
|
337
|
+
return {"refused": "vision_fp8_chain: MLP activation is not "
|
|
338
|
+
"tanh-GELU"}
|
|
339
|
+
scale_attr = getattr(layers[0].self_attn, "scale", None)
|
|
340
|
+
scaling = float(scale_attr) if scale_attr else hd ** -0.5
|
|
341
|
+
|
|
342
|
+
bound = BoundVisionFp8Chain()
|
|
343
|
+
bound.kernels = {"kg": kg, "kf": kf, "kg4": kg4, "kf4": kf4}
|
|
344
|
+
bound.band = band
|
|
345
|
+
bound.scaling = scaling
|
|
346
|
+
bound.dims = {"nh": nh, "hd": hd, "dim": dim, "hidden": hidden,
|
|
347
|
+
"layers": len(layers)}
|
|
348
|
+
|
|
349
|
+
calls: list[dict] = []
|
|
350
|
+
amax: dict = {}
|
|
351
|
+
chan: dict = {}
|
|
352
|
+
|
|
353
|
+
def note(site):
|
|
354
|
+
def hook(_m, args):
|
|
355
|
+
peak = float(args[0].detach().abs().amax())
|
|
356
|
+
amax[site] = max(amax.get(site, 0.0), peak)
|
|
357
|
+
return hook
|
|
358
|
+
|
|
359
|
+
def cnote(site):
|
|
360
|
+
# per-input-channel amax at the FC1 input — the native SigLIP
|
|
361
|
+
# AWQ statistic (collected on the LN output the producer emits)
|
|
362
|
+
def hook(_m, args):
|
|
363
|
+
v = args[0].detach().float().abs()
|
|
364
|
+
v = v.reshape(-1, v.shape[-1]).amax(0)
|
|
365
|
+
prev = chan.get(site)
|
|
366
|
+
chan[site] = v if prev is None else torch.maximum(prev, v)
|
|
367
|
+
return hook
|
|
368
|
+
|
|
369
|
+
hooks = []
|
|
370
|
+
for i, ly in enumerate(layers):
|
|
371
|
+
hooks.append(ly.self_attn.q_proj.register_forward_pre_hook(
|
|
372
|
+
note((i, "qkv"))))
|
|
373
|
+
hooks.append(ly.self_attn.out_proj.register_forward_pre_hook(
|
|
374
|
+
note((i, "o"))))
|
|
375
|
+
if BANDS[band]["packages"] and BANDS[band].get("awq"):
|
|
376
|
+
hooks.append(ly.mlp.fc1.register_forward_pre_hook(
|
|
377
|
+
cnote((i, "fc1"))))
|
|
378
|
+
hooks.append(ly.mlp.fc1.register_forward_pre_hook(
|
|
379
|
+
note((i, "fc1"))))
|
|
380
|
+
hooks.append(ly.mlp.fc2.register_forward_pre_hook(
|
|
381
|
+
note((i, "fc2"))))
|
|
382
|
+
|
|
383
|
+
saved_probe = stack.__dict__.get("forward")
|
|
384
|
+
host_forward = stack.forward
|
|
385
|
+
|
|
386
|
+
def capturing(_self, *args, **kwargs):
|
|
387
|
+
out = host_forward(*args, **kwargs)
|
|
388
|
+
embs = kwargs.get("inputs_embeds",
|
|
389
|
+
args[0] if args else None)
|
|
390
|
+
hidden_out = getattr(out, "last_hidden_state", None)
|
|
391
|
+
if (embs is not None and hidden_out is not None
|
|
392
|
+
and embs.dim() == 3
|
|
393
|
+
and kwargs.get("attention_mask") is None):
|
|
394
|
+
calls.append({"x": embs.detach().clone(),
|
|
395
|
+
"out": hidden_out.detach().clone(),
|
|
396
|
+
"out_type": type(out)})
|
|
397
|
+
return out
|
|
398
|
+
|
|
399
|
+
stack.forward = types.MethodType(capturing, stack)
|
|
400
|
+
try:
|
|
401
|
+
with torch.inference_mode():
|
|
402
|
+
probe()
|
|
403
|
+
finally:
|
|
404
|
+
for hook in hooks:
|
|
405
|
+
hook.remove()
|
|
406
|
+
if saved_probe is not None:
|
|
407
|
+
stack.forward = saved_probe
|
|
408
|
+
else:
|
|
409
|
+
stack.__dict__.pop("forward", None)
|
|
410
|
+
|
|
411
|
+
if not calls:
|
|
412
|
+
return {"refused": "vision_fp8_chain: probe never made an "
|
|
413
|
+
"unmasked encoder call"}
|
|
414
|
+
first = calls[0]
|
|
415
|
+
if any(tuple(c["x"].shape) != tuple(first["x"].shape)
|
|
416
|
+
for c in calls[1:]):
|
|
417
|
+
return {"refused": "vision_fp8_chain: probe calls disagree "
|
|
418
|
+
"on shape"}
|
|
419
|
+
if any((i, s) not in amax or amax[(i, s)] <= 0.0
|
|
420
|
+
for i in range(len(layers))
|
|
421
|
+
for s in ("qkv", "o", "fc1", "fc2")):
|
|
422
|
+
return {"refused": "vision_fp8_chain: calibration saw a dead "
|
|
423
|
+
"quantizer site"}
|
|
424
|
+
|
|
425
|
+
B, S, _ = first["x"].shape
|
|
426
|
+
bound.dims["batch"], bound.dims["seq"] = B, S
|
|
427
|
+
bound.out_ctor = first["out_type"]
|
|
428
|
+
bound.out_dtype = first["out"].dtype
|
|
429
|
+
_quantize(bound, layers, amax, chan)
|
|
430
|
+
dev, bf = "cuda", torch.bfloat16
|
|
431
|
+
b = bound.buf
|
|
432
|
+
b["res"] = torch.empty(B * S, dim, device=dev, dtype=bf)
|
|
433
|
+
b["xn8"] = torch.empty(B * S, dim, device=dev,
|
|
434
|
+
dtype=torch.float8_e4m3fn)
|
|
435
|
+
b["qkv"] = torch.empty(B * S, 3 * dim, device=dev, dtype=bf)
|
|
436
|
+
b["o8"] = torch.empty(B * S, dim, device=dev,
|
|
437
|
+
dtype=torch.float8_e4m3fn)
|
|
438
|
+
if BANDS[bound.band]["packages"] != ():
|
|
439
|
+
kg4 = bound.kernels["kg4"]
|
|
440
|
+
aligned = getattr(kg4, "aligned_fp4_dim",
|
|
441
|
+
lambda d, alignment=32: -(-d // 32) * 32)
|
|
442
|
+
hidden_p = int(aligned(hidden))
|
|
443
|
+
b["hid"] = torch.empty(B * S, hidden_p, device=dev, dtype=bf)
|
|
444
|
+
quant4 = kg4.quantize_fp4_sfa_bf16
|
|
445
|
+
b["xp4"], b["xsf4"] = quant4(
|
|
446
|
+
torch.zeros(B * S, dim, device=dev, dtype=bf))
|
|
447
|
+
b["hp4"], b["hsf4"] = quant4(
|
|
448
|
+
torch.zeros(B * S, hidden_p, device=dev, dtype=bf))
|
|
449
|
+
else:
|
|
450
|
+
b["hid"] = torch.empty(B * S, hidden, device=dev, dtype=bf)
|
|
451
|
+
b["h8"] = torch.empty(B * S, hidden, device=dev,
|
|
452
|
+
dtype=torch.float8_e4m3fn)
|
|
453
|
+
|
|
454
|
+
attend, attn_mode = None, None
|
|
455
|
+
try:
|
|
456
|
+
ka = hub_kernel(FA4_REPO, ">=1")
|
|
457
|
+
cand = _make_attend(bound, "fa4_cute", ka)
|
|
458
|
+
cand(torch.zeros(B, S, nh, hd, device=dev, dtype=bf),
|
|
459
|
+
torch.zeros(B, S, nh, hd, device=dev, dtype=bf),
|
|
460
|
+
torch.zeros(B, S, nh, hd, device=dev, dtype=bf))
|
|
461
|
+
torch.cuda.synchronize()
|
|
462
|
+
attend, attn_mode = cand, "fa4_cute"
|
|
463
|
+
except Exception: # noqa: BLE001 — the floor rung serves
|
|
464
|
+
attend, attn_mode = _make_attend(bound, "sdpa", None), "sdpa"
|
|
465
|
+
bound.kernels["attend"] = attend
|
|
466
|
+
|
|
467
|
+
run = _make_run(bound)
|
|
468
|
+
guard = bound._frt_arm(dtypes=(torch.bfloat16,),
|
|
469
|
+
device=torch.device("cuda"))
|
|
470
|
+
guard.notes["n_layers"] = len(layers)
|
|
471
|
+
guard.notes["attention"] = attn_mode
|
|
472
|
+
|
|
473
|
+
worst = None
|
|
474
|
+
with torch.inference_mode():
|
|
475
|
+
for c in calls:
|
|
476
|
+
got = run(c["x"].to(torch.bfloat16))
|
|
477
|
+
cos = torch.nn.functional.cosine_similarity(
|
|
478
|
+
got.last_hidden_state.float().flatten(),
|
|
479
|
+
c["out"].float().flatten(), dim=0)
|
|
480
|
+
worst = float(cos) if worst is None else min(worst,
|
|
481
|
+
float(cos))
|
|
482
|
+
if worst is None or worst < SMOKE_FLOOR:
|
|
483
|
+
return {"refused": f"vision_fp8_chain smoke cos {worst} < "
|
|
484
|
+
f"{SMOKE_FLOOR} across {len(calls)} "
|
|
485
|
+
"probe call(s)"}
|
|
486
|
+
guard.notes["smoke_cos"] = round(worst, 6)
|
|
487
|
+
|
|
488
|
+
saved = stack.__dict__.get("forward")
|
|
489
|
+
x_shape = tuple(first["x"].shape)
|
|
490
|
+
|
|
491
|
+
def routed(_self, *args, **kwargs):
|
|
492
|
+
compiling = torch.compiler.is_compiling()
|
|
493
|
+
capturing_now = (False if compiling
|
|
494
|
+
else torch.cuda.is_current_stream_capturing())
|
|
495
|
+
eager = not compiling and not capturing_now
|
|
496
|
+
if eager:
|
|
497
|
+
guard.calls += 1
|
|
498
|
+
embs = kwargs.get("inputs_embeds",
|
|
499
|
+
args[0] if args else None)
|
|
500
|
+
ok = (embs is not None
|
|
501
|
+
and kwargs.get("attention_mask") is None
|
|
502
|
+
and tuple(embs.shape) == x_shape)
|
|
503
|
+
if not ok:
|
|
504
|
+
if not eager:
|
|
505
|
+
raise RuntimeError(
|
|
506
|
+
"vision_fp8_chain: out-of-contract call during "
|
|
507
|
+
"capture/compile — fix the eager path first")
|
|
508
|
+
guard.fallbacks += 1
|
|
509
|
+
guard.last_reason = "call outside the routed contract"
|
|
510
|
+
return host_forward(*args, **kwargs)
|
|
511
|
+
return run(embs.to(torch.bfloat16))
|
|
512
|
+
|
|
513
|
+
def enable() -> None:
|
|
514
|
+
stack.forward = types.MethodType(routed, stack)
|
|
515
|
+
|
|
516
|
+
def disable() -> None:
|
|
517
|
+
if saved is not None:
|
|
518
|
+
stack.forward = saved
|
|
519
|
+
elif "forward" in stack.__dict__:
|
|
520
|
+
del stack.forward
|
|
521
|
+
|
|
522
|
+
def revert() -> None:
|
|
523
|
+
disable()
|
|
524
|
+
bound.table.clear()
|
|
525
|
+
bound.buf.clear()
|
|
526
|
+
|
|
527
|
+
enable()
|
|
528
|
+
return {
|
|
529
|
+
"observed": {f"{root}::vision_fp8_chain": bound},
|
|
530
|
+
"revert": [revert],
|
|
531
|
+
"toggle": (enable, disable),
|
|
532
|
+
"smoke_cos": worst,
|
|
533
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""The vision_tower region family: structural identification, candidates.
|
|
2
|
+
|
|
3
|
+
The identifier matches shape, never names: a module carrying a
|
|
4
|
+
``layers`` list whose blocks each hold two affine LayerNorms, a
|
|
5
|
+
*biased* attention group (``q_proj``/``k_proj``/``v_proj``/
|
|
6
|
+
``out_proj``) and a biased two-linear MLP — the bias is what
|
|
7
|
+
separates this tower from the decoder families, whose projections
|
|
8
|
+
are bias-free.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import torch
|
|
14
|
+
|
|
15
|
+
from . import fp8_chain
|
|
16
|
+
from ... import regions
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _bias_linear(mod) -> bool:
|
|
20
|
+
return isinstance(mod, torch.nn.Linear) and mod.bias is not None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _affine_norm(mod) -> bool:
|
|
24
|
+
w = getattr(mod, "weight", None)
|
|
25
|
+
b = getattr(mod, "bias", None)
|
|
26
|
+
return (w is not None and getattr(w, "ndim", 0) == 1
|
|
27
|
+
and b is not None and getattr(b, "ndim", 0) == 1)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _block_ok(block) -> bool:
|
|
31
|
+
attn = getattr(block, "self_attn", None)
|
|
32
|
+
mlp = getattr(block, "mlp", None)
|
|
33
|
+
if attn is None or mlp is None:
|
|
34
|
+
return False
|
|
35
|
+
if not all(_bias_linear(getattr(attn, a, None))
|
|
36
|
+
for a in ("q_proj", "k_proj", "v_proj", "out_proj")):
|
|
37
|
+
return False
|
|
38
|
+
if not all(_bias_linear(getattr(mlp, a, None))
|
|
39
|
+
for a in ("fc1", "fc2")):
|
|
40
|
+
return False
|
|
41
|
+
if not _affine_norm(getattr(block, "layer_norm1", None)):
|
|
42
|
+
return False
|
|
43
|
+
return _affine_norm(getattr(block, "layer_norm2", None))
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def identify(model) -> list[str]:
|
|
47
|
+
roots = []
|
|
48
|
+
for path, mod in model.named_modules():
|
|
49
|
+
layers = getattr(mod, "layers", None)
|
|
50
|
+
if not isinstance(layers, torch.nn.ModuleList) or len(layers) < 2:
|
|
51
|
+
continue
|
|
52
|
+
head = layers[0]
|
|
53
|
+
if not hasattr(head, "layer_norm1"):
|
|
54
|
+
continue
|
|
55
|
+
if not all(_block_ok(b) for b in layers):
|
|
56
|
+
continue
|
|
57
|
+
roots.append(path)
|
|
58
|
+
return roots
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _bind(model, root, probe):
|
|
62
|
+
return fp8_chain.bind_vision_fp8_chain(model, root, probe)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _band_candidate(band: str, row: dict) -> regions.RegionCandidate:
|
|
66
|
+
return regions.RegionCandidate(
|
|
67
|
+
name=f"{band}_chain",
|
|
68
|
+
missing=lambda band=band: fp8_chain.missing_symbols(band=band),
|
|
69
|
+
bind=lambda model, root, probe, band=band:
|
|
70
|
+
fp8_chain.bind_vision_fp8_chain(model, root, probe,
|
|
71
|
+
band=band),
|
|
72
|
+
precision_rank=row["precision_rank"],
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
#: candidates generate from the band table — a precision band is a
|
|
77
|
+
#: table row in the chain module, never new wiring here
|
|
78
|
+
FAMILY = regions.RegionFamily(
|
|
79
|
+
family="vision_tower",
|
|
80
|
+
identify=identify,
|
|
81
|
+
candidates=[_band_candidate(band, row)
|
|
82
|
+
for band, row in fp8_chain.BANDS.items()],
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def register() -> None:
|
|
87
|
+
"""(Re-)register the family — idempotent, import calls it once."""
|
|
88
|
+
regions.register_region_family(FAMILY)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
register()
|