hybrid_loader.py 68 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214
  1. """
  2. hybrid_loader.py — Path A: TP4-native NVFP4/NF3 hybrid loader for vLLM (modelopt path).
  3. Deploy via .pth (`import hybrid_loader`). Fires in every worker.
  4. GLM-5.2 hybrid checkpoint: routed experts are per-layer mixed — top-K (=64) NVFP4 (crisp) +
  5. the rest NF3 (3-bit, group-32). Non-experts bf16 (excluded). Stock modelopt would allocate
  6. uniform NVFP4 for all 256 experts (~420 GiB → OOM on 384). This loader allocates COMPACT
  7. two-group storage (~326 GiB) and does a reference two-pass forward.
  8. Interceptions (armed by an import hook on vllm...modelopt):
  9. 1. ModelOptNvFp4Config.from_config -> stash `hybrid_bit_map` (stock strips unknown keys).
  10. 2. FusedMoEMethodCls -> HybridNvFp4MoE.
  11. NO mapping patch: stock RoutedExperts.make_expert_params_mapping is PREFIX-based, so
  12. `...gate_proj.weight_packed` -> `...routed_experts.w13_weight_packed`, `...weight_scale` ->
  13. `...w13_weight_scale`, etc. We register compact params under those exact names; the per-layer
  14. weight_loader demuxes NVFP4 vs NF3 by the expert's group (this layer's remap) and TP-shards.
  15. Facts baked in (verified against the eldritch image):
  16. * apply(layer, x, topk_weights, topk_ids, shared_experts, shared_experts_input): routing is
  17. upstream (sigmoid/noaux_tc/norm/2.5x already applied); shared experts run by the runner
  18. separately -> apply returns ROUTED-ONLY output.
  19. * moe_kernel stays None for hybrid layers -> is_monolithic False (via experts_cls) -> apply
  20. dispatched; maybe_make_prepare_finalize overridden to None so MK-init doesn't raise.
  21. * on-disk NVFP4 block scales are LINEAR (2D) -> dequantize_to_dtype(..., swizzle=False).
  22. * TP=4, moe_intermediate=2048 -> clean chunk, no padding. gate/up shard dim0, down shard dim1.
  23. """
  24. import os, sys, importlib.abc, importlib.util
  25. _NF3_VALS = [-1.0, -0.6047, -0.3563, -0.1275, 0.1275, 0.3563, 0.6047, 1.0]
  26. _HYBRID_DEBUG = os.environ.get("HYBRID_DEBUG") not in (None, "", "0") # eager-only: per-tier norms
  27. # triton | b12x | b12x_nf3 | ref. b12x_nf3 = BOTH tiers through the b12x W4A16
  28. # CuteDSL kernel: kept-64 NVFP4 as weight_layout="packed", NF3-192 as the new
  29. # weight_layout="nf3_2p1" (e4m3_k32 scales). HYBRID_NF3 is ignored in that mode.
  30. _HYBRID_KEPT = os.environ.get("HYBRID_KEPT", "triton")
  31. _HYBRID_TIER = os.environ.get("HYBRID_TIER", "both") # both|a|b (b12x_nf3 isolation)
  32. _HYBRID_ACT_CAPTURE = os.environ.get("HYBRID_ACT_CAPTURE", "") # dir: save MoE-layer inputs for GPTQ Hessians
  33. _act_store = {"n": 0, "buf": {}, "flushed": {}}
  34. _HYBRID_NF3 = os.environ.get("HYBRID_NF3", "fast") # fast | ref (NF3 3-bit tier)
  35. _HYBRID_PROFILE = os.environ.get("HYBRID_PROFILE", "0") == "1" # per-tier CUDA-event timing at prefill M>64
  36. # TC-decode fast path for m<=8 (2026-07-05): compile a SECOND launch per tier at
  37. # size_m=max_m (small-size_m compiles are the broken family) with block-8 direct
  38. # top-k + fused sum. Measured standalone: 0.27ms vs prod 0.36-0.38ms/launch at
  39. # decode m, numerics rel<0.012. Gated OFF by default; flag-off = today's bytes.
  40. _HYBRID_TC_DECODE = os.environ.get("HYBRID_TC_DECODE", "0") == "1"
  41. # v2-lite fusion: tiers A+B share ONE fc2_out staging (disjoint (token,k)
  42. # route slots via the -1-dropping expert maps); tier B compiles with
  43. # zero_fc2_output=False so A's staged routes survive, and a SINGLE topk_sum
  44. # over the union replaces (sum_a, sum_b, add). Packed path only — tc-decode
  45. # steps keep the per-tier fused-sum + add.
  46. _HYBRID_FUSE_V2 = os.environ.get("HYBRID_FUSE_V2", "0") == "1"
  47. _prof_store = {"n": 0, "a_ms": 0.0, "b_ms": 0.0, "rows": 0, "pend": []}
  48. _dbg_first_build = [True] # keep kept-tier originals for ONLY the first b12x layer (VRAM)
  49. _HBM = None # cached hybrid_bit_map (per-process); read once from the checkpoint config.json
  50. # ---- b12x_nf3 backend constants / shared runtime ----
  51. # Pinned CTA tiles (fc1_tile_k, fc1_tile_n, fc2_tile_k, fc2_tile_n): the NF3
  52. # flat-span weight layout is packed for a SPECIFIC tile_n, but the kernel's
  53. # auto tile selection is m-dependent (fc1_tile_n flips 128<->256 across m).
  54. # (64,256,64,256) validated for our shapes (fc1 N=1024 K=6144 / fc2 N=6144
  55. # K=512) at BOTH moe_block_size 8 (decode) and 64 (prefill), both scale
  56. # formats: smem fits (45-76KB <= 100.9KB) and the SM121 reg-count table has
  57. # entries for (256,{1,4},16,4). It is also exactly what auto-selection picks
  58. # for the max-m prefill, so prefill throughput is the natural one.
  59. _B12X_NF3_TILES = (64, 256, 64, 256)
  60. _B12X_NF3_DECODE_M = 8 # <=8 -> preplanned TC-decode launch (fused topk sum)
  61. _B12X_NF3_MAX_TOKENS = int(os.environ.get("HYBRID_B12X_MAX_TOKENS", "8192"))
  62. # v1.5 stream-fusion: run tier-A (NVFP4) and tier-B (NF3) launches on CONCURRENT
  63. # streams instead of sequentially. Tier B gets its OWN scratch set (buffers_b) so
  64. # nothing races; fork/join via pre-created events (graph-capture legal). Failure
  65. # mode if the kernel host ignores torch stream ctx = launches serialize on one
  66. # stream = no overlap, still correct. Default OFF.
  67. _HYBRID_FUSE_STREAMS = os.environ.get("HYBRID_FUSE_STREAMS", "0") == "1"
  68. _b12x_nf3_rt = { # module-level, shared across ALL layers (one scratch set)
  69. "max_m": None, # fixed at first apply: max(env, first-call m)
  70. "topk": None,
  71. "launches": {}, # (E, layout, scale_fmt, topk, max_m) -> (dec, pre)
  72. "buffers": None, # W4A16PackedBuffers planned at max_m/route_E=256
  73. "buffers_b": None, # v1.5: tier-B scratch set (only when FUSE_STREAMS)
  74. "stream_b": None, # v1.5: side stream + fork/join events
  75. "ev_fork": None,
  76. "ev_join": None,
  77. "out_a": None, # [max_m, H] bf16 per-tier outputs (fully overwritten
  78. "out_b": None, # by every run_w4a16_moe call that uses them)
  79. }
  80. def _load_hbm(quant_config=None):
  81. """Reliable in-worker hybrid_bit_map: config-object attr, else read config.json off disk.
  82. (from_config stash on the config object does NOT survive pickling to TP workers.)"""
  83. global _HBM
  84. if _HBM is not None:
  85. return _HBM
  86. hbm = getattr(quant_config, "hybrid_bit_map", None) if quant_config is not None else None
  87. if hbm is None:
  88. try:
  89. import json, os
  90. from vllm.config import get_current_vllm_config
  91. mp = get_current_vllm_config().model_config.model
  92. cfgp = os.path.join(mp, "config.json")
  93. qc = json.load(open(cfgp)).get("quantization_config", {})
  94. hbm = qc.get("hybrid_bit_map")
  95. print(f"[hybrid_loader] hbm read from {cfgp}: {len(hbm) if hbm else 0} layers", flush=True)
  96. except Exception as e:
  97. print("[hybrid_loader] hbm config.json read failed:", e, flush=True)
  98. _HBM = hbm
  99. return hbm
  100. def _unpack_nf3(packed, scale, out_cols, blk=32):
  101. """packed:[R, out_cols//8*3] uint8, scale:[R, out_cols//blk] fp8 -> [R, out_cols] bf16."""
  102. import torch
  103. nf = torch.tensor(_NF3_VALS, device=packed.device, dtype=torch.float32)
  104. R = packed.shape[0]
  105. p = packed.reshape(R, out_cols // 8, 3).to(torch.int32)
  106. w24 = p[..., 0] | (p[..., 1] << 8) | (p[..., 2] << 16)
  107. codes = torch.stack([(w24 >> (3 * i)) & 0x7 for i in range(8)], -1).reshape(R, out_cols)
  108. return (nf[codes.long()] * scale.float().repeat_interleave(blk, 1)).to(torch.bfloat16)
  109. def _fp8_ne_transform(weights):
  110. """Dequant fp8 non-expert weights -> bf16 on the fly. Speaks BOTH scale
  111. dialects: `.weight_scale_fp8` (rev-2, bf16 per-channel) and `.weight_scale`
  112. U8 (rev-3 MXFP8, e8m0 per-32 groups, [out, in//32]). Expert tensors never
  113. match (uint8-packed weights / F8 scales) and pass through untouched."""
  114. import torch
  115. scales, pend = {}, {}
  116. def _deq(w, s):
  117. kind, st = s
  118. if kind == "chan":
  119. return (w.to(torch.float32) * st.to(torch.float32).unsqueeze(1)).to(torch.bfloat16)
  120. sc = torch.pow(2.0, st.to(torch.float32) - 127.0)
  121. return (w.to(torch.float32) * sc.repeat_interleave(32, 1)).to(torch.bfloat16)
  122. def _stage(t):
  123. # fastsafetensors yields CUDA tensors; holding tier pairs in VRAM
  124. # mid-shard OOMs the load. CPU-stage ONLY the F8 tier (16GB of 327) —
  125. # experts keep streaming GPU-direct.
  126. return t.cpu() if getattr(t, "is_cuda", False) else t
  127. for name, t in weights:
  128. if name.endswith(".weight_scale_fp8"):
  129. wn = name[:-len(".weight_scale_fp8")] + ".weight"
  130. w = pend.pop(wn, None)
  131. if w is not None:
  132. yield wn, _deq(w, ("chan", _stage(t)))
  133. else:
  134. scales[wn] = ("chan", _stage(t))
  135. elif (name.endswith(".weight_scale")
  136. and getattr(t, "dtype", None) == torch.uint8 and t.dim() == 2):
  137. wn = name[:-len(".weight_scale")] + ".weight"
  138. w = pend.pop(wn, None)
  139. if w is not None:
  140. yield wn, _deq(w, ("mx", _stage(t)))
  141. else:
  142. scales[wn] = ("mx", _stage(t))
  143. elif name.endswith(".weight") and getattr(t, "dtype", None) == torch.float8_e4m3fn:
  144. s = scales.pop(name, None)
  145. if s is not None:
  146. yield name, _deq(_stage(t), s)
  147. else:
  148. pend[name] = _stage(t)
  149. else:
  150. yield name, t
  151. for wn, t in pend.items(): # unmatched fp8 weight (shouldn't happen) -> best-effort
  152. yield wn, t.to(torch.bfloat16)
  153. def _deq_nv(w, s, g, gs, deq):
  154. """NVFP4 dequant (linear on-disk scales). g is [2] for fused w13 or scalar for w2."""
  155. import torch
  156. if g.numel() == 2: # fused w13: gate rows use g[0], up rows use g[1]
  157. half = w.shape[0] // 2
  158. a = deq(w[:half], s[:half], g[0], torch.bfloat16, gs, swizzle=False)
  159. b = deq(w[half:], s[half:], g[1], torch.bfloat16, gs, swizzle=False)
  160. return torch.cat([a, b], 0)
  161. return deq(w, s, g.reshape(()), torch.bfloat16, gs, swizzle=False)
  162. def _patch(mod):
  163. import re, torch
  164. import torch.nn.functional as F
  165. from vllm.model_executor.utils import set_weight_attrs
  166. from vllm.model_executor.layers.quantization.utils.nvfp4_emulation_utils import dequantize_to_dtype
  167. from vllm.distributed import (get_tensor_model_parallel_rank,
  168. get_tensor_model_parallel_world_size)
  169. Base = mod.ModelOptNvFp4FusedMoE
  170. Cfg = mod.ModelOptNvFp4Config
  171. # ---- 1. keep hybrid_bit_map alive through from_config ----
  172. _orig_fc = getattr(Cfg.from_config, "__func__", Cfg.from_config)
  173. def _from_config(cls, config):
  174. obj = _orig_fc(cls, config)
  175. hbm = None
  176. kf = None
  177. if isinstance(config, dict):
  178. hbm = config.get("hybrid_bit_map")
  179. kf = config.get("kept_format")
  180. if isinstance(config.get("quantization"), dict):
  181. hbm = hbm or config["quantization"].get("hybrid_bit_map")
  182. kf = kf or config["quantization"].get("kept_format")
  183. try:
  184. obj.hybrid_bit_map = hbm
  185. obj.kept_format = kf
  186. print(f"[hybrid_loader] hybrid_bit_map stashed: "
  187. f"{len(hbm) if hbm else 0} layers"
  188. f"{' kept_format=' + kf if kf else ''}", flush=True)
  189. except Exception as e:
  190. print("[hybrid_loader] stash failed:", e, flush=True)
  191. return obj
  192. Cfg.from_config = classmethod(_from_config)
  193. class HybridNvFp4MoE(Base):
  194. def maybe_make_prepare_finalize(self, *a, **k):
  195. return None # we own the forward via apply(); no external prepare/finalize
  196. def _bits(self, layer):
  197. hbm = _load_hbm(self.quant_config)
  198. pfx = getattr(layer, "prefix", None)
  199. if pfx is None:
  200. pfx = getattr(layer, "layer_name", "") or ""
  201. m = re.search(r"layers\.(\d+)\b", str(pfx))
  202. b = hbm.get(str(int(m.group(1)))) if (hbm and m) else None
  203. if b is None:
  204. print(f"[hybrid][MISS] pfx={pfx!r} hbm_len={len(hbm) if hbm else 0} "
  205. f"idx={m.group(1) if m else None}", flush=True)
  206. return b
  207. def create_weights(self, layer, num_experts, hidden_size,
  208. intermediate_size_per_partition, params_dtype, **extra):
  209. bits = self._bits(layer)
  210. # v3: kept tier is MXFP4 (e2m1 + ue8m0/32) ONLY for hybrid-mapped
  211. # layers; the MTP/uniform layer (bits None) stays NVFP4.
  212. kept_mx = (bits is not None and
  213. getattr(self.quant_config, "kept_format", None)
  214. == "mxfp4_e8m0k32")
  215. if bits is None:
  216. # Non-hybrid MoE (the MTP/nextn layer) — its experts are uniform NVFP4.
  217. # Route it through OUR path as all-kept (bits=4) so it uses our Triton NVFP4
  218. # kernel + our weight_loader. (Falling to super() uses the stock MoE loader,
  219. # whose weight-scale quant_method check at routed_experts.py:906 rejects it
  220. # under our method -> the MTP boot crash.)
  221. bits = [4] * num_experts
  222. H, I = hidden_size, intermediate_size_per_partition
  223. gs = self.quant_config.group_size
  224. tp_rank = get_tensor_model_parallel_rank()
  225. tp_size = get_tensor_model_parallel_world_size()
  226. kept = [e for e, b in enumerate(bits) if b == 4]
  227. dem = [e for e, b in enumerate(bits) if b == 3]
  228. Kn, Km = len(kept), len(dem)
  229. layer.hyb = {"remap": {**{e: (0, i) for i, e in enumerate(kept)},
  230. **{e: (1, i) for i, e in enumerate(dem)}},
  231. "H": H, "I": I, "gs": gs, "E": num_experts,
  232. "kept_mx": kept_mx}
  233. _pfx = getattr(layer, "prefix", None) or getattr(layer, "layer_name", "?")
  234. layer.hyb["lname"] = str(_pfx)
  235. print(f"[hybrid] {_pfx}: {Kn}{'MXFP4' if kept_mx else 'NVFP4'} + "
  236. f"{Km}NF3 (tp{tp_rank}/{tp_size} I={I})", flush=True)
  237. def wl(param, loaded, name_mapped=None, *, shard_id=None,
  238. expert_id=None, return_success=False, **kw):
  239. nm = name_mapped or ""
  240. if "input_scale" in nm: # W4A16 reference -> unused
  241. return True
  242. grp, li = layer.hyb["remap"][int(expert_id)]
  243. fam = "w13" if "w13_" in nm else "w2"
  244. sh = shard_id
  245. if "weight_scale_2" in nm: # NVFP4 per-tensor global (kept only)
  246. tgt = getattr(layer, f"{fam}_weight_scale_2")
  247. if fam == "w13":
  248. tgt.data[li, 0 if sh == "w1" else 1] = loaded.reshape(()).to(tgt.dtype)
  249. else:
  250. tgt.data[li] = loaded.reshape(()).to(tgt.dtype)
  251. return True
  252. # TP shard the block-quantized 2D tensor (gate/up -> dim0, down -> dim1)
  253. if tp_size > 1 and loaded.ndim >= 2:
  254. if sh in ("w1", "w3"):
  255. loaded = loaded.chunk(tp_size, 0)[tp_rank]
  256. elif sh == "w2":
  257. loaded = loaded.chunk(tp_size, 1)[tp_rank]
  258. if "weight_scale" in nm: # block scale -> real storage, demux by group
  259. tgt = getattr(layer, f"{fam}_nv_s" if grp == 0 else f"{fam}_nf_s")
  260. elif "weight_packed" in nm: # NF3 packed weight
  261. tgt = getattr(layer, f"{fam}_weight_packed")
  262. else: # plain NVFP4 weight
  263. tgt = getattr(layer, f"{fam}_weight")
  264. d = tgt.data[li]
  265. if fam == "w13" and sh in ("w1", "w3"): # gate->top half, up->bottom half
  266. half = d.shape[0] // 2
  267. d = d[:half] if sh == "w1" else d[half:]
  268. d.copy_(loaded.reshape(d.shape).to(d.dtype))
  269. return True
  270. def P(name, shape, dt=torch.uint8):
  271. p = torch.nn.Parameter(torch.zeros(shape, dtype=dt,
  272. device=torch.cuda.current_device()), requires_grad=False)
  273. set_weight_attrs(p, {"weight_loader": wl})
  274. layer.register_parameter(name, p)
  275. mk = lambda n: max(n, 1)
  276. # --- names the stock (prefix-based) mapping produces (routing needs no patch) ---
  277. P("w13_weight", (mk(Kn), 2 * I, H // 2)) # NVFP4 weight (kept)
  278. P("w13_weight_packed", (mk(Km), 2 * I, H // 8 * 3)) # NF3 packed weight (demoted)
  279. P("w13_weight_scale", (1,)) # dispatcher (routes to *_s)
  280. P("w13_weight_scale_2", (mk(Kn), 2), torch.float32) # NVFP4 global (kept)
  281. P("w13_input_scale", (1,), torch.float32) # dispatcher (ignored)
  282. P("w2_weight", (mk(Kn), H, I // 2))
  283. P("w2_weight_packed", (mk(Km), H, I // 8 * 3))
  284. P("w2_weight_scale", (1,))
  285. P("w2_weight_scale_2", (mk(Kn),), torch.float32)
  286. P("w2_input_scale", (1,), torch.float32)
  287. # --- real block-scale storage (filled by dispatcher; not mapping-routed) ---
  288. # mx kept tier: ue8m0 scales at group 32 (uint8) instead of e4m3/gs.
  289. nv_gs = 32 if kept_mx else gs
  290. nv_dt = torch.uint8 if kept_mx else torch.float8_e4m3fn
  291. for nm, sh, dt_ in [("w13_nv_s", (mk(Kn), 2 * I, H // nv_gs), nv_dt),
  292. ("w13_nf_s", (mk(Km), 2 * I, H // 32), torch.float8_e4m3fn),
  293. ("w2_nv_s", (mk(Kn), H, I // nv_gs), nv_dt),
  294. ("w2_nf_s", (mk(Km), H, I // 32), torch.float8_e4m3fn)]:
  295. layer.register_parameter(nm, torch.nn.Parameter(
  296. torch.zeros(sh, dtype=dt_,
  297. device=torch.cuda.current_device()), requires_grad=False))
  298. def _build_kept_b12x(self, layer):
  299. """Build a REAL b12x NVFP4 fused-MoE kernel over just the Kn kept experts.
  300. Reuses the production kernel (graph-safe, sm120) via a cloned num_experts=Kn
  301. FusedMoEConfig. Validated standalone: correct + skips out-of-range ids + cudagraph-safe.
  302. apply() remaps topk so kept->[0,Kn), non-kept->Kn (the kernel drops the sentinel)."""
  303. import dataclasses
  304. import torch.nn as _nn
  305. from vllm.model_executor.layers.fused_moe.oracle.nvfp4 import (
  306. select_nvfp4_moe_backend, convert_to_nvfp4_moe_kernel_format,
  307. make_nvfp4_moe_quant_config, make_nvfp4_moe_kernel)
  308. from vllm.model_executor.layers.fused_moe.config import FusedMoEParallelConfig
  309. from vllm.model_executor.layers.quantization.utils.quant_utils import kNvfp4Static
  310. from vllm.model_executor.layers.fused_moe.activation import MoEActivation
  311. E = layer.hyb["E"]
  312. dev = layer.w13_weight.device
  313. remap = layer.hyb["remap"]
  314. Kn = sum(1 for (grp, li) in remap.values() if grp == 0)
  315. # Build the kept kernel as a NON-PARALLEL (tp=1) MoE over the PER-RANK intermediate:
  316. # the weights are already TP-sharded by the weight_loader (ispp per rank), so the
  317. # kernel must see intermediate_size == ispp and tp=1 (else it mis-indexes full vs
  318. # sharded -> per-element garbage). The layer's post-apply all-reduce handles TP.
  319. ispp = self.moe.intermediate_size_per_partition
  320. kept_moe = dataclasses.replace(
  321. self.moe, num_experts=Kn, num_local_experts=Kn, num_logical_experts=Kn,
  322. intermediate_size=ispp,
  323. moe_parallel_config=FusedMoEParallelConfig.make_no_parallel())
  324. backend, experts_cls = select_nvfp4_moe_backend(
  325. config=kept_moe, weight_key=kNvfp4Static, activation_key=None)
  326. KL = _nn.Module()
  327. KL.activation = getattr(layer, "activation", MoEActivation.SILU)
  328. KL.moe_config = kept_moe
  329. KL.local_num_experts = Kn
  330. a13 = torch.ones(Kn, 2, device=dev, dtype=torch.float32)
  331. a2 = torch.ones(Kn, device=dev, dtype=torch.float32)
  332. w13ks2 = layer.w13_weight_scale_2[:, 0].contiguous()
  333. conv = convert_to_nvfp4_moe_kernel_format(
  334. nvfp4_backend=backend, layer=KL,
  335. w13=layer.w13_weight, w13_scale=layer.w13_nv_s, w13_scale_2=w13ks2, a13_scale=a13,
  336. w2=layer.w2_weight, w2_scale=layer.w2_nv_s, w2_scale_2=layer.w2_weight_scale_2,
  337. a2_scale=a2, is_act_and_mul=True, use_a16=True)
  338. (cw13, cw13s, cw13s2, ca13, cw2, cw2s, cw2s2, ca2) = conv
  339. for k, v in [("w13_weight", cw13), ("w13_weight_scale", cw13s),
  340. ("w13_weight_scale_2", cw13s2), ("w13_input_scale", ca13),
  341. ("w2_weight", cw2), ("w2_weight_scale", cw2s),
  342. ("w2_weight_scale_2", cw2s2), ("w2_input_scale", ca2)]:
  343. setattr(KL, k, v)
  344. qconf = make_nvfp4_moe_quant_config(backend, cw13s, cw2s, cw13s2, cw2s2,
  345. ca13, ca2, use_a16=True)
  346. kk = make_nvfp4_moe_kernel(qconf, kept_moe, experts_cls, routing_tables=None)
  347. kk.fused_experts.process_weights_after_loading(KL)
  348. # Mark this method as owning its modular kernel (supports_internal_mk -> True) so
  349. # vLLM's post-load maybe_init_modular_kernel() returns early instead of rebuilding
  350. # the parent kernel from the (freed) standard weight attrs.
  351. self.moe_kernel = kk
  352. # remap: global -> kept-local, else sentinel Kn (b12x skips ids >= num_experts)
  353. nvfp4_remap = torch.full((E,), Kn, dtype=torch.int32, device=dev)
  354. for g, (grp, li) in remap.items():
  355. if grp == 0:
  356. nvfp4_remap[g] = li
  357. if _HYBRID_DEBUG and not _b12x_nf3_rt.get("_selftested"):
  358. _b12x_nf3_rt["_selftested"] = True
  359. try:
  360. from vllm.distributed import get_tensor_model_parallel_rank as _gr
  361. _rk = _gr()
  362. except Exception:
  363. _rk = -1
  364. xt = torch.randn(4, layer.hyb["H"], device=dev, dtype=torch.bfloat16) * 0.03
  365. ids = (torch.arange(32, device=dev, dtype=torch.int32) % Kn).reshape(4, 8)
  366. tww = torch.full((4, 8), 0.125, device=dev, dtype=torch.float32)
  367. o = kk.apply(xt, KL.w13_weight, KL.w2_weight, tww, ids,
  368. activation=KL.activation, global_num_experts=Kn,
  369. expert_map=None, apply_router_weight_on_input=False,
  370. shared_experts=None, shared_experts_input=None)
  371. torch.cuda.synchronize()
  372. print(f"[selftest] r{_rk} {getattr(layer, 'prefix', '?')}: "
  373. f"out={o.float().norm():.4f} inf={bool(torch.isinf(o).any())} "
  374. f"nan={bool(torch.isnan(o).any())} "
  375. f"cw13={KL.w13_weight.view(torch.uint8).float().mean():.3f} "
  376. f"cw13s2_max={KL.w13_weight_scale_2.float().abs().max():.3e} "
  377. f"cw2s2_max={KL.w2_weight_scale_2.float().abs().max():.3e}", flush=True)
  378. layer.hyb["kept_kernel"] = kk
  379. layer.hyb["kept_KL"] = KL
  380. layer.hyb["Kn"] = Kn
  381. layer.hyb["nvfp4_remap"] = nvfp4_remap
  382. # CRITICAL: keep the converted tensors alive past this function. b12x's
  383. # process_weights compacts the source weight to (0,) but its prepared weights
  384. # VIEW the converted `cw13`/`cw2`; if those locals are freed on return the views
  385. # dangle -> per-layer garbage (works in a script where they stay in scope).
  386. layer.hyb["_keepalive"] = conv
  387. # free the BIG compact kept originals (KL holds the converted copies) -> flat VRAM.
  388. # keep the tiny *_weight_scale* params (get_fused_moe_quant_config may still read them).
  389. keep_dbg = _HYBRID_DEBUG and _dbg_first_build[0] # keep originals for ONE layer only
  390. if keep_dbg:
  391. _dbg_first_build[0] = False
  392. for nm in ("w13_weight", "w2_weight", "w13_nv_s", "w2_nv_s"):
  393. if not keep_dbg and hasattr(layer, nm):
  394. try:
  395. delattr(layer, nm)
  396. except Exception:
  397. setattr(layer, nm, None)
  398. print(f"[hybrid] {getattr(layer, 'prefix', '?')}: kept b12x kernel built "
  399. f"(Kn={Kn}, backend={backend}, kept_ispp={kept_moe.intermediate_size_per_partition}, "
  400. f"kept_tp={kept_moe.moe_parallel_config.tp_size}, "
  401. f"w13={tuple(KL.w13_weight.shape)})", flush=True)
  402. def _build_kept_mxfp4(self, layer):
  403. """v3 kept tier: MXFP4 (e2m1 + ue8m0/32) over the Kn kept experts
  404. via the stock mxfp4 oracle chain. The B12X backend's convert is a
  405. passthrough — repacking happens inside process_weights_after_loading.
  406. A16 by default; A8 opt-in via HYBRID_MX_A8=1 (KLD-gate before daily).
  407. Mirrors _build_kept_b12x's no-parallel-clone + keepalive shape."""
  408. import dataclasses
  409. import os as _os
  410. import torch.nn as _nn
  411. from vllm.model_executor.layers.fused_moe.oracle.mxfp4 import (
  412. select_mxfp4_moe_backend, convert_weight_to_mxfp4_moe_kernel_format,
  413. make_mxfp4_moe_quant_config, make_mxfp4_moe_kernel)
  414. from vllm.model_executor.layers.fused_moe.config import FusedMoEParallelConfig
  415. from vllm.model_executor.layers.fused_moe.activation import MoEActivation
  416. E = layer.hyb["E"]
  417. dev = layer.w13_weight.device
  418. remap = layer.hyb["remap"]
  419. Kn = sum(1 for (grp, li) in remap.values() if grp == 0)
  420. ispp = self.moe.intermediate_size_per_partition
  421. kept_moe = dataclasses.replace(
  422. self.moe, num_experts=Kn, num_local_experts=Kn, num_logical_experts=Kn,
  423. intermediate_size=ispp,
  424. moe_parallel_config=FusedMoEParallelConfig.make_no_parallel())
  425. act_key = None
  426. if _os.environ.get("HYBRID_MX_A8", "0") == "1":
  427. from vllm.model_executor.layers.quantization.utils.quant_utils import (
  428. kFp8StaticTensorSym)
  429. act_key = kFp8StaticTensorSym
  430. backend, experts_cls = select_mxfp4_moe_backend(
  431. kept_moe, activation_key=act_key)
  432. KL = _nn.Module()
  433. KL.activation = getattr(layer, "activation", MoEActivation.SILU)
  434. KL.moe_config = kept_moe
  435. KL.local_num_experts = Kn
  436. cw13, cw2, cw13s, cw2s, _b13, _b2 = (
  437. convert_weight_to_mxfp4_moe_kernel_format(
  438. backend, KL, layer.w13_weight, layer.w2_weight,
  439. layer.w13_nv_s, layer.w2_nv_s))
  440. for k, v in [("w13_weight", cw13), ("w13_weight_scale", cw13s),
  441. ("w2_weight", cw2), ("w2_weight_scale", cw2s)]:
  442. setattr(KL, k, v)
  443. qconf = make_mxfp4_moe_quant_config(backend, cw13s, cw2s, layer=KL)
  444. kk = make_mxfp4_moe_kernel(qconf, kept_moe, experts_cls,
  445. routing_tables=None)
  446. kk.fused_experts.process_weights_after_loading(KL)
  447. self.moe_kernel = kk
  448. mx_remap = torch.full((E,), Kn, dtype=torch.int32, device=dev)
  449. for g, (grp, li) in remap.items():
  450. if grp == 0:
  451. mx_remap[g] = li
  452. layer.hyb["kept_kernel"] = kk
  453. layer.hyb["kept_KL"] = KL
  454. layer.hyb["nvfp4_remap"] = mx_remap
  455. layer.hyb["_keepalive_mx"] = (cw13, cw2, cw13s, cw2s)
  456. for nm in ("w13_weight", "w2_weight", "w13_nv_s", "w2_nv_s"):
  457. if hasattr(layer, nm):
  458. try:
  459. delattr(layer, nm)
  460. except Exception:
  461. setattr(layer, nm, None)
  462. print(f"[hybrid] {getattr(layer, 'prefix', '?')}: kept MXFP4 kernel "
  463. f"built (Kn={Kn}, backend={backend}, a8={act_key is not None})",
  464. flush=True)
  465. def _build_b12x_nf3(self, layer):
  466. """HYBRID_KEPT=b12x_nf3: drive BOTH tiers through the b12x W4A16
  467. CuteDSL MoE kernel.
  468. Object A (kept NVFP4) -> the PRODUCTION vLLM chain via
  469. _build_kept_b12x (select_nvfp4_moe_backend -> convert_to_nvfp4_
  470. moe_kernel_format -> make_nvfp4_moe_kernel, no-parallel clone,
  471. keepalive). Manual composition through the prepare building
  472. blocks is numerically WRONG for varying real-range scales
  473. (harness-proven 2026-07-01: only the production convert chain
  474. passes vs the dequant reference; probe test_b12x.py TESTS A-D).
  475. Object B (NF3 192) -> weight_layout="nf3_2p1"/e4m3_k32 packed
  476. from the 837 checkpoint planes (chunked over experts) through
  477. our NF3 kernel format (GPU unit test + in-model norms PASS).
  478. Launches/buffers are built lazily at first apply() (topk + real max
  479. m known there; the first forward is vLLM's EAGER profile run, so
  480. nothing compiles inside CUDA-graph capture)."""
  481. import torch
  482. from b12x.moe.fused.w4a16.prepare import (
  483. PreparedNF3MoeWeights,
  484. W4A16PackedWeights,
  485. _make_workspace,
  486. _nf3_pack_code_experts,
  487. _nf3_pack_scale_experts,
  488. _permute_nvfp4_scales,
  489. _repack_weight,
  490. )
  491. import nf3_replan
  492. hyb = layer.hyb
  493. E, H, I = hyb["E"], hyb["H"], hyb["I"]
  494. remap = hyb["remap"]
  495. dev = layer.w13_weight.device
  496. Kn = sum(1 for (grp, _li) in remap.values() if grp == 0)
  497. Km = sum(1 for (grp, _li) in remap.values() if grp == 1)
  498. emap_a = torch.full((E,), -1, dtype=torch.int32, device=dev)
  499. emap_b = torch.full((E,), -1, dtype=torch.int32, device=dev)
  500. for g, (grp, li) in remap.items():
  501. (emap_a if grp == 0 else emap_b)[g] = li
  502. fc1_tn, fc2_tn = _B12X_NF3_TILES[1], _B12X_NF3_TILES[3]
  503. # ---- object B: NF3 -> "nf3_2p1" (chunked over experts) ----
  504. # (built FIRST: object A's production build frees the kept originals)
  505. prep_b = None
  506. if Km > 0:
  507. chunk = 16 # bound transient VRAM (codes int32 = ~400MB/16 w13 experts)
  508. w13_planes, w2_planes = [], []
  509. for e0 in range(0, Km, chunk):
  510. codes = nf3_replan.unpack_837_codes(
  511. layer.w13_weight_packed[e0:e0 + chunk], H)
  512. w13_planes.append(_nf3_pack_code_experts(
  513. codes, size_k=H, size_n=2 * I, tile_n=fc1_tn))
  514. del codes
  515. for e0 in range(0, Km, chunk):
  516. codes = nf3_replan.unpack_837_codes(
  517. layer.w2_weight_packed[e0:e0 + chunk], I)
  518. w2_planes.append(_nf3_pack_code_experts(
  519. codes, size_k=I, size_n=H, tile_n=fc2_tn))
  520. del codes
  521. w13_nf3 = torch.cat(w13_planes, 0).contiguous(); del w13_planes
  522. w2_nf3 = torch.cat(w2_planes, 0).contiguous(); del w2_planes
  523. w13_ns = _nf3_pack_scale_experts(
  524. layer.w13_nf_s.float(), size_k=H, size_n=2 * I)
  525. w2_ns = _nf3_pack_scale_experts(
  526. layer.w2_nf_s.float(), size_k=I, size_n=H)
  527. nf3_global = torch.full(
  528. (Km,), 2.0 ** 116, dtype=torch.float32, device=dev)
  529. prep_b = PreparedNF3MoeWeights(
  530. w13=w13_nf3, w13_scale=w13_ns, w13_global_scale=nf3_global,
  531. w2=w2_nf3, w2_scale=w2_ns,
  532. w2_global_scale=nf3_global.clone(),
  533. workspace=_make_workspace(dev),
  534. hidden_size=H, intermediate_size=I, num_experts=Km,
  535. is_gated=True, params_dtype=torch.bfloat16,
  536. fc1_tile_n=fc1_tn, fc2_tile_n=fc2_tn)
  537. hyb["prepB"] = prep_b
  538. hyb["prepA"] = None # filled by the kept build below
  539. hyb["emap_a"], hyb["emap_b"] = emap_a, emap_b
  540. hyb["Kn"], hyb["Km"] = Kn, Km
  541. keep_dbg = _HYBRID_DEBUG and _dbg_first_build[0]
  542. if keep_dbg:
  543. _dbg_first_build[0] = False
  544. # ---- object A: kept NVFP4 -> manual "packed" composition.
  545. # REHABILITATED 2026-07-01: byte-identical to the stock prepare entry
  546. # (verified) and PASSES the FIXED (swizzle=False) dequant reference on
  547. # ranks 0/1/2 at rel 0.006. The earlier condemnation used a broken
  548. # reference. Produces weight_layout="packed" -> TC-decode launches
  549. # compile; NO modular kernel / workspace manager in the forward.
  550. if Kn > 0:
  551. g13 = layer.w13_weight_scale_2[:Kn, 0].contiguous()
  552. g2 = layer.w2_weight_scale_2[:Kn].contiguous()
  553. w13_packed = _repack_weight(
  554. layer.w13_weight.contiguous(), size_k=H, size_n=2 * I)
  555. w2_packed = _repack_weight(
  556. layer.w2_weight.contiguous(), size_k=I, size_n=H)
  557. w13_ps, w13_pg = _permute_nvfp4_scales(
  558. layer.w13_nv_s, g13, size_k=H, size_n=2 * I,
  559. a_dtype=torch.bfloat16)
  560. w2_ps, w2_pg = _permute_nvfp4_scales(
  561. layer.w2_nv_s, g2, size_k=I, size_n=H,
  562. a_dtype=torch.bfloat16)
  563. hyb["prepA"] = W4A16PackedWeights(
  564. w13=w13_packed, w13_scale=w13_ps, w13_global_scale=w13_pg,
  565. w2=w2_packed, w2_scale=w2_ps, w2_global_scale=w2_pg,
  566. workspace=_make_workspace(dev),
  567. hidden_size=H, intermediate_size=I, num_experts=Kn,
  568. is_gated=True, params_dtype=torch.bfloat16,
  569. source_format="modelopt_nvfp4", w13_layout="w13",
  570. weight_layout="packed", scale_format="e4m3_k16")
  571. if not keep_dbg:
  572. for nm in ("w13_weight", "w2_weight", "w13_nv_s", "w2_nv_s"):
  573. p_ = getattr(layer, nm, None)
  574. if p_ is not None and getattr(p_, "data", None) is not None:
  575. p_.data = p_.data.new_empty((0,))
  576. if not keep_dbg:
  577. for nm in ("w13_weight_packed", "w2_weight_packed",
  578. "w13_nf_s", "w2_nf_s"):
  579. p = getattr(layer, nm, None)
  580. if p is not None and getattr(p, "data", None) is not None:
  581. p.data = p.data.new_empty((0,))
  582. print(f"[hybrid] {getattr(layer, 'prefix', '?')}: b12x_nf3 built "
  583. f"(Kn={Kn} via production chain + Km={Km} nf3_2p1, "
  584. f"tiles={_B12X_NF3_TILES})", flush=True)
  585. def _ensure_b12x_nf3_runtime(self, layer, m, topk):
  586. """First-apply init: pinned-tile preplanned launches (per object) +
  587. ONE module-level scratch/buffer set. First apply = vLLM's eager
  588. profile run at max_num_batched_tokens, so max_m sizes itself to the
  589. real serving ceiling and nothing compiles during graph capture."""
  590. import dataclasses
  591. import torch
  592. from b12x.moe.fused.w4a16.kernel import compile_w4a16_fused_moe
  593. from b12x.moe.fused.w4a16.host import (
  594. make_w4a16_packed_buffers, max_packed_route_slots)
  595. hyb = layer.hyb
  596. st = _b12x_nf3_rt
  597. E, H, I = hyb["E"], hyb["H"], hyb["I"]
  598. dev = hyb["emap_a"].device
  599. if st["max_m"] is None:
  600. st["max_m"] = max(_B12X_NF3_MAX_TOKENS, int(m))
  601. st["topk"] = int(topk)
  602. if int(topk) != st["topk"]:
  603. raise RuntimeError(
  604. f"b12x_nf3: topk changed {st['topk']} -> {topk}")
  605. props = torch.cuda.get_device_properties(dev)
  606. sms = int(props.multi_processor_count)
  607. max_shared_mem = int(getattr(
  608. props, "shared_memory_per_block_optin", 101_376))
  609. def launches(prepared, zero_out=True):
  610. key = (prepared.num_experts, prepared.weight_layout,
  611. prepared.scale_format, st["topk"], st["max_m"], H, I,
  612. zero_out)
  613. got = st["launches"].get(key)
  614. if got is not None:
  615. return got
  616. common = dict(
  617. hidden_size=H, intermediate_size=I,
  618. num_experts=prepared.num_experts, top_k=st["topk"],
  619. activation="silu", apply_router_weight_on_input=False,
  620. element_dtype="bf16", fast_math=True, sms=sms,
  621. max_shared_mem=max_shared_mem,
  622. weight_layout=prepared.weight_layout,
  623. scale_format=prepared.scale_format,
  624. force_tile_config=_B12X_NF3_TILES)
  625. # ONE launch per object for ALL m (1..max_m): spec-0 (size_m>=2)
  626. # block-64 packed-route + expert_map + zero_fc2_output=True.
  627. # VALIDATED on real ckpt data at m=1/8/33 (rel 0.02-0.05).
  628. # TC-decode/block-8 and the size_m=1 compile are BROKEN for these
  629. # shapes+tiles (rel 1.4 / 197) — never use them. Decode padding
  630. # cost ~0: blocks exist only for ACTIVE experts; pad slots waste
  631. # ALU, not HBM bytes, and decode is bandwidth-bound.
  632. cap_slots = max_packed_route_slots(st["max_m"] * st["topk"], 64, E)
  633. pre = compile_w4a16_fused_moe(
  634. size_m=st["max_m"], zero_fc2_output=zero_out,
  635. moe_block_size=64, max_m_blocks=(cap_slots + 63) // 64,
  636. direct_topk_routes=False, tc_decode_fused_sum=False,
  637. **common)
  638. assert (int(pre.fc1_tile_n), int(pre.fc2_tile_n)) == (
  639. _B12X_NF3_TILES[1], _B12X_NF3_TILES[3]), "tile pin failed"
  640. dec = pre
  641. if _HYBRID_TC_DECODE:
  642. # dec launch: SMALL size_m (8) direct-topk + fused-sum at FORCED
  643. # PIN tiles. Needs the op-boundary tile-config passthrough fix
  644. # (b12x_nf3_*_fix/kernel.py): the stock op re-resolves its kernel
  645. # WITHOUT force_tile_config, silently swapping PIN->auto so the
  646. # 256-pack was read with wrong geometry (garbage rel 1.3-1.5 at
  647. # m=1,6,8). Fixed kernel honors the forced PIN -> reads the SAME
  648. # production 256-pack (NO 2nd pack, NO pool cost). Opus-validated
  649. # rel 0.006-0.011 @ m=1..8, single-compile reuse worst 0.0099.
  650. # 0.277ms vs packed 0.365ms = ~14ms/step decode bounty.
  651. # Run side: LUT-mapped local ids, NO expert_map (direct-topk).
  652. try:
  653. cand = compile_w4a16_fused_moe(
  654. size_m=_B12X_NF3_DECODE_M, zero_fc2_output=False,
  655. moe_block_size=8,
  656. max_m_blocks=_B12X_NF3_DECODE_M * st["topk"],
  657. direct_topk_routes=True, tc_decode_fused_sum=True,
  658. **common) # common carries force_tile_config=_B12X_NF3_TILES
  659. assert (int(cand.fc1_tile_n), int(cand.fc2_tile_n)) == (
  660. _B12X_NF3_TILES[1], _B12X_NF3_TILES[3]), "tc tile pin failed"
  661. dec = cand
  662. print(f"[hybrid] tc-decode launch armed (force PIN) "
  663. f"E={prepared.num_experts} tiles="
  664. f"{int(cand.fc1_tile_n)},{int(cand.fc2_tile_n)}",
  665. flush=True)
  666. except Exception as _te:
  667. print(f"[hybrid] tc-decode compile failed, packed fallback: "
  668. f"{_te}", flush=True)
  669. st["launches"][key] = (dec, pre)
  670. return st["launches"][key]
  671. if hyb.get("prepA") is not None:
  672. hyb["launchA"] = launches(hyb["prepA"])
  673. if hyb.get("prepB") is not None:
  674. # v2-lite: B must NOT zero the shared staging (A staged first).
  675. # A-only / B-only debug tiers are incompatible with that.
  676. if _HYBRID_FUSE_V2 and _HYBRID_TIER in ("a", "b"):
  677. raise RuntimeError("HYBRID_FUSE_V2 is incompatible with "
  678. "HYBRID_TIER=a/b")
  679. hyb["launchB"] = launches(hyb["prepB"],
  680. zero_out=not _HYBRID_FUSE_V2)
  681. if st["buffers"] is None:
  682. prep_any = hyb.get("prepA") or hyb.get("prepB")
  683. if prep_any is None:
  684. # uniform-NVFP4 layer (MTP) first: no NF3 object anywhere yet;
  685. # the kept kernel manages its own workspace -> no buffers needed.
  686. hyb["_rt_ready"] = True
  687. return
  688. buf = make_w4a16_packed_buffers(
  689. prep_any, m=st["max_m"], topk=st["topk"],
  690. dtype=torch.bfloat16, device=dev, route_num_experts=E)
  691. # the preplanned prefill launch validates route capacity at
  692. # moe_block_size=64; the plan's own block choice can be smaller
  693. # for small max_m -> upsize the route buffers if needed.
  694. need_slots = max_packed_route_slots(st["max_m"] * st["topk"], 64, E)
  695. need_blocks = (need_slots + 63) // 64
  696. if (buf.packed_route_indices.numel() < need_slots
  697. or buf.block_expert_ids.numel() < need_blocks):
  698. buf = dataclasses.replace(
  699. buf,
  700. packed_route_indices=torch.empty(
  701. (need_slots,), dtype=torch.int32, device=dev),
  702. block_expert_ids=torch.empty(
  703. (need_blocks,), dtype=torch.int32, device=dev))
  704. st["buffers"] = buf
  705. st["out_a"] = buf.output # [max_m, H], fully overwritten per call
  706. st["out_b"] = torch.empty_like(buf.output)
  707. if _HYBRID_FUSE_STREAMS:
  708. # v1.5: tier-B gets its OWN scratch (no cross-stream races) +
  709. # a dedicated side stream + pre-created fork/join events
  710. # (event creation during graph capture is illegal -> here).
  711. buf_b = make_w4a16_packed_buffers(
  712. prep_any, m=st["max_m"], topk=st["topk"],
  713. dtype=torch.bfloat16, device=dev, route_num_experts=E)
  714. if (buf_b.packed_route_indices.numel() < need_slots
  715. or buf_b.block_expert_ids.numel() < need_blocks):
  716. buf_b = dataclasses.replace(
  717. buf_b,
  718. packed_route_indices=torch.empty(
  719. (need_slots,), dtype=torch.int32, device=dev),
  720. block_expert_ids=torch.empty(
  721. (need_blocks,), dtype=torch.int32, device=dev))
  722. st["buffers_b"] = buf_b
  723. st["out_b"] = buf_b.output
  724. st["stream_b"] = torch.cuda.Stream(device=dev)
  725. st["ev_fork"] = torch.cuda.Event()
  726. st["ev_join"] = torch.cuda.Event()
  727. print("[hybrid] v1.5 stream-fusion armed (tier-B scratch + "
  728. "side stream)", flush=True)
  729. if _HYBRID_FUSE_V2:
  730. # dedicated union staging: fc2 results from BOTH tiers
  731. # live here across the A->B sequence. Must NOT alias the
  732. # fc1 workspace (kernel default) — B's FC1 would clobber
  733. # A's staged rows (learned the hard way: /Optics/ loops).
  734. st["fc2_union"] = torch.empty(
  735. (st["max_m"] * st["topk"] * H,),
  736. dtype=torch.bfloat16, device=dev)
  737. print("[hybrid] v2-lite fusion armed (dedicated union "
  738. "staging + single topk_sum)", flush=True)
  739. print(f"[hybrid] b12x_nf3 runtime ready: max_m={st['max_m']} "
  740. f"topk={st['topk']} sms={sms}", flush=True)
  741. hyb["_rt_ready"] = True
  742. def _apply_b12x_nf3(self, layer, x, topk_weights, topk_ids):
  743. import torch
  744. from b12x.moe.fused.w4a16.kernel import run_w4a16_moe
  745. hyb = layer.hyb
  746. st = _b12x_nf3_rt
  747. m = int(x.shape[0])
  748. topk = int(topk_ids.shape[1])
  749. if not hyb.get("_rt_ready"):
  750. self._ensure_b12x_nf3_runtime(layer, m, topk)
  751. if m > st["max_m"]:
  752. raise RuntimeError(
  753. f"b12x_nf3: m={m} exceeds planned capacity {st['max_m']}; "
  754. "set HYBRID_B12X_MAX_TOKENS >= max_num_batched_tokens")
  755. decode = m <= _B12X_NF3_DECODE_M
  756. if _HYBRID_ACT_CAPTURE and m > 8:
  757. try:
  758. from vllm.distributed import get_tensor_model_parallel_rank
  759. if get_tensor_model_parallel_rank() == 0:
  760. pfx = str(hyb.get("lname") or getattr(layer, "prefix", None)
  761. or id(layer)).replace("/", "_").replace(".", "_")
  762. b = _act_store["buf"].setdefault(pfx, {"x": [], "ids": []})
  763. if _act_store["flushed"].get(pfx, 0) < 32768: # cap tokens/layer
  764. b["x"].append(x.detach().to(torch.float16).cpu())
  765. b["ids"].append(topk_ids.detach().to(torch.int32).cpu())
  766. if sum(t.shape[0] for t in b["x"]) >= 8192:
  767. import os as _os
  768. _os.makedirs(_HYBRID_ACT_CAPTURE, exist_ok=True)
  769. fn = f"{_HYBRID_ACT_CAPTURE}/{pfx}.pt"
  770. prev = torch.load(fn) if _os.path.exists(fn) else {"x": [], "ids": []}
  771. prev["x"].append(torch.cat(b["x"]))
  772. prev["ids"].append(torch.cat(b["ids"]))
  773. torch.save(prev, fn)
  774. _act_store["flushed"][pfx] = _act_store["flushed"].get(pfx, 0) + sum(t.shape[0] for t in b["x"])
  775. b["x"], b["ids"] = [], []
  776. except Exception as _ce:
  777. if not _act_store.get("_warned"):
  778. _act_store["_warned"] = True
  779. print("[hybrid][act-capture] failed:", repr(_ce), flush=True)
  780. tw = (topk_weights if topk_weights.dtype == torch.float32
  781. else topk_weights.float())
  782. if not tw.is_contiguous():
  783. tw = tw.contiguous()
  784. buf = st["buffers"]
  785. def run(prepared, launch_pair, emap, out, rbuf=None,
  786. skip_sum=False, force_pre=False, fc2u=None):
  787. rbuf = buf if rbuf is None else rbuf
  788. use_dec = (_HYBRID_TC_DECODE and decode and not force_pre
  789. and launch_pair[0] is not launch_pair[1])
  790. launch = launch_pair[0] if use_dec else launch_pair[1]
  791. ids = (topk_ids if topk_ids.dtype == torch.int32
  792. else topk_ids.to(torch.int32))
  793. if not ids.is_contiguous():
  794. ids = ids.contiguous()
  795. if use_dec:
  796. # direct-topk path: kernel reads FLAT local ids and skips
  797. # negatives itself; expert_map must NOT be used. emap doubles
  798. # as the global->local LUT (graph-safe gather).
  799. ids = emap[ids.long()].to(torch.int32).contiguous()
  800. em = None
  801. else:
  802. em = emap # kernel translates global->local + drops -1 (zero=True pairs)
  803. return run_w4a16_moe(
  804. x, prepared, tw, ids,
  805. activation="silu",
  806. intermediate_cache13=rbuf.intermediate_cache13,
  807. intermediate_cache2=rbuf.intermediate_cache2,
  808. output=out,
  809. fc1_c_tmp=rbuf.fc1_c_tmp, fc2_c_tmp=rbuf.fc2_c_tmp,
  810. packed_route_indices=rbuf.packed_route_indices,
  811. block_expert_ids=rbuf.block_expert_ids,
  812. packed_route_count=rbuf.packed_route_count,
  813. expert_offsets=rbuf.expert_offsets,
  814. expert_map=em,
  815. fused_launch=launch,
  816. # v2-lite kwargs exist only in our tcfix kernel; pass
  817. # them only when engaged so stock kernel dirs stay
  818. # boot-compatible with this loader.
  819. **({"skip_topk_sum": True} if skip_sum else {}),
  820. **({"fc2_out_override": fc2u} if fc2u is not None else {}))
  821. if hyb["Km"] == 0:
  822. # uniform-NVFP4 layer (MTP/nextn): single tier through OUR launcher
  823. out = torch.empty((m, hyb["H"]), dtype=x.dtype, device=x.device)
  824. out = run(hyb["prepA"], hyb["launchA"], hyb["emap_a"], out)
  825. if _HYBRID_DEBUG and not hyb.get("_dbg"):
  826. hyb["_dbg"] = True
  827. print(f"[dbg-nf3] {getattr(layer, 'prefix', '?')} m={m} "
  828. f"A-only={out.float().norm():.1f}", flush=True)
  829. return out
  830. out_a = out_b = None
  831. if _HYBRID_TIER == "a":
  832. out = run(hyb["prepA"], hyb["launchA"], hyb["emap_a"],
  833. st["out_a"][:m]).clone()
  834. elif _HYBRID_TIER == "b":
  835. out = run(hyb["prepB"], hyb["launchB"], hyb["emap_b"],
  836. st["out_b"][:m]).clone()
  837. elif _HYBRID_FUSE_V2 and not (
  838. _HYBRID_TC_DECODE and decode
  839. and hyb["launchA"][0] is not hyb["launchA"][1]
  840. and hyb["launchB"][0] is not hyb["launchB"][1]):
  841. # v2-lite: A zeros the shared fc2 staging and stages its
  842. # routes; B (compiled zero_fc2_output=False) stages its
  843. # disjoint routes; ONE topk_sum over the union -> out_b is
  844. # the complete result. No out_a+out_b add. force_pre pins
  845. # both tiers to the packed path (a lone tc-armed tier would
  846. # bypass staging and double-count).
  847. run(hyb["prepA"], hyb["launchA"], hyb["emap_a"],
  848. st["out_a"][:m], skip_sum=True, force_pre=True,
  849. fc2u=st["fc2_union"])
  850. out = run(hyb["prepB"], hyb["launchB"], hyb["emap_b"],
  851. st["out_b"][:m], force_pre=True,
  852. fc2u=st["fc2_union"])
  853. elif _HYBRID_FUSE_STREAMS and st["stream_b"] is not None:
  854. # v1.5: fork tier-B onto the side stream so both grouped GEMMs
  855. # co-schedule on the SMs; join before the sum. Events pre-created
  856. # (graph-capture legal); tier-B uses its own scratch set.
  857. s = torch.cuda.current_stream()
  858. sb = st["stream_b"]
  859. st["ev_fork"].record(s)
  860. sb.wait_event(st["ev_fork"])
  861. out_a = run(hyb["prepA"], hyb["launchA"], hyb["emap_a"],
  862. st["out_a"][:m])
  863. with torch.cuda.stream(sb):
  864. out_b = run(hyb["prepB"], hyb["launchB"], hyb["emap_b"],
  865. st["out_b"][:m], rbuf=st["buffers_b"])
  866. st["ev_join"].record(sb)
  867. s.wait_event(st["ev_join"])
  868. out = out_a + out_b
  869. else:
  870. prof = _HYBRID_PROFILE and m > 64
  871. if prof:
  872. import time as _time
  873. _w0 = _time.perf_counter()
  874. ev = [torch.cuda.Event(enable_timing=True) for _ in range(3)]
  875. ev[0].record()
  876. out_a = run(hyb["prepA"], hyb["launchA"], hyb["emap_a"],
  877. st["out_a"][:m])
  878. if prof:
  879. ev[1].record()
  880. out_b = run(hyb["prepB"], hyb["launchB"], hyb["emap_b"],
  881. st["out_b"][:m])
  882. if prof:
  883. ev[2].record()
  884. _prof_store["wall_ms"] = _prof_store.get("wall_ms", 0.0) + \
  885. (_time.perf_counter() - _w0) * 1000.0
  886. _prof_store["pend"].append((m, ev))
  887. _prof_store["n"] += 1
  888. if _prof_store["n"] % 624 == 0: # ~8 full 78-layer prefill passes
  889. try:
  890. torch.cuda.synchronize()
  891. for pm, pe in _prof_store["pend"]:
  892. _prof_store["a_ms"] += pe[0].elapsed_time(pe[1])
  893. _prof_store["b_ms"] += pe[1].elapsed_time(pe[2])
  894. _prof_store["rows"] += pm
  895. _prof_store["pend"] = []
  896. from vllm.distributed import get_tensor_model_parallel_rank
  897. if get_tensor_model_parallel_rank() == 0:
  898. n = _prof_store["n"]
  899. a = _prof_store["a_ms"] / n
  900. b = _prof_store["b_ms"] / n
  901. mavg = _prof_store["rows"] / n
  902. w = _prof_store.get("wall_ms", 0.0) / n
  903. print(f"[hybrid-prof] n={n} avg_m={mavg:.0f} "
  904. f"A(nvfp4)={a:.3f}ms B(nf3)={b:.3f}ms "
  905. f"wall={w:.3f}ms /layer-chunk "
  906. f"-> MoE-gpu {78*(a+b):.0f}ms MoE-wall {78*w:.0f}ms "
  907. f"per {mavg:.0f}-tok chunk",
  908. flush=True)
  909. except Exception as _pe:
  910. print("[hybrid-prof] harvest failed:", repr(_pe), flush=True)
  911. out = out_a + out_b
  912. if _HYBRID_DEBUG and not hyb.get("_dbg"):
  913. hyb["_dbg"] = True
  914. na = "-" if out_a is None else f"{out_a.float().norm():.1f}"
  915. nb = "-" if out_b is None else f"{out_b.float().norm():.1f}"
  916. print(f"[dbg-nf3] {getattr(layer, 'prefix', '?')} m={m} "
  917. f"decode={decode} tier={_HYBRID_TIER} x={x.float().norm():.1f} "
  918. f"A={na} B={nb} out={out.float().norm():.1f} "
  919. f"nan={bool(torch.isnan(out).any())}", flush=True)
  920. if getattr(layer, "w13_weight", None) is not None and \
  921. layer.w13_weight.numel() > 0:
  922. try:
  923. ra = self._apply_ref(layer, x, topk_weights, topk_ids, 0)
  924. rb = self._apply_ref(layer, x, topk_weights, topk_ids, 1)
  925. ea = float((out_a.float() - ra.float()).abs().sum()
  926. / (ra.float().abs().sum() + 1e-9))
  927. eb = float((out_b.float() - rb.float()).abs().sum()
  928. / (rb.float().abs().sum() + 1e-9))
  929. print(f"[dbgcmp-nf3] A_rel={ea:.4f} B_rel={eb:.4f}",
  930. flush=True)
  931. except Exception as _e:
  932. print("[dbgcmp-nf3] ref failed:", repr(_e), flush=True)
  933. return out
  934. def process_weights_after_loading(self, layer):
  935. if not hasattr(layer, "hyb"):
  936. return super().process_weights_after_loading(layer)
  937. if _HYBRID_KEPT == "b12x_nf3":
  938. try:
  939. self._build_b12x_nf3(layer)
  940. layer.hyb["_b12x_nf3"] = True
  941. layer.hyb["_b12x"] = False
  942. layer.hyb["_kept_triton"] = False
  943. layer.hyb["_fast"] = False
  944. return
  945. except Exception as e:
  946. import traceback
  947. print("[hybrid] b12x_nf3 build FAILED -> triton/ref "
  948. "fallback:", e, flush=True)
  949. traceback.print_exc()
  950. layer.hyb["_b12x_nf3"] = False
  951. # originals are freed only on success -> the stock flow
  952. # below still has everything it needs.
  953. E = layer.hyb["E"]
  954. dev = layer.w13_weight.device
  955. # --- NF3 tier: expert map (demoted global id -> local NF3 index, else -1) ---
  956. emap = torch.full((E,), -1, dtype=torch.int32, device=dev)
  957. for g, (grp, li) in layer.hyb["remap"].items():
  958. if grp == 1:
  959. emap[g] = li
  960. layer.hyb["emap_nf3"] = emap
  961. if _HYBRID_NF3 == "fast":
  962. try:
  963. import nf3_kernel # noqa: F401 (mounted alongside loader; warm import)
  964. layer.hyb["_fast"] = True
  965. except Exception as e:
  966. print("[hybrid] nf3_kernel import failed -> reference:", e, flush=True)
  967. layer.hyb["_fast"] = False
  968. else:
  969. layer.hyb["_fast"] = False
  970. # --- NVFP4 kept tier ---
  971. layer.hyb["_b12x"] = False
  972. layer.hyb["_kept_triton"] = False
  973. if _HYBRID_KEPT in ("triton", "b12x_nf3"):
  974. # Custom Triton NVFP4 grouped-GEMM: reads the checkpoint weights DIRECTLY
  975. # (no convert/prepare/copy), graph-safe. emap: kept global -> local, else -1.
  976. # ("b12x_nf3" reaches here ONLY after a failed b12x_nf3 build ->
  977. # fall back to the proven triton kept tier; originals intact.)
  978. kmap = torch.full((E,), -1, dtype=torch.int32, device=dev)
  979. for gid, (grp, li) in layer.hyb["remap"].items():
  980. if grp == 0:
  981. kmap[gid] = li
  982. layer.hyb["emap_nvfp4"] = kmap
  983. layer.hyb["g13"] = layer.w13_weight_scale_2[:, 0].contiguous()
  984. layer.hyb["g2"] = layer.w2_weight_scale_2.contiguous()
  985. try:
  986. import nvfp4_kernel # noqa: F401
  987. layer.hyb["_kept_triton"] = True
  988. except Exception as e:
  989. print("[hybrid] nvfp4_kernel import failed -> reference:", e, flush=True)
  990. elif _HYBRID_KEPT == "b12x":
  991. try:
  992. self._build_kept_b12x(layer)
  993. layer.hyb["_b12x"] = True
  994. except Exception as e:
  995. import traceback
  996. print("[hybrid] kept b12x build FAILED -> reference NVFP4:", e, flush=True)
  997. traceback.print_exc()
  998. def _apply_ref(self, layer, x, topk_weights, topk_ids, only_grp):
  999. H, I, gs = layer.hyb["H"], layer.hyb["I"], layer.hyb["gs"]
  1000. remap = layer.hyb["remap"]
  1001. out = torch.zeros_like(x)
  1002. for e in torch.unique(topk_ids).tolist():
  1003. if e < 0 or e not in remap:
  1004. continue
  1005. grp, li = remap[e]
  1006. if grp != only_grp:
  1007. continue
  1008. if grp == 0:
  1009. w13 = _deq_nv(layer.w13_weight[li], layer.w13_nv_s[li], layer.w13_weight_scale_2[li], gs, dequantize_to_dtype)
  1010. w2 = _deq_nv(layer.w2_weight[li], layer.w2_nv_s[li], layer.w2_weight_scale_2[li], gs, dequantize_to_dtype)
  1011. else:
  1012. w13 = _unpack_nf3(layer.w13_weight_packed[li], layer.w13_nf_s[li], H)
  1013. w2 = _unpack_nf3(layer.w2_weight_packed[li], layer.w2_nf_s[li], I)
  1014. sel = (topk_ids == e)
  1015. tok = sel.any(-1)
  1016. if not tok.any():
  1017. continue
  1018. g, u = (x[tok] @ w13.t()).chunk(2, -1)
  1019. y = (F.silu(g) * u) @ w2.t()
  1020. wgt = (topk_weights * sel).sum(-1)[tok].unsqueeze(-1).to(y.dtype)
  1021. out[tok] += wgt * y
  1022. return out
  1023. def apply(self, layer, x, topk_weights, topk_ids,
  1024. shared_experts=None, shared_experts_input=None):
  1025. # routed experts only; shared experts + routing handled by the runner.
  1026. if not hasattr(layer, "hyb"):
  1027. return super().apply(layer, x, topk_weights, topk_ids,
  1028. shared_experts, shared_experts_input)
  1029. if layer.hyb.get("_b12x_nf3"):
  1030. return self._apply_b12x_nf3(layer, x, topk_weights, topk_ids)
  1031. H, I, E = layer.hyb["H"], layer.hyb["I"], layer.hyb["E"]
  1032. # --- NVFP4 kept tier ---
  1033. if layer.hyb.get("_kept_triton"):
  1034. import nvfp4_kernel
  1035. kept_out = nvfp4_kernel.nvfp4_moe_layer(
  1036. x, layer.w13_weight, layer.w13_nv_s, layer.hyb["g13"],
  1037. layer.w2_weight, layer.w2_nv_s, layer.hyb["g2"],
  1038. topk_ids, topk_weights, layer.hyb["emap_nvfp4"], E, H, I, 16)
  1039. elif layer.hyb.get("_b12x"):
  1040. kk = layer.hyb["kept_kernel"]
  1041. KL = layer.hyb["kept_KL"]
  1042. Kn = layer.hyb["Kn"]
  1043. kept_ids = layer.hyb["nvfp4_remap"][topk_ids] # kept->[0,Kn), else Kn (b12x skips)
  1044. kept_out = kk.apply(
  1045. x, KL.w13_weight, KL.w2_weight, topk_weights, kept_ids,
  1046. activation=KL.activation, global_num_experts=Kn, expert_map=None,
  1047. apply_router_weight_on_input=False,
  1048. shared_experts=None, shared_experts_input=None)
  1049. else:
  1050. kept_out = self._apply_ref(layer, x, topk_weights, topk_ids, 0)
  1051. # --- NF3 tier (192 experts) ---
  1052. if layer.hyb.get("_fast"):
  1053. import nf3_kernel
  1054. nf3_out = nf3_kernel.nf3_moe_layer(
  1055. x, layer.w13_weight_packed, layer.w13_nf_s,
  1056. layer.w2_weight_packed, layer.w2_nf_s,
  1057. topk_ids, topk_weights, layer.hyb["emap_nf3"], E, 32, H, I)
  1058. else:
  1059. nf3_out = self._apply_ref(layer, x, topk_weights, topk_ids, 1)
  1060. out = kept_out + nf3_out
  1061. if _HYBRID_DEBUG and not layer.hyb.get("_dbg"):
  1062. layer.hyb["_dbg"] = True
  1063. print(f"[dbg] {getattr(layer, 'prefix', '?')} "
  1064. f"x={x.float().norm():.1f} kept={kept_out.float().norm():.1f} "
  1065. f"nf3={nf3_out.float().norm():.1f} out={out.float().norm():.1f} "
  1066. f"nan={bool(torch.isnan(out).any())}", flush=True)
  1067. if layer.hyb.get("_b12x") and hasattr(layer, "w13_weight"):
  1068. try:
  1069. rk = self._apply_ref(layer, x, topk_weights, topk_ids, 0)
  1070. ratio = float(kept_out.float().norm() / (rk.float().norm() + 1e-9))
  1071. erel = float((kept_out.float() - rk.float()).abs().sum()
  1072. / (rk.float().abs().sum() + 1e-9))
  1073. print(f"[dbgcmp] {getattr(layer, 'prefix', '?')} "
  1074. f"b12x={kept_out.float().norm():.3f} ref={rk.float().norm():.3f} "
  1075. f"ratio={ratio:.3f} elem_rel={erel:.3f}", flush=True)
  1076. except Exception as _e:
  1077. print("[dbgcmp] ref failed:", repr(_e), flush=True)
  1078. return out
  1079. mod.ModelOptNvFp4Config.FusedMoEMethodCls = HybridNvFp4MoE
  1080. print("[hybrid_loader] HybridNvFp4MoE installed", flush=True)
  1081. # ---- fp8 non-expert dequant-on-load (weight_scale_fp8 modules are in `ignore` -> bf16) ----
  1082. try:
  1083. from vllm.model_executor.model_loader.default_loader import DefaultModelLoader
  1084. if not getattr(DefaultModelLoader, "_hyb_wrapped", False):
  1085. _oga = DefaultModelLoader.get_all_weights
  1086. def get_all_weights(self, model_config, model):
  1087. return _fp8_ne_transform(_oga(self, model_config, model))
  1088. DefaultModelLoader.get_all_weights = get_all_weights
  1089. DefaultModelLoader._hyb_wrapped = True
  1090. print("[hybrid_loader] fp8 non-expert dequant-on-load installed", flush=True)
  1091. except Exception as e:
  1092. print("[hybrid_loader] wrap get_all_weights failed:", e, flush=True)
  1093. # ---- 3. HYBRID_MXFP8_NATIVE: serve the F8 ne-tier via online-mxfp8 ----
  1094. # Instead of dequant-to-bf16 (2 B/param resident), excluded LinearBase
  1095. # modules whose disk tensors are F8 get Mxfp8OnlineLinearMethod: loader
  1096. # still feeds them our dequanted bf16, the method re-quantizes e8m0/32 at
  1097. # load (bit-exact round trip vs rev-3 disk) and serves through the B12X
  1098. # fp8 GEMM (VLLM_USE_B12X_FP8_GEMM=1 forces B12xMxfp8LinearKernel).
  1099. # Net: ~-3.65 GiB/GPU weights. Activations on these linears become
  1100. # dynamic-A8 (Festr serving convention) — KLD re-gate before publishing.
  1101. if os.environ.get("HYBRID_MXFP8_NATIVE", "0") == "1":
  1102. try:
  1103. import json as _json
  1104. from vllm.model_executor.layers.quantization.online.mxfp8 import (
  1105. Mxfp8OnlineLinearMethod)
  1106. from vllm.model_executor.layers.linear import (
  1107. LinearBase, UnquantizedLinearMethod)
  1108. from vllm.model_executor.layers.vocab_parallel_embedding import (
  1109. ParallelLMHead)
  1110. _tier_path = os.environ.get(
  1111. "HYBRID_MXFP8_TIER_JSON",
  1112. "/opt/venv/lib/python3.12/site-packages/mxfp8_tier.json")
  1113. _allow = set(_json.load(open(_tier_path))["module_prefixes"])
  1114. def _mx_norm(p):
  1115. i = p.find("layers.")
  1116. return p[i:] if i >= 0 else p
  1117. _base = mod.ModelOptQuantConfigBase
  1118. if not getattr(_base, "_hyb_mxfp8_overlay", False):
  1119. _orig_gqm = _base.get_quant_method
  1120. _n_over = [0]
  1121. def get_quant_method(self, layer, prefix):
  1122. m = _orig_gqm(self, layer, prefix)
  1123. if (type(m) is UnquantizedLinearMethod
  1124. and isinstance(layer, LinearBase)
  1125. and not isinstance(layer, ParallelLMHead)
  1126. and _mx_norm(prefix) in _allow):
  1127. _n_over[0] += 1
  1128. if _n_over[0] <= 4 or _n_over[0] % 128 == 0:
  1129. print(f"[hybrid_loader] mxfp8 overlay #{_n_over[0]}: "
  1130. f"{prefix}", flush=True)
  1131. return Mxfp8OnlineLinearMethod()
  1132. return m
  1133. _base.get_quant_method = get_quant_method
  1134. _base._hyb_mxfp8_overlay = True
  1135. print(f"[hybrid_loader] mxfp8 ne-tier overlay armed "
  1136. f"({len(_allow)} module prefixes)", flush=True)
  1137. except Exception as e:
  1138. import traceback
  1139. print("[hybrid_loader] mxfp8 overlay FAILED:", e, flush=True)
  1140. traceback.print_exc()
  1141. class _Hook(importlib.abc.MetaPathFinder):
  1142. T = "vllm.model_executor.layers.quantization.modelopt"
  1143. def find_spec(self, name, path, target=None):
  1144. if name == self.T and not getattr(self, "_d", False):
  1145. self._d = True
  1146. spec = importlib.util.find_spec(name)
  1147. if spec:
  1148. real_exec = spec.loader.exec_module
  1149. def ex(module):
  1150. real_exec(module)
  1151. try:
  1152. _patch(module)
  1153. except Exception as e:
  1154. import traceback
  1155. print("[hybrid_loader] patch FAILED:", e, flush=True)
  1156. traceback.print_exc()
  1157. spec.loader.exec_module = ex
  1158. return spec
  1159. return None
  1160. if not any(isinstance(f, _Hook) for f in sys.meta_path):
  1161. sys.meta_path.insert(0, _Hook())
  1162. print("[hybrid_loader] import hook armed", flush=True)