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,623 @@
|
|
|
1
|
+
"""Structure discovery — find catalog structures inside a host model.
|
|
2
|
+
|
|
3
|
+
Walks the module tree and matches region-structure seams by shape, not
|
|
4
|
+
by model name: a gated gate/up/down MLP is a ``decoder_ffn`` seam, a
|
|
5
|
+
fc1/fc2 MLP with a sibling LayerNorm is a ``vision_ffn`` seam. The
|
|
6
|
+
result is the same information a hand-written binding file carries
|
|
7
|
+
(paths, dims, variant), derived from the model object itself; bindings
|
|
8
|
+
become generated receipts instead of required inputs.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import re
|
|
14
|
+
from dataclasses import dataclass, field
|
|
15
|
+
|
|
16
|
+
import torch
|
|
17
|
+
from torch import nn
|
|
18
|
+
|
|
19
|
+
_DECODER_PROJ = ("gate_proj", "up_proj", "down_proj")
|
|
20
|
+
_VISION_PROJ = (("fc1", "fc2"), ("linear_fc1", "linear_fc2"),
|
|
21
|
+
("0", "2"),
|
|
22
|
+
("net.0.proj", "net.2"))
|
|
23
|
+
_NORM_ATTRS = ("post_attention_layernorm", "layer_norm2", "norm2", "norm3")
|
|
24
|
+
_ATTN_PROJ = (("q_proj", "k_proj", "v_proj", "o_proj"),
|
|
25
|
+
("q_proj", "k_proj", "v_proj", "out_proj"),
|
|
26
|
+
("q", "k", "v", "o"),
|
|
27
|
+
("to_q", "to_k", "to_v", "to_out"),
|
|
28
|
+
("add_q_proj", "add_k_proj", "add_v_proj", "to_add_out"))
|
|
29
|
+
# the HF decoder-layer shape: two sublayers, each a norm feeding a
|
|
30
|
+
# compute region. Matched by slots, not by class name, so every host
|
|
31
|
+
# built on that layout is the same seam.
|
|
32
|
+
_BLOCK_SLOTS = ("self_attn", "mlp", "input_layernorm",
|
|
33
|
+
"post_attention_layernorm")
|
|
34
|
+
# sibling groups that qkv_pack packs into one GEMM: same input, fixed
|
|
35
|
+
# consumption order. The trailing o_proj/out_proj is not part of the
|
|
36
|
+
# pack (it consumes the attention output, not the shared input).
|
|
37
|
+
_QKV_PACK = (("q_proj", "k_proj", "v_proj"),
|
|
38
|
+
("q", "k", "v"),
|
|
39
|
+
("to_q", "to_k", "to_v"),
|
|
40
|
+
("add_q_proj", "add_k_proj", "add_v_proj"))
|
|
41
|
+
# adaptive-norm modules: a norm that also projects a conditioning
|
|
42
|
+
# vector. The child that produces the modulation is the tell.
|
|
43
|
+
_COND_PROJ_ATTRS = ("dense", "linear", "adaLN_modulation", "modulation")
|
|
44
|
+
_PROJ_WEIGHT_FLOOR = 262144 # candidacy filter only; impls add their own
|
|
45
|
+
# work-based qualification and gates decide
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _is_attn_block(module: nn.Module) -> bool:
|
|
49
|
+
"""A whole attention block, not just sibling projections.
|
|
50
|
+
|
|
51
|
+
When the host exposes q/k/v/out plus head_dim and scale, the pack
|
|
52
|
+
can replace the block itself and declare the attention compute
|
|
53
|
+
dtype too — strictly more than packing the projections alone.
|
|
54
|
+
"""
|
|
55
|
+
if not all(isinstance(getattr(module, a, None), nn.Linear)
|
|
56
|
+
for a in ("q_proj", "k_proj", "v_proj", "out_proj")):
|
|
57
|
+
return False
|
|
58
|
+
if not (hasattr(module, "head_dim") and hasattr(module, "scale")):
|
|
59
|
+
return False
|
|
60
|
+
widths = {getattr(module, a).out_features
|
|
61
|
+
for a in ("q_proj", "k_proj", "v_proj")}
|
|
62
|
+
return len(widths) == 1
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _has_cond_forward(module: nn.Module) -> bool:
|
|
66
|
+
"""A norm takes a conditioning argument (adaptive norm) if its
|
|
67
|
+
forward accepts a second positional / a ``cond``/``temb`` keyword."""
|
|
68
|
+
import inspect
|
|
69
|
+
try:
|
|
70
|
+
params = list(inspect.signature(module.forward).parameters)
|
|
71
|
+
except (TypeError, ValueError):
|
|
72
|
+
return False
|
|
73
|
+
if any(p in params for p in ("cond", "temb", "emb", "c")):
|
|
74
|
+
return True
|
|
75
|
+
# (self is bound out of module.forward already) x + one more positional
|
|
76
|
+
positional = [p for p in params if p not in ("args", "kwargs")]
|
|
77
|
+
return len(positional) >= 2
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _nested_module(module: nn.Module, path: str) -> nn.Module | None:
|
|
81
|
+
"""Resolve a relative child path, including Sequential indices."""
|
|
82
|
+
node = module
|
|
83
|
+
try:
|
|
84
|
+
for part in path.split("."):
|
|
85
|
+
node = node[int(part)] if part.isdigit() else getattr(node, part)
|
|
86
|
+
except (AttributeError, IndexError, KeyError, TypeError):
|
|
87
|
+
return None
|
|
88
|
+
return node if isinstance(node, nn.Module) else None
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _is_modnorm_qkv_chain(
|
|
92
|
+
module: nn.Module,
|
|
93
|
+
) -> tuple[int, int, str] | None:
|
|
94
|
+
"""Recognise a direct conditional-norm -> sibling-QKV data flow.
|
|
95
|
+
|
|
96
|
+
The block is admitted only when no positional module sits between the
|
|
97
|
+
modulated norm and the projections. That is the property required by
|
|
98
|
+
the shared FP8 wire; class and model names are deliberately irrelevant.
|
|
99
|
+
"""
|
|
100
|
+
norm = getattr(module, "norm1", None)
|
|
101
|
+
attn = getattr(module, "attn1", None)
|
|
102
|
+
if not (isinstance(norm, nn.Module) and _has_cond_forward(norm)
|
|
103
|
+
and isinstance(attn, nn.Module)):
|
|
104
|
+
return None
|
|
105
|
+
if getattr(module, "pos_embed", None) is not None:
|
|
106
|
+
return None
|
|
107
|
+
q_proj = getattr(attn, "to_q", None)
|
|
108
|
+
if not isinstance(q_proj, nn.Linear):
|
|
109
|
+
return None
|
|
110
|
+
dim = q_proj.in_features
|
|
111
|
+
k_proj, v_proj = getattr(attn, "to_k", None), getattr(attn, "to_v", None)
|
|
112
|
+
fanout = "q_only"
|
|
113
|
+
if (isinstance(k_proj, nn.Linear) and isinstance(v_proj, nn.Linear)
|
|
114
|
+
and k_proj.in_features == dim and v_proj.in_features == dim):
|
|
115
|
+
fanout = "qkv"
|
|
116
|
+
cond = next((getattr(norm, attr, None) for attr in _COND_PROJ_ATTRS
|
|
117
|
+
if isinstance(getattr(norm, attr, None), nn.Linear)), None)
|
|
118
|
+
if cond is None or cond.out_features != 2 * dim:
|
|
119
|
+
return None
|
|
120
|
+
return dim, cond.in_features, fanout
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _is_table_modnorm_chain(module: nn.Module) -> tuple[int, int] | None:
|
|
124
|
+
"""Recognise the per-token-table modulated block (video-DiT family).
|
|
125
|
+
|
|
126
|
+
Shape, not class names: the block carries its own ``[1, chunks, D]``
|
|
127
|
+
modulation parameter, a no-affine ``norm1`` and ``norm3`` pair, and
|
|
128
|
+
sibling self/cross attentions plus an FFN whose modulation happens
|
|
129
|
+
inline in the block's forward from a per-token timestep table. Only a
|
|
130
|
+
block owner can reroute that inline math, which is why this seam is
|
|
131
|
+
the whole block rather than a norm module.
|
|
132
|
+
"""
|
|
133
|
+
table = getattr(module, "scale_shift_table", None)
|
|
134
|
+
if not (isinstance(table, torch.nn.Parameter) and table.dim() == 3
|
|
135
|
+
and table.shape[0] == 1 and table.shape[1] in (4, 6, 9)):
|
|
136
|
+
return None
|
|
137
|
+
attn = getattr(module, "attn1", None)
|
|
138
|
+
q_proj = getattr(attn, "to_q", None) if attn is not None else None
|
|
139
|
+
if not isinstance(q_proj, nn.Linear):
|
|
140
|
+
return None
|
|
141
|
+
dim = q_proj.in_features
|
|
142
|
+
if table.shape[2] != dim:
|
|
143
|
+
return None
|
|
144
|
+
for attr in ("to_k", "to_v"):
|
|
145
|
+
proj = getattr(attn, attr, None)
|
|
146
|
+
if not (isinstance(proj, nn.Linear) and proj.in_features == dim):
|
|
147
|
+
return None
|
|
148
|
+
for norm_attr in ("norm1", "norm3"):
|
|
149
|
+
norm = getattr(module, norm_attr, None)
|
|
150
|
+
if norm is None or getattr(norm, "weight", None) is not None:
|
|
151
|
+
return None
|
|
152
|
+
if getattr(module, "attn2", None) is None:
|
|
153
|
+
return None
|
|
154
|
+
if getattr(module, "ffn", None) is None:
|
|
155
|
+
return None
|
|
156
|
+
return dim, int(table.shape[1])
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _projection_child(
|
|
160
|
+
module: nn.Module, attr: str,
|
|
161
|
+
) -> tuple[str, nn.Linear] | None:
|
|
162
|
+
"""One attention projection, including Diffusers' ``to_out[0]``."""
|
|
163
|
+
direct = getattr(module, attr, None)
|
|
164
|
+
if isinstance(direct, nn.Linear):
|
|
165
|
+
return attr, direct
|
|
166
|
+
if attr not in ("to_out", "to_add_out"):
|
|
167
|
+
return None
|
|
168
|
+
try:
|
|
169
|
+
first = direct[0]
|
|
170
|
+
except (IndexError, KeyError, TypeError):
|
|
171
|
+
return None
|
|
172
|
+
return (attr + ".0", first) if isinstance(first, nn.Linear) else None
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
@dataclass
|
|
176
|
+
class Seam:
|
|
177
|
+
"""One replaceable site: a structure instance found in the host."""
|
|
178
|
+
|
|
179
|
+
structure: str
|
|
180
|
+
path: str # dotted path of the swappable module
|
|
181
|
+
parent_path: str
|
|
182
|
+
norm_attr: str | None
|
|
183
|
+
dims: dict[str, int]
|
|
184
|
+
variant: dict[str, str]
|
|
185
|
+
fc_attrs: tuple[str, str] | None = None
|
|
186
|
+
proj_attr: str | None = None # linear_proj: attr name in parent
|
|
187
|
+
pack_attrs: tuple[str, ...] | None = None # qkv_pack: sibling attrs
|
|
188
|
+
cond_attr: str | None = None # adaln_producer: cond-proj child
|
|
189
|
+
family: str = ""
|
|
190
|
+
layer_index: int = -1
|
|
191
|
+
m_profile: list[int] = field(default_factory=list)
|
|
192
|
+
#: what discovery had to take on trust to describe this seam. Carried
|
|
193
|
+
#: to the receipt: an assumption nobody can see is indistinguishable
|
|
194
|
+
#: from a fact, and these are the ones the parity gate has to check.
|
|
195
|
+
assumptions: tuple[str, ...] = ()
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
_ACT_ATTRS = ("act_fn", "activation_fn", "act", "activation")
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def _activation_of(module: nn.Module) -> tuple[str | None, bool]:
|
|
202
|
+
"""``(name, declared)`` for this module's activation.
|
|
203
|
+
|
|
204
|
+
Two different unknowns, and conflating them was a silent failure. A
|
|
205
|
+
module with *no* activation attribute tells us nothing, and the family
|
|
206
|
+
default is a reasonable assumption to record and let the parity gate
|
|
207
|
+
check. A module that *declares* an activation we cannot classify tells
|
|
208
|
+
us something specific: it is not one of the two this library
|
|
209
|
+
implements, so assuming otherwise would substitute a different
|
|
210
|
+
function and the seam is refused instead.
|
|
211
|
+
|
|
212
|
+
Returns ``(None, True)`` for the second case — declared but not ours.
|
|
213
|
+
"""
|
|
214
|
+
fn = None
|
|
215
|
+
for attr in _ACT_ATTRS:
|
|
216
|
+
fn = getattr(module, attr, None)
|
|
217
|
+
if fn is not None:
|
|
218
|
+
break
|
|
219
|
+
if fn is None:
|
|
220
|
+
return None, False
|
|
221
|
+
label = " ".join(
|
|
222
|
+
[getattr(fn, "__name__", ""), type(fn).__name__, repr(fn)]).lower()
|
|
223
|
+
if "silu" in label or "swish" in label:
|
|
224
|
+
return "silu", True
|
|
225
|
+
if "gelu" in label:
|
|
226
|
+
return "gelu", True
|
|
227
|
+
return None, True
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def _activation_or_default(module: nn.Module, default: str
|
|
231
|
+
) -> tuple[str | None, tuple[str, ...]]:
|
|
232
|
+
"""Resolve the activation, or refuse; report what was assumed.
|
|
233
|
+
|
|
234
|
+
``(None, ())`` means refuse this seam. Discovery turns that into
|
|
235
|
+
"skip"; the explicit door turns it into an error — see
|
|
236
|
+
:func:`activation_for`, which is the same decision with the other
|
|
237
|
+
outcome, so the two doors cannot drift apart.
|
|
238
|
+
"""
|
|
239
|
+
name, declared = _activation_of(module)
|
|
240
|
+
if name is not None:
|
|
241
|
+
return name, ()
|
|
242
|
+
if declared:
|
|
243
|
+
return None, () # declared, and not one of ours: refuse
|
|
244
|
+
return default, (f"activation assumed {default} (host declares none)",)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def activation_for(module: nn.Module, default: str) -> str:
|
|
248
|
+
"""The activation name for an explicitly bound module, or raise."""
|
|
249
|
+
name, _ = _activation_or_default(module, default)
|
|
250
|
+
if name is None:
|
|
251
|
+
fn = next((getattr(module, a) for a in _ACT_ATTRS
|
|
252
|
+
if getattr(module, a, None) is not None), None)
|
|
253
|
+
raise ValueError(
|
|
254
|
+
f"activation {type(fn).__name__!r} is declared by this module "
|
|
255
|
+
f"and is not one this library implements (silu or gelu)")
|
|
256
|
+
return name
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def _resolve(root: nn.Module, path: str) -> nn.Module:
|
|
260
|
+
node = root
|
|
261
|
+
for part in path.split("."):
|
|
262
|
+
if part:
|
|
263
|
+
node = node[int(part)] if part.isdigit() else getattr(node, part)
|
|
264
|
+
return node
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def _family_key(path: str) -> tuple[str, int]:
|
|
268
|
+
"""Template the trailing layer index: a.layers.12.mlp -> a.layers.{i}.mlp."""
|
|
269
|
+
matches = list(re.finditer(r"\.(\d+)\.", "." + path + "."))
|
|
270
|
+
if not matches:
|
|
271
|
+
return path, -1
|
|
272
|
+
m = matches[-1]
|
|
273
|
+
start, end = m.start(1) - 1, m.end(1) - 1 # offsets in original path
|
|
274
|
+
return path[:start] + "{i}" + path[end:], int(m.group(1))
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def _norm_attr_of(root: nn.Module, parent_path: str) -> str | None:
|
|
278
|
+
try:
|
|
279
|
+
parent = _resolve(root, parent_path)
|
|
280
|
+
except (AttributeError, IndexError, KeyError):
|
|
281
|
+
return None
|
|
282
|
+
for attr in _NORM_ATTRS:
|
|
283
|
+
if isinstance(getattr(parent, attr, None), nn.Module):
|
|
284
|
+
return attr
|
|
285
|
+
return None
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def _vision_norm_variant(
|
|
289
|
+
norm: nn.Module, dim: int,
|
|
290
|
+
) -> tuple[str | None, str]:
|
|
291
|
+
"""Classify the exact LayerNorm affine contract at a vision-FFN seam."""
|
|
292
|
+
shape = getattr(norm, "normalized_shape", None)
|
|
293
|
+
if shape is None:
|
|
294
|
+
# a fused LayerNorm twin (host accelerator libraries swap these
|
|
295
|
+
# in) often drops ``normalized_shape`` while keeping the affine
|
|
296
|
+
# contract itself: a 1-D weight names the normalized width just
|
|
297
|
+
# as authoritatively, and the parity gates certify the math
|
|
298
|
+
weight = getattr(norm, "weight", None)
|
|
299
|
+
if weight is not None and getattr(weight, "ndim", 0) == 1:
|
|
300
|
+
shape = tuple(weight.shape)
|
|
301
|
+
if isinstance(shape, int):
|
|
302
|
+
shape = (shape,)
|
|
303
|
+
try:
|
|
304
|
+
shape = tuple(shape)
|
|
305
|
+
except TypeError:
|
|
306
|
+
return None, ("norm has no LayerNorm shape contract "
|
|
307
|
+
"(normalized_shape or 1-D affine weight)")
|
|
308
|
+
if shape != (dim,) or not hasattr(norm, "eps"):
|
|
309
|
+
return None, (
|
|
310
|
+
f"norm shape/epsilon is not LayerNorm({dim}); got shape={shape}")
|
|
311
|
+
weight, bias = getattr(norm, "weight", None), getattr(norm, "bias", None)
|
|
312
|
+
if weight is None and bias is None:
|
|
313
|
+
return "identity", ""
|
|
314
|
+
if weight is None or bias is None:
|
|
315
|
+
return None, (
|
|
316
|
+
"norm exposes a one-sided affine contract (for example RMSNorm); "
|
|
317
|
+
"vision_ffn requires LayerNorm with both affine tensors or neither")
|
|
318
|
+
if tuple(weight.shape) != (dim,) or tuple(bias.shape) != (dim,):
|
|
319
|
+
return None, "norm affine tensors do not match the vision width"
|
|
320
|
+
return "learned", ""
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def discover(
|
|
324
|
+
model: nn.Module,
|
|
325
|
+
structures: tuple[str, ...] = ("decoder_ffn", "vision_ffn"),
|
|
326
|
+
*,
|
|
327
|
+
refused: list[tuple[str, str]] | None = None,
|
|
328
|
+
) -> list[Seam]:
|
|
329
|
+
"""Find every region-structure seam in ``model``."""
|
|
330
|
+
seams: list[Seam] = []
|
|
331
|
+
for path, module in model.named_modules():
|
|
332
|
+
if not path:
|
|
333
|
+
continue
|
|
334
|
+
parent_path = path.rsplit(".", 1)[0] if "." in path else ""
|
|
335
|
+
if "decoder_ffn" in structures and all(
|
|
336
|
+
# The catalog exposes only gate/up/down weights. Accepting a
|
|
337
|
+
# biased host here would silently drop parameters at the seam.
|
|
338
|
+
isinstance(getattr(module, a, None), nn.Linear)
|
|
339
|
+
and getattr(module, a).bias is None
|
|
340
|
+
for a in _DECODER_PROJ
|
|
341
|
+
):
|
|
342
|
+
gate = module.gate_proj
|
|
343
|
+
act, assumed = _activation_or_default(module, "silu")
|
|
344
|
+
if act is None:
|
|
345
|
+
continue
|
|
346
|
+
family, idx = _family_key(path)
|
|
347
|
+
seams.append(Seam(
|
|
348
|
+
structure="decoder_ffn", path=path, parent_path=parent_path,
|
|
349
|
+
norm_attr=_norm_attr_of(model, parent_path),
|
|
350
|
+
dims={"D": gate.in_features, "F": gate.out_features},
|
|
351
|
+
variant={"activation": act, "norm_weight_mode": "direct"},
|
|
352
|
+
family=family, layer_index=idx, assumptions=assumed))
|
|
353
|
+
continue
|
|
354
|
+
if "decoder_block" in structures and all(
|
|
355
|
+
isinstance(getattr(module, a, None), nn.Module)
|
|
356
|
+
for a in _BLOCK_SLOTS
|
|
357
|
+
):
|
|
358
|
+
norm_in = module.input_layernorm
|
|
359
|
+
gated = _has_cond_forward(norm_in)
|
|
360
|
+
width = getattr(module, "hidden_size", None)
|
|
361
|
+
if width is None:
|
|
362
|
+
w = getattr(norm_in, "weight", None)
|
|
363
|
+
width = (int(w.shape[-1]) if w is not None
|
|
364
|
+
else getattr(norm_in, "dim", 0))
|
|
365
|
+
family, idx = _family_key(path)
|
|
366
|
+
seams.append(Seam(
|
|
367
|
+
structure="decoder_block", path=path,
|
|
368
|
+
parent_path=parent_path, norm_attr="input_layernorm",
|
|
369
|
+
dims={"D": int(width)},
|
|
370
|
+
variant={"residual": "gated" if gated else "plain",
|
|
371
|
+
"norm": "adaln_rms" if gated else "rms",
|
|
372
|
+
"ffn_entry": "fp8_static"},
|
|
373
|
+
family=family, layer_index=idx))
|
|
374
|
+
if "modnorm_qkv_chain" in structures:
|
|
375
|
+
chain_dims = _is_modnorm_qkv_chain(module)
|
|
376
|
+
if chain_dims is not None:
|
|
377
|
+
dim, cond_dim, fanout = chain_dims
|
|
378
|
+
family, idx = _family_key(path)
|
|
379
|
+
seams.append(Seam(
|
|
380
|
+
structure="modnorm_qkv_chain", path=path,
|
|
381
|
+
parent_path=parent_path, norm_attr="norm1",
|
|
382
|
+
dims={"D": dim, "C": cond_dim},
|
|
383
|
+
variant={"modulation": "scale_shift",
|
|
384
|
+
"wire_dtype": "fp8_static",
|
|
385
|
+
"fanout": fanout},
|
|
386
|
+
family=family, layer_index=idx))
|
|
387
|
+
else:
|
|
388
|
+
table_dims = _is_table_modnorm_chain(module)
|
|
389
|
+
if table_dims is not None:
|
|
390
|
+
dim, chunks = table_dims
|
|
391
|
+
family, idx = _family_key(path)
|
|
392
|
+
seams.append(Seam(
|
|
393
|
+
structure="modnorm_qkv_chain", path=path,
|
|
394
|
+
parent_path=parent_path, norm_attr="norm1",
|
|
395
|
+
dims={"D": dim, "C": chunks},
|
|
396
|
+
variant={"modulation": "per_token_table",
|
|
397
|
+
"wire_dtype": "fp8_static",
|
|
398
|
+
"fanout": "qkv"},
|
|
399
|
+
family=family, layer_index=idx))
|
|
400
|
+
if "qkv_pack" in structures:
|
|
401
|
+
for group in _QKV_PACK:
|
|
402
|
+
projs = [getattr(module, a, None) for a in group]
|
|
403
|
+
if not all(isinstance(p, nn.Linear) for p in projs):
|
|
404
|
+
continue
|
|
405
|
+
if len({p.in_features for p in projs}) != 1:
|
|
406
|
+
continue # siblings must share the input dim
|
|
407
|
+
if projs[0].weight.numel() < _PROJ_WEIGHT_FLOOR:
|
|
408
|
+
continue
|
|
409
|
+
family, idx = _family_key(path)
|
|
410
|
+
bind = "module" if _is_attn_block(module) else "leaf"
|
|
411
|
+
seams.append(Seam(
|
|
412
|
+
structure="qkv_pack", path=path, parent_path=parent_path,
|
|
413
|
+
norm_attr=None, pack_attrs=group,
|
|
414
|
+
dims={"K": projs[0].in_features,
|
|
415
|
+
"N": sum(p.out_features for p in projs)},
|
|
416
|
+
variant={"bind": bind,
|
|
417
|
+
"in_dtype": "bf16_fused_quant"},
|
|
418
|
+
family=family, layer_index=idx))
|
|
419
|
+
if "adaln_producer" in structures:
|
|
420
|
+
cond_attr = next(
|
|
421
|
+
(a for a in _COND_PROJ_ATTRS
|
|
422
|
+
if isinstance(getattr(module, a, None), nn.Linear)), None)
|
|
423
|
+
if (cond_attr is not None and _has_cond_forward(module)
|
|
424
|
+
and getattr(module, cond_attr).out_features
|
|
425
|
+
% 2 == 0):
|
|
426
|
+
cond_proj = getattr(module, cond_attr)
|
|
427
|
+
family, idx = _family_key(path)
|
|
428
|
+
# style width is a multiple of the model dim: 3x (scale,
|
|
429
|
+
# shift, gate) for RMS AdaLN, 2x (scale, shift) for LN
|
|
430
|
+
seams.append(Seam(
|
|
431
|
+
structure="adaln_producer", path=path,
|
|
432
|
+
parent_path=parent_path, norm_attr=None,
|
|
433
|
+
cond_attr=cond_attr,
|
|
434
|
+
dims={"C": cond_proj.in_features,
|
|
435
|
+
"S": cond_proj.out_features},
|
|
436
|
+
variant={"bind": "table_only", "out_dtype": "bf16"},
|
|
437
|
+
family=family, layer_index=idx))
|
|
438
|
+
if "norm_fused" in structures and isinstance(module, nn.LayerNorm):
|
|
439
|
+
if (getattr(module, "weight", None) is not None
|
|
440
|
+
and getattr(module, "bias", None) is not None):
|
|
441
|
+
family, idx = _family_key(path)
|
|
442
|
+
seams.append(Seam(
|
|
443
|
+
structure="norm_fused", path=path,
|
|
444
|
+
parent_path=parent_path, norm_attr=None,
|
|
445
|
+
# take the dim from the affine weight: subclasses
|
|
446
|
+
# (fused LayerNorm variants) may not carry
|
|
447
|
+
# normalized_shape
|
|
448
|
+
dims={"D": int(module.weight.shape[-1])},
|
|
449
|
+
variant={"norm": "layer", "compute_dtype": "bf16"},
|
|
450
|
+
family=family, layer_index=idx))
|
|
451
|
+
if "linear_proj" in structures:
|
|
452
|
+
for group in _ATTN_PROJ:
|
|
453
|
+
resolved = [_projection_child(module, attr)
|
|
454
|
+
for attr in group]
|
|
455
|
+
if not all(item is not None for item in resolved):
|
|
456
|
+
continue
|
|
457
|
+
for attr, proj in resolved:
|
|
458
|
+
if proj.weight.numel() < _PROJ_WEIGHT_FLOOR:
|
|
459
|
+
continue
|
|
460
|
+
family, idx = _family_key(path)
|
|
461
|
+
seams.append(Seam(
|
|
462
|
+
structure="linear_proj",
|
|
463
|
+
path=path + "." + attr, parent_path=path,
|
|
464
|
+
norm_attr=None, proj_attr=attr,
|
|
465
|
+
dims={"K": proj.in_features,
|
|
466
|
+
"N": proj.out_features},
|
|
467
|
+
variant={"bias": ("add" if proj.bias is not None
|
|
468
|
+
else "none"),
|
|
469
|
+
"epilogue": "none", "in_dtype": "bf16"},
|
|
470
|
+
family=family + "." + attr, layer_index=idx))
|
|
471
|
+
if "patch_projection" in structures:
|
|
472
|
+
# Some vision processors already emit one flattened, complete
|
|
473
|
+
# spatio-temporal patch per row. Their host module spells the
|
|
474
|
+
# following projection as Conv3d, even though kernel=stride is
|
|
475
|
+
# exactly that one patch and the convolution has no overlap,
|
|
476
|
+
# padding, dilation or groups. Match this complete semantic
|
|
477
|
+
# contract; an ordinary Conv3d must never be lowered here.
|
|
478
|
+
proj = getattr(module, "proj", None)
|
|
479
|
+
if isinstance(proj, nn.Conv3d):
|
|
480
|
+
try:
|
|
481
|
+
temporal = int(module.temporal_patch_size)
|
|
482
|
+
spatial = int(module.patch_size)
|
|
483
|
+
in_channels = int(module.in_channels)
|
|
484
|
+
embed_dim = int(module.embed_dim)
|
|
485
|
+
except (AttributeError, TypeError, ValueError):
|
|
486
|
+
pass
|
|
487
|
+
else:
|
|
488
|
+
kernel = (temporal, spatial, spatial)
|
|
489
|
+
if (
|
|
490
|
+
tuple(proj.kernel_size) == kernel
|
|
491
|
+
and tuple(proj.stride) == kernel
|
|
492
|
+
and tuple(proj.padding) == (0, 0, 0)
|
|
493
|
+
and tuple(proj.dilation) == (1, 1, 1)
|
|
494
|
+
and proj.groups == 1
|
|
495
|
+
and proj.in_channels == in_channels
|
|
496
|
+
and proj.out_channels == embed_dim
|
|
497
|
+
and proj.weight.numel() >= _PROJ_WEIGHT_FLOOR
|
|
498
|
+
):
|
|
499
|
+
family, idx = _family_key(path)
|
|
500
|
+
seams.append(Seam(
|
|
501
|
+
structure="patch_projection", path=path,
|
|
502
|
+
parent_path=parent_path, norm_attr=None,
|
|
503
|
+
dims={"K": in_channels * temporal * spatial * spatial,
|
|
504
|
+
"N": embed_dim},
|
|
505
|
+
variant={"layout": "preflattened_full_patch",
|
|
506
|
+
"bias": ("add" if proj.bias is not None
|
|
507
|
+
else "none")},
|
|
508
|
+
family=family + ".patch_projection",
|
|
509
|
+
layer_index=idx,
|
|
510
|
+
))
|
|
511
|
+
if "vision_ffn" in structures:
|
|
512
|
+
for fc1_attr, fc2_attr in _VISION_PROJ:
|
|
513
|
+
fc1 = _nested_module(module, fc1_attr)
|
|
514
|
+
fc2 = _nested_module(module, fc2_attr)
|
|
515
|
+
if not (isinstance(fc1, nn.Linear)
|
|
516
|
+
and isinstance(fc2, nn.Linear)):
|
|
517
|
+
continue
|
|
518
|
+
if (fc1.out_features != fc2.in_features
|
|
519
|
+
or fc1.in_features != fc2.out_features):
|
|
520
|
+
continue # not an FFN pair: silence is right here
|
|
521
|
+
# Past this point the seam has been recognised, and every
|
|
522
|
+
# exit is a refusal against a declared boundary. Those
|
|
523
|
+
# must reach the trail: a silent skip reads as "nothing
|
|
524
|
+
# here" when the truth is "this shape, refused for this
|
|
525
|
+
# reason", and the difference is a debugging session.
|
|
526
|
+
if fc1.bias is None or fc2.bias is None:
|
|
527
|
+
if refused is not None:
|
|
528
|
+
refused.append((
|
|
529
|
+
path,
|
|
530
|
+
"vision_ffn refused: b_fc1/b_fc2 are required "
|
|
531
|
+
"slots and this host's projections carry no "
|
|
532
|
+
"bias",
|
|
533
|
+
))
|
|
534
|
+
continue
|
|
535
|
+
norm_attr = _norm_attr_of(model, parent_path)
|
|
536
|
+
if norm_attr is None:
|
|
537
|
+
if refused is not None:
|
|
538
|
+
refused.append((
|
|
539
|
+
path,
|
|
540
|
+
"vision_ffn refused: the boundary includes a "
|
|
541
|
+
"norm and no norm attribute was found beside "
|
|
542
|
+
"this feed-forward",
|
|
543
|
+
))
|
|
544
|
+
continue
|
|
545
|
+
norm = _resolve(
|
|
546
|
+
model,
|
|
547
|
+
(parent_path + "." + norm_attr).lstrip("."),
|
|
548
|
+
)
|
|
549
|
+
norm_affine, reason = _vision_norm_variant(
|
|
550
|
+
norm, fc1.in_features)
|
|
551
|
+
if norm_affine is None:
|
|
552
|
+
if refused is not None:
|
|
553
|
+
refused.append((
|
|
554
|
+
path,
|
|
555
|
+
f"vision_ffn refused: {reason}",
|
|
556
|
+
))
|
|
557
|
+
continue
|
|
558
|
+
act, assumed = _activation_or_default(module, "gelu")
|
|
559
|
+
if act is None:
|
|
560
|
+
break
|
|
561
|
+
family, idx = _family_key(path)
|
|
562
|
+
seams.append(Seam(
|
|
563
|
+
structure="vision_ffn", path=path,
|
|
564
|
+
parent_path=parent_path, norm_attr=norm_attr,
|
|
565
|
+
dims={"D": fc1.in_features, "F": fc1.out_features},
|
|
566
|
+
variant={"activation": act,
|
|
567
|
+
"norm_affine": norm_affine},
|
|
568
|
+
fc_attrs=(fc1_attr, fc2_attr),
|
|
569
|
+
family=family, layer_index=idx, assumptions=assumed))
|
|
570
|
+
break
|
|
571
|
+
return seams
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
def group_families(seams: list[Seam]) -> dict[str, list[Seam]]:
|
|
575
|
+
"""Group seams into families (same template path), index-sorted."""
|
|
576
|
+
families: dict[str, list[Seam]] = {}
|
|
577
|
+
for seam in seams:
|
|
578
|
+
families.setdefault(seam.family, []).append(seam)
|
|
579
|
+
for members in families.values():
|
|
580
|
+
members.sort(key=lambda s: s.layer_index)
|
|
581
|
+
return families
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
def seam_weights(model: nn.Module, seam: Seam) -> dict[str, torch.Tensor]:
|
|
585
|
+
"""Extract the impl-facing weight dict for one seam."""
|
|
586
|
+
module = _resolve(model, seam.path)
|
|
587
|
+
norm = (_resolve(model, seam.parent_path + "." + seam.norm_attr)
|
|
588
|
+
if seam.norm_attr else None)
|
|
589
|
+
if seam.structure == "linear_proj":
|
|
590
|
+
return {"w": module.weight.detach(),
|
|
591
|
+
"b": (module.bias.detach()
|
|
592
|
+
if module.bias is not None else None)}
|
|
593
|
+
if seam.structure == "patch_projection":
|
|
594
|
+
proj = module.proj
|
|
595
|
+
return {
|
|
596
|
+
"w": proj.weight.detach().reshape(seam.dims["N"], -1),
|
|
597
|
+
"b": (proj.bias.detach() if proj.bias is not None else None),
|
|
598
|
+
}
|
|
599
|
+
if seam.structure == "decoder_ffn":
|
|
600
|
+
w_norm = (norm.weight.detach() if norm is not None
|
|
601
|
+
and getattr(norm, "weight", None) is not None
|
|
602
|
+
else torch.ones(seam.dims["D"]))
|
|
603
|
+
return {
|
|
604
|
+
"w_norm": w_norm,
|
|
605
|
+
"w_gate": module.gate_proj.weight.detach().t().contiguous(),
|
|
606
|
+
"w_up": module.up_proj.weight.detach().t().contiguous(),
|
|
607
|
+
"w_down": module.down_proj.weight.detach().t().contiguous(),
|
|
608
|
+
}
|
|
609
|
+
fc1_attr, fc2_attr = seam.fc_attrs
|
|
610
|
+
fc1, fc2 = _nested_module(module, fc1_attr), _nested_module(
|
|
611
|
+
module, fc2_attr)
|
|
612
|
+
norm_weight = getattr(norm, "weight", None)
|
|
613
|
+
norm_bias = getattr(norm, "bias", None)
|
|
614
|
+
return {
|
|
615
|
+
"w_norm": (norm_weight.detach()
|
|
616
|
+
if norm_weight is not None else None),
|
|
617
|
+
"b_norm": (norm_bias.detach()
|
|
618
|
+
if norm_bias is not None else None),
|
|
619
|
+
"w_fc1": fc1.weight.detach(),
|
|
620
|
+
"b_fc1": fc1.bias.detach(),
|
|
621
|
+
"w_fc2": fc2.weight.detach(),
|
|
622
|
+
"b_fc2": fc2.bias.detach(),
|
|
623
|
+
}
|