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.
Files changed (122) hide show
  1. flashrt_structures/__init__.py +174 -0
  2. flashrt_structures/adapters/__init__.py +55 -0
  3. flashrt_structures/adapters/diffusers_attention.py +237 -0
  4. flashrt_structures/adapters/diffusers_rotary_attention.py +239 -0
  5. flashrt_structures/adapters/factored_qk_norm_rope.py +252 -0
  6. flashrt_structures/adapters/factored_two_way_attention.py +99 -0
  7. flashrt_structures/adapters/gemma_attention.py +226 -0
  8. flashrt_structures/adapters/packed_qkv_rope.py +342 -0
  9. flashrt_structures/adapters/packed_stream_qk_norm_rope.py +376 -0
  10. flashrt_structures/adapters/qwen_per_head_qk_norm_rope.py +231 -0
  11. flashrt_structures/adapters/sglang_engine.py +207 -0
  12. flashrt_structures/adapters/transformers_attention_interface.py +73 -0
  13. flashrt_structures/adapters/transformers_gated_delta.py +152 -0
  14. flashrt_structures/adapters/transformers_gated_delta_fused.py +96 -0
  15. flashrt_structures/adapters/vllm_engine.py +424 -0
  16. flashrt_structures/adjudicate.py +85 -0
  17. flashrt_structures/aot.py +191 -0
  18. flashrt_structures/autobuild.py +2052 -0
  19. flashrt_structures/beta/__init__.py +43 -0
  20. flashrt_structures/beta/conform.py +94 -0
  21. flashrt_structures/beta/joins.py +113 -0
  22. flashrt_structures/beta/negotiate.py +84 -0
  23. flashrt_structures/beta/ports.py +140 -0
  24. flashrt_structures/decisions.py +80 -0
  25. flashrt_structures/discover.py +623 -0
  26. flashrt_structures/explain.py +70 -0
  27. flashrt_structures/frontdoor.py +572 -0
  28. flashrt_structures/gates.py +465 -0
  29. flashrt_structures/guard.py +421 -0
  30. flashrt_structures/handle.py +189 -0
  31. flashrt_structures/impls/__init__.py +219 -0
  32. flashrt_structures/impls/adaln_producer/__init__.py +8 -0
  33. flashrt_structures/impls/adaln_producer/broker.py +116 -0
  34. flashrt_structures/impls/adaln_producer/fused.py +388 -0
  35. flashrt_structures/impls/adarms_stack/__init__.py +8 -0
  36. flashrt_structures/impls/adarms_stack/fp8_chain.py +832 -0
  37. flashrt_structures/impls/adarms_stack/region.py +102 -0
  38. flashrt_structures/impls/attention_core/__init__.py +132 -0
  39. flashrt_structures/impls/attention_core/fa2_seqused.py +458 -0
  40. flashrt_structures/impls/attention_core/fa4_cute.py +154 -0
  41. flashrt_structures/impls/attention_core/fa4_fp8.py +178 -0
  42. flashrt_structures/impls/attention_core/masked_mha.py +158 -0
  43. flashrt_structures/impls/attention_core/two_way_fa2.py +220 -0
  44. flashrt_structures/impls/cadence_static/__init__.py +18 -0
  45. flashrt_structures/impls/cadence_static/buffers.py +122 -0
  46. flashrt_structures/impls/cadence_static/cross_attention.py +187 -0
  47. flashrt_structures/impls/chain_elements.py +89 -0
  48. flashrt_structures/impls/decode_loop/__init__.py +0 -0
  49. flashrt_structures/impls/decode_loop/fp8_kv.py +206 -0
  50. flashrt_structures/impls/decode_loop/mtp_speculative.py +245 -0
  51. flashrt_structures/impls/decode_loop/whole_step.py +852 -0
  52. flashrt_structures/impls/decoder_block/__init__.py +6 -0
  53. flashrt_structures/impls/decoder_block/attn_sublayer.py +110 -0
  54. flashrt_structures/impls/decoder_block/fused.py +167 -0
  55. flashrt_structures/impls/decoder_ffn/__init__.py +0 -0
  56. flashrt_structures/impls/decoder_ffn/fp8_static.py +310 -0
  57. flashrt_structures/impls/decoder_ffn/fp8_static.yaml +22 -0
  58. flashrt_structures/impls/decoder_ffn/w4a16_static.py +221 -0
  59. flashrt_structures/impls/decoder_ffn/w8a16_static.py +183 -0
  60. flashrt_structures/impls/dit_stack/__init__.py +11 -0
  61. flashrt_structures/impls/dit_stack/fp4_chain.py +417 -0
  62. flashrt_structures/impls/dit_stack/region.py +86 -0
  63. flashrt_structures/impls/fixed_iter/__init__.py +29 -0
  64. flashrt_structures/impls/fixed_iter/openpi.py +264 -0
  65. flashrt_structures/impls/fixed_iter/protocol.py +94 -0
  66. flashrt_structures/impls/gated_delta_core/__init__.py +3 -0
  67. flashrt_structures/impls/gated_delta_core/fused_layer.py +545 -0
  68. flashrt_structures/impls/gated_delta_core/hub_v3.py +152 -0
  69. flashrt_structures/impls/graph_lowering/__init__.py +27 -0
  70. flashrt_structures/impls/graph_lowering/pi052_denoise.py +179 -0
  71. flashrt_structures/impls/graph_lowering/protocol.py +76 -0
  72. flashrt_structures/impls/graph_lowering/qwen3_vl.py +364 -0
  73. flashrt_structures/impls/linear_proj/__init__.py +0 -0
  74. flashrt_structures/impls/linear_proj/fp8_static.py +270 -0
  75. flashrt_structures/impls/linear_proj/nvfp4_balance.py +131 -0
  76. flashrt_structures/impls/linear_proj/nvfp4_dynamic.py +182 -0
  77. flashrt_structures/impls/linear_proj/w8a16_static.py +230 -0
  78. flashrt_structures/impls/modnorm_qkv_chain/__init__.py +0 -0
  79. flashrt_structures/impls/modnorm_qkv_chain/fp8_ptok_table.py +291 -0
  80. flashrt_structures/impls/moe_experts/__init__.py +9 -0
  81. flashrt_structures/impls/moe_experts/nvfp4_dynamic.py +208 -0
  82. flashrt_structures/impls/moe_experts/nvfp4_w4a16.py +129 -0
  83. flashrt_structures/impls/norm_fused/__init__.py +3 -0
  84. flashrt_structures/impls/norm_fused/bf16.py +94 -0
  85. flashrt_structures/impls/norm_fused/fp8_producer.py +84 -0
  86. flashrt_structures/impls/patch_projection/__init__.py +3 -0
  87. flashrt_structures/impls/patch_projection/bf16_flat.py +139 -0
  88. flashrt_structures/impls/prefill_tower/__init__.py +10 -0
  89. flashrt_structures/impls/prefill_tower/fp8_chain.py +955 -0
  90. flashrt_structures/impls/prefill_tower/region.py +99 -0
  91. flashrt_structures/impls/qk_norm_rope/__init__.py +12 -0
  92. flashrt_structures/impls/qk_norm_rope/per_head_gqa.py +199 -0
  93. flashrt_structures/impls/qk_norm_rope/projection_bf16.py +165 -0
  94. flashrt_structures/impls/qkv_pack/__init__.py +5 -0
  95. flashrt_structures/impls/qkv_pack/bf16.py +110 -0
  96. flashrt_structures/impls/qkv_pack/fp8_static.py +435 -0
  97. flashrt_structures/impls/qkv_pack/nvfp4_balance.py +218 -0
  98. flashrt_structures/impls/qkv_rope/__init__.py +3 -0
  99. flashrt_structures/impls/qkv_rope/packed_bias_bf16.py +143 -0
  100. flashrt_structures/impls/step_table.py +113 -0
  101. flashrt_structures/impls/vision_ffn/__init__.py +0 -0
  102. flashrt_structures/impls/vision_ffn/fp8_static.py +261 -0
  103. flashrt_structures/impls/vision_ffn/nvfp4_balance.py +211 -0
  104. flashrt_structures/impls/vision_tower/__init__.py +7 -0
  105. flashrt_structures/impls/vision_tower/fp8_chain.py +533 -0
  106. flashrt_structures/impls/vision_tower/region.py +91 -0
  107. flashrt_structures/matrix.py +126 -0
  108. flashrt_structures/points.py +368 -0
  109. flashrt_structures/prequantized.py +131 -0
  110. flashrt_structures/quantize_on_adopt.py +94 -0
  111. flashrt_structures/recipe.py +438 -0
  112. flashrt_structures/regions.py +208 -0
  113. flashrt_structures/schemes.py +490 -0
  114. flashrt_structures/stages.py +298 -0
  115. flashrt_structures/storage.py +255 -0
  116. flashrt_structures/swap.py +398 -0
  117. flashrt_structures/workspace.py +110 -0
  118. flashrt_structures-0.2.0.dist-info/METADATA +140 -0
  119. flashrt_structures-0.2.0.dist-info/RECORD +122 -0
  120. flashrt_structures-0.2.0.dist-info/WHEEL +5 -0
  121. flashrt_structures-0.2.0.dist-info/licenses/LICENSE +202 -0
  122. flashrt_structures-0.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,364 @@
1
+ """Whole-graph shape lowering for the Qwen3-VL backbone family.
2
+
3
+ The GR00T N1.7 hosts (official Isaac-GR00T and the LeRobot port) both
4
+ run a Qwen3-VL vision-language backbone that recomputes, on every call,
5
+ quantities that depend only on the request's shape and token placement:
6
+ multimodal position ids, rope tables, vision patch routing, sequence
7
+ cumsums, placeholder masks. Several of those recomputations synchronize
8
+ (``.item()`` / ``.tolist()`` / mask ``.all()``), which CUDA graph
9
+ capture forbids. For one fixed observation shape they are constants, so
10
+ this adapter records one real request, computes each constant once, and
11
+ pins the handful of host functions that would otherwise recompute them.
12
+
13
+ Two transformers generations of the vision contract are served, probed
14
+ by class presence rather than version: the older visual tower returns
15
+ ``(merged, deepstack_list)``; the newer one wraps the same tensors in
16
+ ``BaseModelOutputWithDeepstackFeatures`` and splits pooled embeddings
17
+ inside ``get_image_features``. Hosts that wrap the backbone in their
18
+ own per-call glue (a legacy position-id injector) are pinned through a
19
+ capability probe on the wrapper, never through a host table.
20
+
21
+ Every pin is a shape-derived constant of one fixed request; image and
22
+ state *values* flow through untouched, and ``undo()`` restores every
23
+ patched attribute.
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ import types
29
+ from typing import Any, Callable
30
+
31
+ import torch
32
+
33
+ from .protocol import GraphLowering, GraphLoweringRefused
34
+
35
+
36
+ def _find_qwen3_vl(model: Any):
37
+ """The first Qwen3-VL-shaped conditional-generation module, or None."""
38
+ for _, module in model.named_modules():
39
+ inner = getattr(module, "model", None)
40
+ visual = getattr(inner, "visual", None)
41
+ if (visual is not None
42
+ and hasattr(visual, "fast_pos_embed_interpolate")
43
+ and hasattr(visual, "deepstack_visual_indexes")
44
+ and hasattr(inner, "language_model")
45
+ and hasattr(module, "lm_head")
46
+ and getattr(getattr(module, "config", None),
47
+ "image_token_id", None) is not None):
48
+ return module
49
+ return None
50
+
51
+
52
+ def _find_glue_owner(model: Any, qwen: Any):
53
+ """A host wrapper owning ``qwen`` with per-call position-id glue."""
54
+ for _, module in model.named_modules():
55
+ if (getattr(module, "model", None) is qwen
56
+ and hasattr(module, "_ensure_legacy_qwen3_position_ids")):
57
+ return module
58
+ return None
59
+
60
+
61
+ def _first_output_tensor(value):
62
+ """One deterministic tensor from a pipeline output, for proofs."""
63
+ if torch.is_tensor(value):
64
+ return value
65
+ if isinstance(value, dict):
66
+ for key in sorted(value):
67
+ found = _first_output_tensor(value[key])
68
+ if found is not None:
69
+ return found
70
+ return None
71
+ if isinstance(value, (tuple, list)):
72
+ for item in value:
73
+ found = _first_output_tensor(item)
74
+ if found is not None:
75
+ return found
76
+ return None
77
+
78
+
79
+ class Qwen3VLGraphLoweringAdapter:
80
+ """Pin the Qwen3-VL backbone's shape glue for one fixed request."""
81
+
82
+ family = "qwen3_vl_backbone"
83
+
84
+ def lower(self, model: Any,
85
+ forward: Callable[[], Any]) -> GraphLowering | None:
86
+ qwen = _find_qwen3_vl(model)
87
+ if qwen is None:
88
+ return None
89
+
90
+ # ---- record one real request ---------------------------------
91
+ request: dict[str, torch.Tensor] = {}
92
+
93
+ def grab(_module, args, kwargs):
94
+ for key in ("input_ids", "attention_mask", "image_grid_thw"):
95
+ value = kwargs.get(key)
96
+ if value is None and args:
97
+ break
98
+ if value is not None and key not in request:
99
+ request[key] = value
100
+ return None
101
+
102
+ handle = qwen.register_forward_pre_hook(grab, with_kwargs=True)
103
+ try:
104
+ # the recording pass is calibration-class work: it runs with
105
+ # observation hooks on host modules, and a compiled callable
106
+ # must execute eagerly here — otherwise its first trace
107
+ # happens with the recording hooks inside the graph
108
+ runner = forward
109
+ dynamo = getattr(torch, "_dynamo", None)
110
+ if dynamo is not None and hasattr(dynamo, "disable"):
111
+ runner = dynamo.disable(forward)
112
+ with torch.inference_mode():
113
+ runner()
114
+ finally:
115
+ handle.remove()
116
+ missing = [k for k in ("input_ids", "attention_mask",
117
+ "image_grid_thw") if k not in request]
118
+ if missing:
119
+ raise GraphLoweringRefused(
120
+ f"{self.family}: could not observe {missing} on the "
121
+ "recorded request — the host calls its backbone in a "
122
+ "form this family does not recognize")
123
+
124
+ input_ids = request["input_ids"]
125
+ attention_mask = request["attention_mask"]
126
+ grid_thw = request["image_grid_thw"]
127
+ if not bool(torch.all(attention_mask == 1).item()):
128
+ raise GraphLoweringRefused(
129
+ f"{self.family}: fixed-shape capture requires an "
130
+ "all-one attention mask")
131
+
132
+ base = qwen.model
133
+ visual = base.visual
134
+
135
+ # ---- the constants of this request ---------------------------
136
+ import importlib
137
+ modeling = importlib.import_module(type(visual).__module__)
138
+ output_cls = getattr(modeling,
139
+ "BaseModelOutputWithDeepstackFeatures", None)
140
+
141
+ pos_embeds = visual.fast_pos_embed_interpolate(grid_thw)
142
+ rotary = visual.rot_pos_emb(grid_thw)
143
+ rotary_pair = torch.cat((rotary, rotary), dim=-1)
144
+ position_embeddings = (rotary_pair.cos(), rotary_pair.sin())
145
+ fixed_cu_seqlens = torch.nn.functional.pad(
146
+ torch.repeat_interleave(grid_thw[:, 1] * grid_thw[:, 2],
147
+ grid_thw[:, 0]).cumsum(
148
+ dim=0, dtype=torch.int32), (1, 0), value=0)
149
+ vision_lengths = tuple(
150
+ int(v) for v in
151
+ (fixed_cu_seqlens[1:] - fixed_cu_seqlens[:-1]).cpu().tolist())
152
+ split_sizes = tuple(int(v) for v in (
153
+ grid_thw.prod(-1)
154
+ // visual.spatial_merge_size ** 2).cpu().tolist())
155
+ image_mask = (input_ids
156
+ == qwen.config.image_token_id).unsqueeze(-1)
157
+ video_mask = (input_ids
158
+ == qwen.config.video_token_id).unsqueeze(-1)
159
+ visual_indices = (input_ids.reshape(-1)
160
+ == qwen.config.image_token_id).nonzero().flatten()
161
+ try:
162
+ fixed_position_ids, fixed_rope_deltas = base.get_rope_index(
163
+ input_ids, grid_thw, None, attention_mask=attention_mask)
164
+ have_rope_index = True
165
+ except (TypeError, IndexError):
166
+ # newer transformers changed this helper's signature; hosts
167
+ # that inject position_ids never call it — nothing to pin
168
+ have_rope_index = False
169
+
170
+ glue_owner = _find_glue_owner(model, qwen)
171
+ glue_position_ids = None
172
+ if glue_owner is not None:
173
+ probe = {"input_ids": input_ids,
174
+ "attention_mask": attention_mask,
175
+ "image_grid_thw": grid_thw}
176
+ if hasattr(glue_owner, "_ensure_mm_token_type_ids"):
177
+ glue_owner._ensure_mm_token_type_ids(probe)
178
+ glue_owner._ensure_legacy_qwen3_position_ids(probe)
179
+ glue_position_ids = probe.get("position_ids")
180
+
181
+ # ---- pin ------------------------------------------------------
182
+ from transformers import masking_utils
183
+
184
+ saved = {
185
+ "visual_forward": visual.forward,
186
+ "attn_forwards": [b.attn.forward for b in visual.blocks],
187
+ "get_image_features": base.get_image_features,
188
+ "get_placeholder_mask": base.get_placeholder_mask,
189
+ "deepstack": base.language_model._deepstack_process,
190
+ "use_cache": qwen.config.text_config.use_cache,
191
+ "ignore_mask": masking_utils._ignore_causal_mask_sdpa,
192
+ }
193
+ if have_rope_index:
194
+ saved["get_rope_index"] = base.get_rope_index
195
+ if glue_owner is not None and glue_position_ids is not None:
196
+ saved["glue"] = glue_owner._ensure_legacy_qwen3_position_ids
197
+
198
+ def fixed_visual_forward(self, hidden_states, grid_thw=None,
199
+ **kwargs):
200
+ del grid_thw
201
+ kwargs.pop("return_dict", None)
202
+ hidden_states = self.patch_embed(hidden_states)
203
+ hidden_states = hidden_states + pos_embeds
204
+ seq, _ = hidden_states.size()
205
+ hidden_states = hidden_states.reshape(seq, -1)
206
+ deepstack_features = []
207
+ for index, block in enumerate(self.blocks):
208
+ hidden_states = block(
209
+ hidden_states, cu_seqlens=fixed_cu_seqlens,
210
+ position_embeddings=position_embeddings, **kwargs)
211
+ if index in self.deepstack_visual_indexes:
212
+ merger = self.deepstack_visual_indexes.index(index)
213
+ deepstack_features.append(
214
+ self.deepstack_merger_list[merger](hidden_states))
215
+ merged = self.merger(hidden_states)
216
+ if output_cls is not None:
217
+ return output_cls(last_hidden_state=hidden_states,
218
+ pooler_output=merged,
219
+ deepstack_features=deepstack_features)
220
+ return merged, deepstack_features
221
+
222
+ def fixed_vision_attention(self, hidden_states, cu_seqlens=None,
223
+ rotary_pos_emb=None,
224
+ position_embeddings_arg=None, **kwargs):
225
+ del cu_seqlens, rotary_pos_emb, position_embeddings_arg
226
+ seq = hidden_states.shape[0]
227
+ query, key, value = (self.qkv(hidden_states)
228
+ .reshape(seq, 3, self.num_heads, -1)
229
+ .permute(1, 0, 2, 3).unbind(0))
230
+ cos_t, sin_t = position_embeddings
231
+ query, key = modeling.apply_rotary_pos_emb_vision(
232
+ query, key, cos_t, sin_t)
233
+ query = query.transpose(0, 1).unsqueeze(0)
234
+ key = key.transpose(0, 1).unsqueeze(0)
235
+ value = value.transpose(0, 1).unsqueeze(0)
236
+ interface = modeling.eager_attention_forward
237
+ if self.config._attn_implementation != "eager":
238
+ interface = modeling.ALL_ATTENTION_FUNCTIONS[
239
+ self.config._attn_implementation]
240
+ chunks = (torch.split(t, vision_lengths, dim=2)
241
+ for t in (query, key, value))
242
+ outputs = [interface(self, q, k, v, attention_mask=None,
243
+ scaling=self.scaling, dropout=0.0,
244
+ is_causal=False, **kwargs)[0]
245
+ for q, k, v in zip(*chunks)]
246
+ return self.proj(torch.cat(outputs, dim=1)
247
+ .reshape(seq, -1).contiguous())
248
+
249
+ def fixed_get_image_features(self, pixel_values,
250
+ image_grid_thw=None, **kwargs):
251
+ del kwargs
252
+ pixel_values = pixel_values.type(self.visual.dtype)
253
+ vision_output = self.visual(pixel_values,
254
+ grid_thw=image_grid_thw)
255
+ if output_cls is not None:
256
+ vision_output.pooler_output = torch.split(
257
+ vision_output.pooler_output, split_sizes)
258
+ return vision_output
259
+ embeds, deepstack = vision_output
260
+ return torch.split(embeds, split_sizes), deepstack
261
+
262
+ def fixed_get_placeholder_mask(self, input_ids_arg, inputs_embeds,
263
+ image_features=None,
264
+ video_features=None):
265
+ del self, input_ids_arg, image_features, video_features
266
+ return (image_mask.expand_as(inputs_embeds),
267
+ video_mask.expand_as(inputs_embeds))
268
+
269
+ def fixed_deepstack(self, hidden_states, visual_pos_masks,
270
+ visual_embeds):
271
+ del self, visual_pos_masks
272
+ b, s, c = hidden_states.shape
273
+ flat = hidden_states.reshape(b * s, c)
274
+ updated = flat.index_select(0, visual_indices) + visual_embeds
275
+ return flat.index_copy(0, visual_indices,
276
+ updated).reshape(b, s, c)
277
+
278
+ visual.forward = types.MethodType(fixed_visual_forward, visual)
279
+ for block in visual.blocks:
280
+ block.attn.forward = types.MethodType(fixed_vision_attention,
281
+ block.attn)
282
+ base.get_image_features = types.MethodType(
283
+ fixed_get_image_features, base)
284
+ base.get_placeholder_mask = types.MethodType(
285
+ fixed_get_placeholder_mask, base)
286
+ base.language_model._deepstack_process = types.MethodType(
287
+ fixed_deepstack, base.language_model)
288
+ qwen.config.text_config.use_cache = False
289
+ masking_utils._ignore_causal_mask_sdpa = lambda *a, **k: True
290
+ if have_rope_index:
291
+ base.get_rope_index = types.MethodType(
292
+ lambda self, *a, **k: (fixed_position_ids,
293
+ fixed_rope_deltas), base)
294
+ if "glue" in saved:
295
+ def pinned_glue(model_input, _pids=glue_position_ids):
296
+ model_input["position_ids"] = _pids
297
+ glue_owner._ensure_legacy_qwen3_position_ids = pinned_glue
298
+
299
+ pins = ["visual_forward", "vision_attention",
300
+ "get_image_features", "get_placeholder_mask",
301
+ "deepstack", "use_cache", "causal_mask_decision"]
302
+ if have_rope_index:
303
+ pins.append("get_rope_index")
304
+ if "glue" in saved:
305
+ pins.append("legacy_position_ids_glue")
306
+
307
+ # ---- dead-output pin, held only under proof ------------------
308
+ # A feature-extraction pipeline never reads the vocabulary
309
+ # logits, but whether a compiler can prove that depends on the
310
+ # host's wrapper form — one host's graph dead-code-eliminates
311
+ # the [tokens, vocab] projection, another's keeps it alive and
312
+ # pays real milliseconds for it every call. The family settles
313
+ # it with a receipt instead: skip the head, re-run the recorded
314
+ # request, and keep the pin only if the pipeline output is
315
+ # bit-identical. Any mismatch or error restores the head alone.
316
+ lm_head = getattr(qwen, "lm_head", None)
317
+ if lm_head is not None and hasattr(lm_head, "forward"):
318
+ with torch.inference_mode():
319
+ before = _first_output_tensor(runner())
320
+ saved_head = lm_head.forward
321
+
322
+ def skipped_head(self, hidden_states, *args, **kwargs):
323
+ del args, kwargs
324
+ return hidden_states[..., :0]
325
+
326
+ lm_head.forward = types.MethodType(skipped_head, lm_head)
327
+ proven = False
328
+ if before is not None:
329
+ try:
330
+ with torch.inference_mode():
331
+ after = _first_output_tensor(runner())
332
+ proven = after is not None and torch.equal(before,
333
+ after)
334
+ except Exception: # noqa: BLE001 — proof failed
335
+ proven = False
336
+ if proven:
337
+ saved["lm_head"] = saved_head
338
+ pins.append("lm_head_dead_output")
339
+ else:
340
+ lm_head.forward = saved_head
341
+
342
+ def undo():
343
+ visual.forward = saved["visual_forward"]
344
+ for block, fwd in zip(visual.blocks, saved["attn_forwards"]):
345
+ block.attn.forward = fwd
346
+ base.get_image_features = saved["get_image_features"]
347
+ base.get_placeholder_mask = saved["get_placeholder_mask"]
348
+ base.language_model._deepstack_process = saved["deepstack"]
349
+ qwen.config.text_config.use_cache = saved["use_cache"]
350
+ masking_utils._ignore_causal_mask_sdpa = saved["ignore_mask"]
351
+ if "get_rope_index" in saved:
352
+ base.get_rope_index = saved["get_rope_index"]
353
+ if "glue" in saved:
354
+ glue_owner._ensure_legacy_qwen3_position_ids = saved["glue"]
355
+ if "lm_head" in saved:
356
+ qwen.lm_head.forward = saved["lm_head"]
357
+
358
+ return GraphLowering(
359
+ undo=undo, family=self.family, pins=tuple(pins),
360
+ details={"tokens": int(input_ids.shape[-1]),
361
+ "vision_patches": int(sum(vision_lengths)),
362
+ "vision_contract": ("output_class"
363
+ if output_cls is not None
364
+ else "tuple")})
File without changes
@@ -0,0 +1,270 @@
1
+ """FP8-static implementation of the ``linear_proj`` structure.
2
+
3
+ A projection has more than one executable form, and which one applies is
4
+ a property of the host's own weights rather than a tuning knob:
5
+
6
+ - ``bias``: ``bf16_fp8_linear_bias_bf16`` — fused input quantization,
7
+ FP8 weights, BF16 bias and output. Three kernels per call.
8
+ - ``no_bias``: the quantize as its own kernel followed by
9
+ ``fp8_gemm_bf16``. Two kernels. Hosts whose projections carry no bias
10
+ (the whole Gemma/Llama/Qwen attention family) would otherwise get a
11
+ zero bias built for them and pay a kernel to add it.
12
+ - ``fp8_in``: ``fp8_gemm_bf16`` straight, for a seam whose producer
13
+ already emits FP8. One kernel, no quantization at all.
14
+
15
+ Each form is qualified by its own work band, because a band expresses
16
+ what that form is amortizing and the forms do not carry the same cost.
17
+ Measured against the host's own BF16 Linear at real shapes on RTX 5090
18
+ (work = M*N*K):
19
+
20
+ form band evidence
21
+ bias [2e8, inf) 1.05e8 ties the host (6.68 vs 6.66 us);
22
+ 3.0e9 wins 2.5x (26.0 vs 66.6) — the
23
+ fused quantize needs a large GEMM to
24
+ disappear behind
25
+ no_bias [2e7, 1e9] 2.6e7 wins 0.67us, 1.3e7 loses 0.25us
26
+ (one quantize launch to amortize); above
27
+ the band it *loses* to the bias form even
28
+ with no bias to add — 3.0e9: 26.21 vs
29
+ 26.04 — because the fused entry bundles
30
+ its quantize instead of launching one
31
+ fp8_in [0, inf) nothing to amortize; the producer paid
32
+
33
+ Hence a large projection with no bias still takes the bias form and gets
34
+ a zero bias built for it: that is the measured faster path at that size,
35
+ not an oversight. The rule is which form the measurements put this shape
36
+ in, not which parts the host happens to have.
37
+
38
+ Outside every band the projection is refused and the refusal names the
39
+ form, so "refused" never reads as "this projection cannot be bound" —
40
+ only as "not in that form, at this size".
41
+ """
42
+
43
+ from __future__ import annotations
44
+
45
+ from functools import lru_cache
46
+ from typing import Mapping, Sequence
47
+
48
+ import torch
49
+
50
+ from ...guard import CAST_OK, FP8_ONLY, PROCEED, GuardedSeam
51
+
52
+ KERNEL_DEP = {
53
+ "provider": "hf",
54
+ "repo": "flashrt/flashrt-fp8-ffn",
55
+ "version": ">=1",
56
+ }
57
+ QUANT_DEP = {
58
+ "provider": "hf",
59
+ "repo": "flashrt/flashrt-gemm-epilogues",
60
+ "version": ">=1",
61
+ }
62
+
63
+ _FP8 = torch.float8_e4m3fn
64
+ _FP8_MAX = 448.0
65
+
66
+ # per-form work bands (M*N*K), each measured against the host's own
67
+ # BF16 Linear at real shapes — see the module docstring
68
+ _BAND = {"bias": (2.0e8, float("inf")),
69
+ "no_bias": (2.0e7, 1.0e9),
70
+ "fp8_in": (0.0, float("inf"))}
71
+
72
+ SUPPORT = {
73
+ "work_band": _BAND,
74
+ "K": {"min": 512, "max": 16384},
75
+ "N": {"min": 128, "max": 16384},
76
+ }
77
+
78
+
79
+ @lru_cache(maxsize=1)
80
+ def _kernel():
81
+ from flashrt_structures.impls import hub_kernel
82
+
83
+ return hub_kernel(KERNEL_DEP["repo"], KERNEL_DEP["version"])
84
+
85
+
86
+ @lru_cache(maxsize=1)
87
+ def _quant_kernel():
88
+ """The standalone quantize the no-bias form needs, or None.
89
+
90
+ Its absence is not an error: the form simply does not qualify and
91
+ the projection falls back to the bias form's floor.
92
+ """
93
+ from flashrt_structures.impls import hub_kernel
94
+
95
+ try:
96
+ return hub_kernel(QUANT_DEP["repo"], QUANT_DEP["version"])
97
+ except Exception: # noqa: BLE001
98
+ return None
99
+
100
+
101
+ def _amax_scale(t: torch.Tensor) -> torch.Tensor:
102
+ return (t.float().abs().max() / _FP8_MAX).clamp(min=1e-8)
103
+
104
+
105
+ class FusedLinearProj(GuardedSeam, torch.nn.Module):
106
+ """Drop-in replacement for one nn.Linear projection.
107
+
108
+ ``original`` is retained whole and attribute lookups fall through to
109
+ it, so host code that introspects ``weight``/``bias``/``in_features``
110
+ keeps working — and a call outside the calibrated form runs it.
111
+ """
112
+
113
+ _frt_host_attr = "host_linear"
114
+ _frt_can_fallback = True
115
+
116
+ def __init__(self, w_fp8, bias, input_scale, weight_scale,
117
+ original: torch.nn.Module | None = None,
118
+ form: str = "bias"):
119
+ super().__init__()
120
+ self._w_fp8 = w_fp8
121
+ self._bias = bias
122
+ self._input_scale = input_scale
123
+ self._weight_scale = weight_scale
124
+ self._bufs: dict[int, tuple[torch.Tensor, torch.Tensor]] = {}
125
+ self.form = form
126
+ # resolve the op at bind time: calling the hub loader inside
127
+ # forward makes dynamo trace through kernels.get_kernel's
128
+ # version resolution (network + inspect.Signature) — 26 graph
129
+ # breaks that fragment the surrounding compiled region
130
+ kf = _kernel()
131
+ self._gemm = kf.fp8_gemm_bf16
132
+ self._fn = kf.bf16_fp8_linear_bias_bf16
133
+ if form == "no_bias":
134
+ ke = _quant_kernel()
135
+ self._quantize = ke.channel_scale_quantize_fp8_static_bf16
136
+ # the standalone quantize is a per-channel one; a flat
137
+ # per-tensor scale is the identity channel vector. Held like
138
+ # the other tensors here, as a plain attribute.
139
+ self._chan = torch.ones(w_fp8.shape[1], device=w_fp8.device,
140
+ dtype=torch.bfloat16)
141
+ if original is not None:
142
+ self.host_linear = original
143
+ self._frt_arm(
144
+ dtypes=FP8_ONLY if form == "fp8_in" else CAST_OK,
145
+ device=w_fp8.device, k=int(w_fp8.shape[1]))
146
+
147
+ def __getattr__(self, name):
148
+ try:
149
+ return super().__getattr__(name)
150
+ except AttributeError:
151
+ if name == "host_linear":
152
+ raise
153
+ return getattr(super().__getattr__("host_linear"), name)
154
+
155
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
156
+ admitted = self._frt_admit(x)
157
+ if admitted is not PROCEED:
158
+ return admitted
159
+ shape = x.shape
160
+ flat = x.reshape(-1, shape[-1])
161
+ m = flat.shape[0]
162
+ if torch.compiler.is_compiling():
163
+ # traced regions run the ops functionally: a persistent
164
+ # out-buffer is module state mutated by the op, which
165
+ # functionalization cannot rewrite (the whole-graph export
166
+ # hit exactly that), and inside a compiled graph the
167
+ # allocation is planned away regardless
168
+ x_fp8 = out = None
169
+ else:
170
+ bufs = self._bufs.get(m)
171
+ if bufs is None:
172
+ bufs = (torch.empty(m, self._w_fp8.shape[1],
173
+ device=x.device, dtype=_FP8),
174
+ torch.empty(m, self._w_fp8.shape[0],
175
+ device=x.device,
176
+ dtype=torch.bfloat16))
177
+ self._bufs[m] = bufs
178
+ x_fp8, out = bufs
179
+ if self.form == "fp8_in":
180
+ y = self._gemm(flat, self._w_fp8, self._input_scale,
181
+ self._weight_scale, out=out)
182
+ return y.reshape(*shape[:-1], y.shape[-1])
183
+ flat = flat.to(torch.bfloat16).contiguous()
184
+ if self.form == "no_bias":
185
+ self._quantize(flat, self._chan, self._input_scale, out=x_fp8)
186
+ y = self._gemm(x_fp8, self._w_fp8, self._input_scale,
187
+ self._weight_scale, out=out)
188
+ else:
189
+ y = self._fn(flat, self._w_fp8, self._bias, self._input_scale,
190
+ self._weight_scale, input_fp8=x_fp8, out=out)
191
+ return y.reshape(*shape[:-1], y.shape[-1]).to(x.dtype)
192
+
193
+
194
+ def _form_for(bias: torch.Tensor | None, in_dtype: str,
195
+ work: float) -> str:
196
+ """Which form this projection takes, from what it is *and* its size.
197
+
198
+ Two inputs, not one. What the host has decides which forms are
199
+ available: a projection fed FP8 has no input to quantize, one with a
200
+ real bias must add it. Size decides which of the available forms is
201
+ actually faster — the no-bias form trades a bundled quantize for a
202
+ separate launch, which is a win only while the GEMM is short enough
203
+ for a launch to matter. Above its band a projection with no bias is
204
+ better off in the bias form with a zero bias, and that is measured,
205
+ not conceded.
206
+ """
207
+ if in_dtype == "fp8_static":
208
+ return "fp8_in"
209
+ has_bias = bias is not None and bool(bias.any())
210
+ lo, hi = _BAND["no_bias"]
211
+ if not has_bias and _quant_kernel() is not None and work <= hi:
212
+ return "no_bias"
213
+ return "bias"
214
+
215
+
216
+ @torch.no_grad()
217
+ def bind_proj_seam(
218
+ weights: Mapping[str, torch.Tensor],
219
+ *,
220
+ input_scale: float,
221
+ row_profile: Sequence[int],
222
+ original: torch.nn.Module | None = None,
223
+ in_dtype: str = "bf16",
224
+ ) -> FusedLinearProj:
225
+ """Bind one projection: ``weights['w']`` is checkpoint-layout [N, K].
226
+
227
+ ``input_scale`` is the calibrated per-tensor FP8 scale at this
228
+ projection's input. ``row_profile`` is the row counts that input
229
+ arrived with across calibration — a shape observation, not a
230
+ statistic, and the median of it is what the work-based form
231
+ qualification is measured against.
232
+ """
233
+ if not row_profile:
234
+ raise ValueError("row_profile must be non-empty")
235
+ w = weights["w"]
236
+ n, k = w.shape
237
+ for name, dim in (("K", k), ("N", n)):
238
+ lo, hi = SUPPORT[name]["min"], SUPPORT[name]["max"]
239
+ if not lo <= dim <= hi:
240
+ raise ValueError(f"{name}={dim} outside support envelope")
241
+ raw_bias = weights.get("b")
242
+ ms = sorted(int(m) for m in row_profile)
243
+ m_med = ms[len(ms) // 2]
244
+ work = float(m_med) * n * k
245
+ form = _form_for(raw_bias, in_dtype, work)
246
+ lo, _ = _BAND[form]
247
+ if work < lo:
248
+ raise ValueError(
249
+ f"projection work {m_med}x{n}x{k} below the {form} form's "
250
+ f"band ({lo:.0e}) — host keeps its Linear. Bands are per "
251
+ "form: the same projection may qualify in another one")
252
+ if not w.is_cuda:
253
+ raise ValueError("fp8_static requires CUDA-resident weights")
254
+
255
+ device = w.device
256
+ w_scale = _amax_scale(w)
257
+ w_fp8 = (w.float() / w_scale).clamp(-_FP8_MAX, _FP8_MAX).to(_FP8)
258
+ scale = torch.tensor(float(input_scale), device=device)
259
+ bias = raw_bias
260
+ if bias is None:
261
+ bias = torch.zeros(n, device=device, dtype=torch.bfloat16)
262
+ else:
263
+ bias = bias.detach().to(torch.bfloat16)
264
+ bound = FusedLinearProj(w_fp8, bias, scale.view(1),
265
+ w_scale.view(1), original=original, form=form)
266
+ for m in set(ms): # pre-allocate per calibrated M: keeps the hot
267
+ bound._bufs[m] = ( # path allocation-free (graph/compile safe)
268
+ torch.empty(m, k, device=device, dtype=_FP8),
269
+ torch.empty(m, n, device=device, dtype=torch.bfloat16))
270
+ return bound