CompressedGemma commited on
Commit
fb5b18f
·
verified ·
1 Parent(s): 75c8c03
Files changed (1) hide show
  1. slimshard.py +88 -3
slimshard.py CHANGED
@@ -66,12 +66,13 @@ from .q4_0 import Q4_0_BLOCK_BYTES, QK4_0, dequantize_q4_0_bytes, quantize_tenso
66
 
67
  SHARD_FORMAT = "hpc-slimshard-v1"
68
  EXPERT_RE = re.compile(
69
- r"^((?:[a-zA-Z0-9_]+\.)*(?:layers|h|blocks))\.(\d+)\.((?:moe\.|mlp\.|block_sparse_moe\.|feed_forward\.)?experts)\.(\d+)\.([a-zA-Z0-9_]+)\.(weight|bias|weight_scale_inv|weight_scale|scales)$"
70
  )
71
  LAYER_RE = re.compile(r"^((?:[a-zA-Z0-9_]+\.)*(?:layers|h|blocks))\.(\d+)\.(.+)$")
72
 
73
  _EMBED_NAMES = (
74
  "model.embed_tokens.weight",
 
75
  "transformer.wte.weight",
76
  "gpt_neox.embed_in.weight",
77
  "model.decoder.embed_tokens.weight",
@@ -81,6 +82,7 @@ _EMBED_NAMES = (
81
  )
82
  _HEAD_NAMES = (
83
  "lm_head.weight",
 
84
  "embed_out.weight",
85
  "output.weight",
86
  "language_model.lm_head.weight",
@@ -88,6 +90,7 @@ _HEAD_NAMES = (
88
  )
89
  _NORM_NAMES = (
90
  "model.norm.weight",
 
91
  "transformer.ln_f.weight",
92
  "gpt_neox.final_layer_norm.weight",
93
  "model.decoder.final_layer_norm.weight",
@@ -241,6 +244,8 @@ _TORCH_DTYPE = {
241
  "float8_e5m2": "F8_E5M2",
242
  "float8_e4m3fnuz": "F8_E4M3",
243
  "float8_e5m2fnuz": "F8_E5M2",
 
 
244
  }
245
  _NP_DTYPE = {
246
  "F32": np.float32,
@@ -1235,10 +1240,86 @@ def _write_lm_head_calibrated_chunked(
1235
  writer.add_chunked_bf16(name, (vocab, hidden), gen())
1236
 
1237
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1238
  def inspect_recovery_plan(
1239
  shard: str | Path,
1240
  index: str | Path | None = None,
1241
  config: str | Path | None = None,
 
 
1242
  ) -> dict:
1243
  """Inspect a shard + index/config and return a full CheckFree recovery plan for the GUI."""
1244
  shard_path = Path(shard)
@@ -1250,9 +1331,9 @@ def inspect_recovery_plan(
1250
 
1251
  index_path = Path(index) if index else shard_path.parent / "model.safetensors.index.json"
1252
  if index_path.exists():
1253
- weight_map: dict[str, str] = json.loads(index_path.read_text())["weight_map"]
1254
  else:
1255
- weight_map = infer_weight_map_from_shard(shard_path, arch)
1256
 
1257
  with safe_open(str(shard_path), framework="pt", device="cpu") as f:
1258
  meta = f.metadata() or {}
@@ -1265,6 +1346,10 @@ def inspect_recovery_plan(
1265
  present_shapes[k] = tuple(sl.get_shape())
1266
  present_dtypes[k] = _safetensors_dtype(sl.get_dtype())
1267
 
 
 
 
 
1268
  surviving_layers = sorted(
1269
  {int(LAYER_RE.match(k).group(2)) for k in present if LAYER_RE.match(k)}
1270
  )
 
66
 
67
  SHARD_FORMAT = "hpc-slimshard-v1"
68
  EXPERT_RE = re.compile(
69
+ r"^((?:[a-zA-Z0-9_]+\.)*(?:layers|h|blocks))\.(\d+)\.((?:moe\.|mlp\.|ffn\.|block_sparse_moe\.|feed_forward\.)?experts)\.(\d+)\.([a-zA-Z0-9_]+)\.(weight|bias|weight_scale_inv|weight_scale|scales|scale)$"
70
  )
71
  LAYER_RE = re.compile(r"^((?:[a-zA-Z0-9_]+\.)*(?:layers|h|blocks))\.(\d+)\.(.+)$")
72
 
73
  _EMBED_NAMES = (
74
  "model.embed_tokens.weight",
75
+ "embed.weight",
76
  "transformer.wte.weight",
77
  "gpt_neox.embed_in.weight",
78
  "model.decoder.embed_tokens.weight",
 
82
  )
83
  _HEAD_NAMES = (
84
  "lm_head.weight",
85
+ "head.weight",
86
  "embed_out.weight",
87
  "output.weight",
88
  "language_model.lm_head.weight",
 
90
  )
91
  _NORM_NAMES = (
92
  "model.norm.weight",
93
+ "norm.weight",
94
  "transformer.ln_f.weight",
95
  "gpt_neox.final_layer_norm.weight",
96
  "model.decoder.final_layer_norm.weight",
 
244
  "float8_e5m2": "F8_E5M2",
245
  "float8_e4m3fnuz": "F8_E4M3",
246
  "float8_e5m2fnuz": "F8_E5M2",
247
+ "float8_e8m0fnu": "U8",
248
+ "F8_E8M0": "U8",
249
  }
250
  _NP_DTYPE = {
251
  "F32": np.float32,
 
1240
  writer.add_chunked_bf16(name, (vocab, hidden), gen())
1241
 
1242
 
1243
+ def _filter_weight_map_for_target(
1244
+ weight_map: dict[str, str],
1245
+ present: set[str],
1246
+ arch: dict,
1247
+ target_params_b: float | None = None,
1248
+ max_experts: int | None = None,
1249
+ ) -> tuple[dict[str, str], int | None, float]:
1250
+ """Filter ``weight_map`` for single-shard recovery and optional parameter-budget compression.
1251
+
1252
+ * Strips external multi-hundred-GB ``.engram.`` tables, ``mtp.`` draft layers,
1253
+ and ``vision.`` / ``aligner.`` / ``image_`` branches if absent from ``present``.
1254
+ * Computes ``kept_experts`` when ``target_params_b`` (e.g. ``30.0``) or
1255
+ ``max_experts`` is specified, pruning routed experts ``>= kept_experts``.
1256
+ * Returns ``(filtered_weight_map, kept_experts, estimated_params_b)``.
1257
+ """
1258
+ has_vision = any(k.startswith(("vision.", "aligner.", "image_")) for k in present)
1259
+ has_mtp = any(k.startswith("mtp.") for k in present)
1260
+ has_engram = any(".engram." in k for k in present)
1261
+
1262
+ orig_experts = int(arch.get("num_experts") or 0)
1263
+ num_layers = int(arch.get("num_hidden_layers") or 25)
1264
+ hidden = int(arch.get("hidden_size") or 2560)
1265
+ moe_inter = int(arch.get("moe_intermediate_size") or arch.get("intermediate_size") or 1088)
1266
+ vocab = int(arch.get("vocab_size") or 128000)
1267
+ top_k = int(arch.get("num_experts_per_token") or arch.get("num_experts_per_tok") or 6)
1268
+
1269
+ # Estimate dense/non-routed parameters (embed + head + attention + shared experts)
1270
+ tie_emb = bool(arch.get("tie_word_embeddings", False))
1271
+ embed_params = vocab * hidden * (1 if tie_emb else 2)
1272
+ attn_shared_per_layer = (4 * hidden * hidden) + (3 * moe_inter * hidden)
1273
+ dense_params = float(embed_params + num_layers * attn_shared_per_layer)
1274
+ params_per_expert = float(3 * moe_inter * hidden)
1275
+
1276
+ kept_experts: int | None = None
1277
+ if max_experts is not None and max_experts > 0 and orig_experts > 0:
1278
+ kept_experts = min(orig_experts, max(top_k, int(max_experts)))
1279
+ elif target_params_b is not None and target_params_b > 0.0 and orig_experts > 0 and params_per_expert > 0:
1280
+ target_p = float(target_params_b) * 1.0e9
1281
+ avail_for_routed = max(0.0, target_p - dense_params)
1282
+ moe_layers = max(1, num_layers - int(arch.get("first_k_dense_replace", 0)))
1283
+ est_e = int(round(avail_for_routed / (moe_layers * params_per_expert)))
1284
+ kept_experts = min(orig_experts, max(top_k, est_e))
1285
+
1286
+ filtered: dict[str, str] = {}
1287
+ for k, sh in weight_map.items():
1288
+ if not has_engram and ".engram." in k:
1289
+ continue
1290
+ if not has_mtp and k.startswith("mtp."):
1291
+ continue
1292
+ if not has_vision and (k.startswith(("vision.", "aligner.", "image_")) or k.endswith(".bias_vl")):
1293
+ continue
1294
+ em = EXPERT_RE.match(k)
1295
+ if em and kept_experts is not None:
1296
+ eidx = int(em.group(4))
1297
+ if eidx >= kept_experts:
1298
+ continue
1299
+ filtered[k] = sh
1300
+
1301
+ moe_layers = max(1, num_layers - int(arch.get("first_k_dense_replace", 0)))
1302
+ eff_experts = kept_experts if kept_experts is not None else orig_experts
1303
+ est_total_b = (dense_params + (moe_layers * eff_experts * params_per_expert if eff_experts > 0 else 0.0)) / 1.0e9
1304
+ return filtered, kept_experts, est_total_b
1305
+
1306
+
1307
+ def _is_router_gate_tensor(name: str, orig_experts: int, shape: tuple[int, ...]) -> bool:
1308
+ if orig_experts <= 0 or not shape or shape[0] != orig_experts:
1309
+ return False
1310
+ return (
1311
+ ".gate.weight" in name
1312
+ or ".gate.bias" in name
1313
+ or name.endswith("e_score_correction_bias")
1314
+ ) and ".experts." not in name
1315
+
1316
+
1317
  def inspect_recovery_plan(
1318
  shard: str | Path,
1319
  index: str | Path | None = None,
1320
  config: str | Path | None = None,
1321
+ target_params_b: float | None = None,
1322
+ max_experts: int | None = None,
1323
  ) -> dict:
1324
  """Inspect a shard + index/config and return a full CheckFree recovery plan for the GUI."""
1325
  shard_path = Path(shard)
 
1331
 
1332
  index_path = Path(index) if index else shard_path.parent / "model.safetensors.index.json"
1333
  if index_path.exists():
1334
+ raw_weight_map: dict[str, str] = json.loads(index_path.read_text())["weight_map"]
1335
  else:
1336
+ raw_weight_map = infer_weight_map_from_shard(shard_path, arch)
1337
 
1338
  with safe_open(str(shard_path), framework="pt", device="cpu") as f:
1339
  meta = f.metadata() or {}
 
1346
  present_shapes[k] = tuple(sl.get_shape())
1347
  present_dtypes[k] = _safetensors_dtype(sl.get_dtype())
1348
 
1349
+ weight_map, kept_experts, est_params_b = _filter_weight_map_for_target(
1350
+ raw_weight_map, present, arch, target_params_b=target_params_b, max_experts=max_experts
1351
+ )
1352
+
1353
  surviving_layers = sorted(
1354
  {int(LAYER_RE.match(k).group(2)) for k in present if LAYER_RE.match(k)}
1355
  )