CompressedGemma commited on
Commit
e4cbf85
·
verified ·
1 Parent(s): 6645bbb

Upload slimshard.py

Browse files
Files changed (1) hide show
  1. slimshard.py +514 -0
slimshard.py CHANGED
@@ -2681,6 +2681,520 @@ def slimshard_info(path: str | Path) -> dict:
2681
  }
2682
 
2683
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2684
  def main() -> None:
2685
  ap = argparse.ArgumentParser(description="HPC SlimShard / CheckFree single-shard LLM recovery")
2686
  sub = ap.add_subparsers(dest="cmd", required=False)
 
2681
  }
2682
 
2683
 
2684
+ # ---------------------------------------------------------------------------
2685
+ # Universal SafeTensors -> GGUF Exporter (supports FP4/FP8/BF16/F16/F32 + Q2_K/Q4_0)
2686
+ # ---------------------------------------------------------------------------
2687
+ _GGUF_MAGIC = 0x46554747
2688
+ _GGUF_ALIGNMENT = 32
2689
+ _GGML_F32 = 0
2690
+ _GGML_F16 = 1
2691
+ _GGML_Q4_0 = 2
2692
+ _GGML_Q2_K = 10
2693
+ _GGML_BF16 = 30
2694
+
2695
+ _LAYER_SUFFIX_TO_GGUF = {
2696
+ "input_layernorm.weight": "attn_norm.weight",
2697
+ "attn_norm.weight": "attn_norm.weight",
2698
+ "ln_1.weight": "attn_norm.weight",
2699
+ "post_attention_layernorm.weight": "ffn_norm.weight",
2700
+ "ffn_norm.weight": "ffn_norm.weight",
2701
+ "ln_2.weight": "ffn_norm.weight",
2702
+ "self_attn.q_proj.weight": "attn_q.weight",
2703
+ "attn.q_proj.weight": "attn_q.weight",
2704
+ "attention.wq.weight": "attn_q.weight",
2705
+ "self_attn.k_proj.weight": "attn_k.weight",
2706
+ "attn.k_proj.weight": "attn_k.weight",
2707
+ "attention.wk.weight": "attn_k.weight",
2708
+ "self_attn.v_proj.weight": "attn_v.weight",
2709
+ "attn.v_proj.weight": "attn_v.weight",
2710
+ "attention.wv.weight": "attn_v.weight",
2711
+ "self_attn.o_proj.weight": "attn_output.weight",
2712
+ "attn.o_proj.weight": "attn_output.weight",
2713
+ "attention.wo.weight": "attn_output.weight",
2714
+ "attn.wo_b.weight": "attn_output.weight",
2715
+ "attn.wo_a.weight": "attn_o_a.weight",
2716
+ "self_attn.q_a_proj.weight": "attn_q_a.weight",
2717
+ "attn.wq_a.weight": "attn_q_a.weight",
2718
+ "self_attn.q_a_layernorm.weight": "attn_q_a_norm.weight",
2719
+ "attn.q_norm.weight": "attn_q_a_norm.weight",
2720
+ "self_attn.q_b_proj.weight": "attn_q_b.weight",
2721
+ "attn.wq_b.weight": "attn_q_b.weight",
2722
+ "self_attn.kv_a_proj_with_mqa.weight": "attn_kv_a_mqa.weight",
2723
+ "attn.wkv.weight": "attn_kv_a_mqa.weight",
2724
+ "self_attn.kv_a_layernorm.weight": "attn_kv_a_norm.weight",
2725
+ "attn.kv_norm.weight": "attn_kv_a_norm.weight",
2726
+ "self_attn.kv_b_proj.weight": "attn_kv_b.weight",
2727
+ "self_attn.g_proj.weight": "attn_gate.weight",
2728
+ "mlp.gate_proj.weight": "ffn_gate.weight",
2729
+ "feed_forward.w1.weight": "ffn_gate.weight",
2730
+ "mlp.up_proj.weight": "ffn_up.weight",
2731
+ "feed_forward.w3.weight": "ffn_up.weight",
2732
+ "mlp.down_proj.weight": "ffn_down.weight",
2733
+ "feed_forward.w2.weight": "ffn_down.weight",
2734
+ "moe.gate.weight": "ffn_gate_inp.weight",
2735
+ "mlp.gate.weight": "ffn_gate_inp.weight",
2736
+ "ffn.gate.weight": "ffn_gate_inp.weight",
2737
+ "block_sparse_moe.gate.weight": "ffn_gate_inp.weight",
2738
+ "moe.gate.e_score_correction_bias": "exp_probs_b.bias",
2739
+ "ffn.gate.bias": "exp_probs_b.bias",
2740
+ "moe.shared_experts.gate_proj.weight": "ffn_gate_shexp.weight",
2741
+ "mlp.shared_experts.gate_proj.weight": "ffn_gate_shexp.weight",
2742
+ "ffn.shared_experts.w1.weight": "ffn_gate_shexp.weight",
2743
+ "moe.shared_experts.up_proj.weight": "ffn_up_shexp.weight",
2744
+ "mlp.shared_experts.up_proj.weight": "ffn_up_shexp.weight",
2745
+ "ffn.shared_experts.w3.weight": "ffn_up_shexp.weight",
2746
+ "moe.shared_experts.down_proj.weight": "ffn_down_shexp.weight",
2747
+ "mlp.shared_experts.down_proj.weight": "ffn_down_shexp.weight",
2748
+ "ffn.shared_experts.w2.weight": "ffn_down_shexp.weight",
2749
+ }
2750
+
2751
+ _EXPERT_PROJ_TO_GGUF = {
2752
+ "gate_proj": "ffn_gate_exps.weight",
2753
+ "w1": "ffn_gate_exps.weight",
2754
+ "fc1": "ffn_gate_exps.weight",
2755
+ "up_proj": "ffn_up_exps.weight",
2756
+ "w3": "ffn_up_exps.weight",
2757
+ "down_proj": "ffn_down_exps.weight",
2758
+ "w2": "ffn_down_exps.weight",
2759
+ "fc2": "ffn_down_exps.weight",
2760
+ }
2761
+
2762
+
2763
+ def _gguf_align(val: int, alignment: int = _GGUF_ALIGNMENT) -> int:
2764
+ return (val + alignment - 1) & ~(alignment - 1)
2765
+
2766
+
2767
+ def _pack_gguf_str(s: str) -> bytes:
2768
+ b = s.encode("utf-8")
2769
+ return struct.pack("<Q", len(b)) + b
2770
+
2771
+
2772
+ def _build_gguf_kv_pairs(
2773
+ arch: dict,
2774
+ tokenizer_path: Path | None,
2775
+ chat_template_path: Path | None,
2776
+ quant_format: str,
2777
+ model_name: str,
2778
+ ) -> list[tuple[str, int, bytes]]:
2779
+ raw_mtype = str(arch.get("model_type", "llama")).lower()
2780
+ if "deepseek" in raw_mtype:
2781
+ g_arch = "deepseek2"
2782
+ elif "qwen" in raw_mtype:
2783
+ g_arch = "qwen2moe" if int(arch.get("num_experts") or 0) > 0 else "qwen2"
2784
+ else:
2785
+ g_arch = raw_mtype
2786
+
2787
+ ftype_map = {"bf16": 32, "q4_0": 2, "q2_k": 10, "mixed": 10}
2788
+ kvs: list[tuple[str, int, bytes]] = [
2789
+ ("general.architecture", 8, _pack_gguf_str(g_arch)),
2790
+ ("general.name", 8, _pack_gguf_str(model_name)),
2791
+ ("general.file_type", 4, struct.pack("<I", ftype_map.get(quant_format, 10))),
2792
+ ("general.quantization_version", 4, struct.pack("<I", 2)),
2793
+ ]
2794
+
2795
+ def add_u32(k: str, v: int) -> None:
2796
+ if v is not None and int(v) > 0:
2797
+ kvs.append((k, 4, struct.pack("<I", int(v))))
2798
+
2799
+ def add_f32(k: str, v: float) -> None:
2800
+ if v is not None:
2801
+ kvs.append((k, 6, struct.pack("<f", float(v))))
2802
+
2803
+ add_u32(f"{g_arch}.block_count", int(arch.get("num_hidden_layers", 0)))
2804
+ add_u32(f"{g_arch}.embedding_length", int(arch.get("hidden_size", 0)))
2805
+ add_u32(
2806
+ f"{g_arch}.feed_forward_length",
2807
+ int(arch.get("intermediate_size") or arch.get("moe_intermediate_size") or 0),
2808
+ )
2809
+ add_u32(f"{g_arch}.expert_feed_forward_length", int(arch.get("moe_intermediate_size") or 0))
2810
+ add_u32(f"{g_arch}.attention.head_count", int(arch.get("num_attention_heads", 0)))
2811
+ add_u32(
2812
+ f"{g_arch}.attention.head_count_kv",
2813
+ int(arch.get("num_key_value_heads") or arch.get("num_attention_heads") or 0),
2814
+ )
2815
+ add_f32(
2816
+ f"{g_arch}.attention.layer_norm_rms_epsilon",
2817
+ float(arch.get("rms_norm_eps", 1.0e-5)),
2818
+ )
2819
+ add_u32(f"{g_arch}.expert_count", int(arch.get("num_experts") or 0))
2820
+ add_u32(
2821
+ f"{g_arch}.expert_used_count",
2822
+ int(arch.get("num_experts_per_token") or arch.get("num_experts_per_tok") or 0),
2823
+ )
2824
+ add_u32(f"{g_arch}.context_length", int(arch.get("max_position_embeddings", 32768)))
2825
+ add_u32(f"{g_arch}.vocab_size", int(arch.get("vocab_size", 0)))
2826
+ add_u32(f"{g_arch}.attention.q_lora_rank", int(arch.get("q_lora_rank") or 0))
2827
+ add_u32(f"{g_arch}.attention.kv_lora_rank", int(arch.get("kv_lora_rank") or 0))
2828
+
2829
+ vocab_sz = int(arch.get("vocab_size", 0))
2830
+ if tokenizer_path is not None and tokenizer_path.exists():
2831
+ try:
2832
+ tok_data = json.loads(tokenizer_path.read_text())
2833
+ vmap: dict[str, int] = tok_data.get("model", {}).get("vocab", {})
2834
+ added = tok_data.get("added_tokens", [])
2835
+ max_id = max(
2836
+ [vocab_sz - 1]
2837
+ + list(vmap.values())
2838
+ + [int(a.get("id", -1)) for a in added]
2839
+ )
2840
+ n_tok = max(max_id + 1, 1)
2841
+ tokens = [f"<|tok_{i}|>" for i in range(n_tok)]
2842
+ ttypes = np.ones(n_tok, dtype="<i4")
2843
+ for s, tid in vmap.items():
2844
+ if 0 <= tid < n_tok:
2845
+ tokens[tid] = s
2846
+ for a in added:
2847
+ tid = int(a.get("id", -1))
2848
+ if 0 <= tid < n_tok:
2849
+ tokens[tid] = str(a.get("content", tokens[tid]))
2850
+ if a.get("special", False):
2851
+ ttypes[tid] = 3
2852
+
2853
+ kvs.append(("tokenizer.ggml.model", 8, _pack_gguf_str("gpt2")))
2854
+ kvs.append(("tokenizer.ggml.pre", 8, _pack_gguf_str("default")))
2855
+ tok_buf = bytearray(struct.pack("<IQ", 8, len(tokens)))
2856
+ for s in tokens:
2857
+ tok_buf.extend(_pack_gguf_str(s))
2858
+ kvs.append(("tokenizer.ggml.tokens", 9, bytes(tok_buf)))
2859
+ kvs.append(
2860
+ (
2861
+ "tokenizer.ggml.token_type",
2862
+ 9,
2863
+ struct.pack("<IQ", 5, len(tokens)) + ttypes.tobytes(),
2864
+ )
2865
+ )
2866
+ merges = tok_data.get("model", {}).get("merges", [])
2867
+ if merges:
2868
+ m_buf = bytearray(struct.pack("<IQ", 8, len(merges)))
2869
+ for m in merges:
2870
+ ms = " ".join(m) if isinstance(m, list) else str(m)
2871
+ m_buf.extend(_pack_gguf_str(ms))
2872
+ kvs.append(("tokenizer.ggml.merges", 9, bytes(m_buf)))
2873
+ except Exception:
2874
+ pass
2875
+
2876
+ if "bos_token_id" in arch and arch["bos_token_id"] is not None:
2877
+ kvs.append(("tokenizer.ggml.bos_token_id", 4, struct.pack("<I", int(arch["bos_token_id"]))))
2878
+ if "eos_token_id" in arch and arch["eos_token_id"] is not None:
2879
+ kvs.append(("tokenizer.ggml.eos_token_id", 4, struct.pack("<I", int(arch["eos_token_id"]))))
2880
+ if "pad_token_id" in arch and arch["pad_token_id"] is not None:
2881
+ kvs.append(("tokenizer.ggml.padding_token_id", 4, struct.pack("<I", int(arch["pad_token_id"]))))
2882
+ if chat_template_path is not None and chat_template_path.exists():
2883
+ kvs.append(("tokenizer.chat_template", 8, _pack_gguf_str(chat_template_path.read_text())))
2884
+
2885
+ return kvs
2886
+
2887
+
2888
+ def export_safetensors_to_gguf(
2889
+ safetensors_path: str | Path,
2890
+ output_gguf: str | Path,
2891
+ config: str | Path | None = None,
2892
+ quant_format: str = "mixed",
2893
+ device: str = "auto",
2894
+ verbose: bool = True,
2895
+ progress_cb=None,
2896
+ stop_event=None,
2897
+ ) -> dict:
2898
+ """Convert a SafeTensors model (including FP4/FP8 DeepSeek-V4.1, Raon, Llama, Qwen, Mixtral) to GGUF.
2899
+
2900
+ * Unpacks FP4 (``I8`` + ``.scale``) and FP8 (``F8_E4M3`` + ``.scale`` / ``.weight_scale_inv``)
2901
+ tensor pairs on the fly.
2902
+ * Stacks routed MoE experts ``0..E-1`` per layer into standard 3D GGUF expert tensors
2903
+ (``blk.{l}.ffn_{gate,up,down}_exps.weight``).
2904
+ * Quantizes eligible weights using HPC-Quantize V2 (``mixed``, ``q2_k``, ``q4_0``, or ``bf16``)
2905
+ with cross-layer payload caching for identical CheckFree anchor layers.
2906
+ """
2907
+ if safe_open is None or torch is None:
2908
+ raise RuntimeError("safetensors + torch are required for GGUF export")
2909
+
2910
+ st_path = Path(safetensors_path)
2911
+ out_path = Path(output_gguf)
2912
+ out_path.parent.mkdir(parents=True, exist_ok=True)
2913
+ cfg_path = Path(config) if config else st_path.parent / "config.json"
2914
+ raw_cfg = json.loads(cfg_path.read_text()) if cfg_path.exists() else {}
2915
+ arch = _normalize_arch_config(raw_cfg)
2916
+ tok_path = cfg_path.parent / "tokenizer.json"
2917
+ if not tok_path.exists():
2918
+ tok_path = st_path.parent / "tokenizer.json"
2919
+ chat_path = cfg_path.parent / "chat_template.jinja"
2920
+ if not chat_path.exists():
2921
+ chat_path = st_path.parent / "chat_template.jinja"
2922
+
2923
+ use_cuda = (device in ("auto", "cuda")) and torch.cuda.is_available()
2924
+ dev = torch.device("cuda:0" if use_cuda else "cpu")
2925
+ lut = torch.tensor(_FP4_LUT_CPU, dtype=torch.float32, device=dev)
2926
+
2927
+ hpc_cfg = HPCConfig(
2928
+ device="cuda" if use_cuda else "cpu",
2929
+ quant_format=quant_format if quant_format in ("mixed", "q2_k", "q4_0") else "mixed",
2930
+ verbose=False,
2931
+ ).validate()
2932
+ quantizer = Q2KQuantizer(hpc_cfg)
2933
+
2934
+ with safe_open(str(st_path), framework="pt", device="cpu") as f:
2935
+ keys = sorted(f.keys())
2936
+ keys_set = set(keys)
2937
+
2938
+ # Group routed experts by (layer_idx, proj) -> sorted [(expert_idx, weight_key, scale_key)]
2939
+ expert_groups: dict[tuple[int, str], list[tuple[int, str, str | None]]] = {}
2940
+ consumed_keys: set[str] = set()
2941
+
2942
+ for k in keys:
2943
+ if k.endswith((".scale", ".weight_scale_inv", ".scales", ".weight_scale")):
2944
+ base_w = k.rsplit(".", 1)[0] + ".weight"
2945
+ if base_w in keys_set:
2946
+ consumed_keys.add(k)
2947
+ continue
2948
+ em = EXPERT_RE.match(k)
2949
+ if em and em.group(6) == "weight":
2950
+ lidx = int(em.group(2))
2951
+ eidx = int(em.group(4))
2952
+ proj = em.group(5)
2953
+ sc_k = None
2954
+ for sfx in (".scale", ".weight_scale_inv", ".scales", ".weight_scale"):
2955
+ cand_s = k[:-7] + sfx
2956
+ if cand_s in keys_set:
2957
+ sc_k = cand_s
2958
+ consumed_keys.add(cand_s)
2959
+ break
2960
+ expert_groups.setdefault((lidx, proj), []).append((eidx, k, sc_k))
2961
+ consumed_keys.add(k)
2962
+
2963
+ for gk in expert_groups:
2964
+ expert_groups[gk].sort(key=lambda x: x[0])
2965
+
2966
+ # Build work items: ("single", src_key, scale_key, gguf_name) or ("experts", (lidx, proj), items, gguf_name)
2967
+ work_items: list[tuple] = []
2968
+ for k in keys:
2969
+ if k in consumed_keys:
2970
+ continue
2971
+ sc_k = None
2972
+ if k.endswith(".weight"):
2973
+ for sfx in (".scale", ".weight_scale_inv", ".scales", ".weight_scale"):
2974
+ cand_s = k[:-7] + sfx
2975
+ if cand_s in keys_set:
2976
+ sc_k = cand_s
2977
+ break
2978
+ if _is_embed_key(k):
2979
+ gname = "token_embd.weight"
2980
+ elif _is_head_key(k):
2981
+ gname = "output.weight"
2982
+ elif k in _NORM_NAMES:
2983
+ gname = "output_norm.weight"
2984
+ else:
2985
+ lm = LAYER_RE.match(k)
2986
+ if lm:
2987
+ lidx = int(lm.group(2))
2988
+ suf = lm.group(3)
2989
+ mapped = _LAYER_SUFFIX_TO_GGUF.get(suf, suf)
2990
+ gname = f"blk.{lidx}.{mapped}"
2991
+ else:
2992
+ gname = k
2993
+ work_items.append(("single", k, sc_k, gname))
2994
+
2995
+ for (lidx, proj), members in sorted(expert_groups.items()):
2996
+ mapped_proj = _EXPERT_PROJ_TO_GGUF.get(proj, f"ffn_{proj}_exps.weight")
2997
+ gname = f"blk.{lidx}.{mapped_proj}"
2998
+ work_items.append(("experts", (lidx, proj), members, gname))
2999
+
3000
+ # Stream quantized/converted tensor payloads into a temporary data file and record GGUF directory
3001
+ tmp_data = tempfile.NamedTemporaryFile(delete=False, dir=str(out_path.parent))
3002
+ gguf_tensors: list[tuple[str, tuple[int, ...], int, int]] = []
3003
+ data_offset = 0
3004
+ payload_cache: dict[tuple, tuple[int, tuple[int, ...], int, int]] = {}
3005
+ stats = {"tensors": 0, "q2_k": 0, "q4_0": 0, "bf16": 0, "f32": 0}
3006
+ total_items = len(work_items)
3007
+
3008
+ def _dequant_single_to_f32_torch(w_key: str, s_key: str | None) -> "torch.Tensor":
3009
+ wt = f.get_tensor(w_key).to(dev)
3010
+ dt_s = _safetensors_dtype(f.get_slice(w_key).get_dtype())
3011
+ if s_key is not None and s_key in keys_set:
3012
+ st = f.get_tensor(s_key).to(dev)
3013
+ if dt_s == "I8":
3014
+ return _ds4_dequant_fp4_1x32(wt, st, lut)
3015
+ if dt_s.startswith("F8"):
3016
+ if st.ndim == 2 and wt.shape[0] // st.shape[0] == 32 and wt.shape[1] // st.shape[1] == 32:
3017
+ return _ds4_dequant_fp8_32x32(wt, st)
3018
+ return _dequant_mxfp8_torch(wt, st)
3019
+ return wt.float()
3020
+
3021
+ def _choose_gguf_target(gname: str, torch_shape: tuple[int, ...]) -> str:
3022
+ if len(torch_shape) < 2 or "norm" in gname or gname.endswith(".bias") or "ffn_gate_inp" in gname or "hc_" in gname or "attn_sink" in gname:
3023
+ return "F32" if len(torch_shape) == 1 else "BF16"
3024
+ if quant_format == "bf16":
3025
+ return "BF16"
3026
+ row_w = int(torch_shape[-1])
3027
+ n_el = int(np.prod(torch_shape))
3028
+ is_emb = gname in ("token_embd.weight", "output.weight")
3029
+ if quant_format == "q4_0":
3030
+ return "Q4_0" if (row_w % QK4_0 == 0 and n_el % QK4_0 == 0) else "BF16"
3031
+ if quant_format == "q2_k":
3032
+ if not is_emb and row_w % QK_K == 0 and n_el % QK_K == 0:
3033
+ return "Q2_K"
3034
+ return "BF16"
3035
+ # mixed
3036
+ if is_emb:
3037
+ return "Q4_0" if (row_w % QK4_0 == 0 and n_el % QK4_0 == 0) else "BF16"
3038
+ if row_w % QK_K == 0 and n_el % QK_K == 0:
3039
+ return "Q2_K"
3040
+ if row_w % QK4_0 == 0 and n_el % QK4_0 == 0:
3041
+ return "Q4_0"
3042
+ return "BF16"
3043
+
3044
+ def _encode_tensor_f32(t_f32: "torch.Tensor", tgt: str) -> tuple[int, bytes]:
3045
+ row_w = int(t_f32.shape[-1])
3046
+ if tgt == "F32":
3047
+ return _GGML_F32, t_f32.detach().cpu().numpy().astype("<f4").tobytes()
3048
+ if tgt == "BF16":
3049
+ b16 = t_f32.to(torch.bfloat16).view(torch.uint16).detach().cpu().numpy().astype("<u2").tobytes()
3050
+ return _GGML_BF16, b16
3051
+ if tgt == "Q4_0":
3052
+ total_r = int(np.prod(t_f32.shape[:-1]))
3053
+ t2d = t_f32.reshape(total_r, row_w)
3054
+ chunk_r = max(1, (8 * 1024 * 1024) // max(row_w, 1))
3055
+ out_chunks = []
3056
+ for r0 in range(0, total_r, chunk_r):
3057
+ sub = t2d[r0 : min(r0 + chunk_r, total_r)].detach().cpu().numpy().astype(np.float32)
3058
+ raw_q4, _, _ = quantize_tensor_q4_0(sub, cfg=hpc_cfg)
3059
+ out_chunks.append(raw_q4)
3060
+ return _GGML_Q4_0, b"".join(out_chunks)
3061
+ if tgt == "Q2_K":
3062
+ flat_np = t_f32.detach().cpu().numpy().astype(np.float32).reshape(-1)
3063
+ res = quantizer.quantize(flat_np, row_width=row_w)
3064
+ return _GGML_Q2_K, blocks_to_bytes(res.scales, res.qs, res.dm)
3065
+ raise ValueError(tgt)
3066
+
3067
+ for idx_w, item in enumerate(work_items, 1):
3068
+ if stop_event is not None and stop_event.is_set():
3069
+ tmp_data.close()
3070
+ os.unlink(tmp_data.name)
3071
+ raise InterruptedError("GGUF export cancelled by user.")
3072
+
3073
+ kind = item[0]
3074
+ if kind == "single":
3075
+ _, w_key, s_key, gname = item
3076
+ sl = f.get_slice(w_key)
3077
+ t_shape = tuple(sl.get_shape())
3078
+ g_dims = tuple(reversed(t_shape)) if t_shape else (1,)
3079
+ tgt = _choose_gguf_target(gname, t_shape or (1,))
3080
+
3081
+ # Fast signature for identical anchor layer reuse
3082
+ lm = LAYER_RE.match(w_key)
3083
+ cache_key = None
3084
+ if lm:
3085
+ suf = lm.group(3)
3086
+ w_Sample = _payload_bytes(f.get_tensor(w_key).flatten()[:256])
3087
+ cache_key = ("single", suf, t_shape, tgt, w_Sample)
3088
+ if cache_key is not None and cache_key in payload_cache:
3089
+ out_type, g_dims, src_off, src_len = payload_cache[cache_key]
3090
+ raw_bytes = os.pread(tmp_data.fileno(), src_len, src_off)
3091
+ else:
3092
+ t_f32 = _dequant_single_to_f32_torch(w_key, s_key)
3093
+ if not t_shape:
3094
+ t_f32 = t_f32.reshape(1)
3095
+ out_type, raw_bytes = _encode_tensor_f32(t_f32, tgt)
3096
+ del t_f32
3097
+ else:
3098
+ _, (lidx, proj), members, gname = item
3099
+ first_w = members[0][1]
3100
+ e_shape = tuple(f.get_slice(first_w).get_shape())
3101
+ # If packed FP4 I8, logical in_dim is 2 * stored in_dim
3102
+ dt_e = _safetensors_dtype(f.get_slice(first_w).get_dtype())
3103
+ if dt_e == "I8" and members[0][2] is not None:
3104
+ e_shape = (e_shape[0], e_shape[1] * 2)
3105
+ full_shape = (len(members), e_shape[0], e_shape[1])
3106
+ g_dims = (e_shape[1], e_shape[0], len(members))
3107
+ tgt = _choose_gguf_target(gname, full_shape)
3108
+
3109
+ w_sample = _payload_bytes(f.get_tensor(first_w).flatten()[:256])
3110
+ cache_key = ("experts", proj, full_shape, tgt, w_sample)
3111
+ if cache_key in payload_cache:
3112
+ out_type, g_dims, src_off, src_len = payload_cache[cache_key]
3113
+ raw_bytes = os.pread(tmp_data.fileno(), src_len, src_off)
3114
+ else:
3115
+ chunks = []
3116
+ for _, wk, sk in members:
3117
+ ef32 = _dequant_single_to_f32_torch(wk, sk)
3118
+ _, eb = _encode_tensor_f32(ef32, tgt)
3119
+ chunks.append(eb)
3120
+ del ef32
3121
+ raw_bytes = b"".join(chunks)
3122
+ out_type = (
3123
+ _GGML_Q2_K
3124
+ if tgt == "Q2_K"
3125
+ else (_GGML_Q4_0 if tgt == "Q4_0" else (_GGML_BF16 if tgt == "BF16" else _GGML_F32))
3126
+ )
3127
+
3128
+ pad = _gguf_align(data_offset) - data_offset
3129
+ if pad > 0:
3130
+ tmp_data.write(b"\x00" * pad)
3131
+ data_offset += pad
3132
+ cur_off = data_offset
3133
+ tmp_data.write(raw_bytes)
3134
+ tmp_data.flush()
3135
+ data_offset += len(raw_bytes)
3136
+
3137
+ if cache_key is not None and cache_key not in payload_cache:
3138
+ payload_cache[cache_key] = (out_type, g_dims, cur_off, len(raw_bytes))
3139
+
3140
+ gguf_tensors.append((gname, g_dims, out_type, cur_off))
3141
+ stats["tensors"] += 1
3142
+ if out_type == _GGML_Q2_K:
3143
+ stats["q2_k"] += 1
3144
+ elif out_type == _GGML_Q4_0:
3145
+ stats["q4_0"] += 1
3146
+ elif out_type == _GGML_BF16:
3147
+ stats["bf16"] += 1
3148
+ else:
3149
+ stats["f32"] += 1
3150
+
3151
+ if progress_cb is not None and (idx_w % 8 == 0 or idx_w == total_items):
3152
+ progress_cb(idx_w, total_items, gname, tgt, stats)
3153
+
3154
+ # Update effective expert count in arch metadata if stacked experts were pruned
3155
+ if expert_groups:
3156
+ first_group = next(iter(expert_groups.values()))
3157
+ arch["num_experts"] = len(first_group)
3158
+
3159
+ kv_pairs = _build_gguf_kv_pairs(
3160
+ arch,
3161
+ tok_path if tok_path.exists() else None,
3162
+ chat_path if chat_path.exists() else None,
3163
+ quant_format,
3164
+ st_path.stem,
3165
+ )
3166
+
3167
+ with out_path.open("wb") as fout:
3168
+ fout.write(struct.pack("<IIQQ", _GGUF_MAGIC, 3, len(gguf_tensors), len(kv_pairs)))
3169
+ for k, vt, raw_v in kv_pairs:
3170
+ fout.write(_pack_gguf_str(k))
3171
+ fout.write(struct.pack("<I", vt))
3172
+ fout.write(raw_v)
3173
+ for gname, g_dims, out_type, off in gguf_tensors:
3174
+ fout.write(_pack_gguf_str(gname))
3175
+ fout.write(struct.pack("<I", len(g_dims)))
3176
+ for d in g_dims:
3177
+ fout.write(struct.pack("<Q", int(d)))
3178
+ fout.write(struct.pack("<I", int(out_type)))
3179
+ fout.write(struct.pack("<Q", int(off)))
3180
+ data_start = _gguf_align(fout.tell())
3181
+ if data_start > fout.tell():
3182
+ fout.write(b"\x00" * (data_start - fout.tell()))
3183
+ tmp_data.seek(0)
3184
+ shutil.copyfileobj(tmp_data, fout, length=16 * 1024 * 1024)
3185
+
3186
+ tmp_data.close()
3187
+ os.unlink(tmp_data.name)
3188
+ stats["output_bytes"] = out_path.stat().st_size
3189
+ if verbose:
3190
+ print(
3191
+ f"Exported GGUF -> {out_path} ({stats['output_bytes'] / 1e9:.2f} GB, "
3192
+ f"{stats['tensors']} tensors: Q2_K={stats['q2_k']}, Q4_0={stats['q4_0']}, "
3193
+ f"BF16={stats['bf16']}, F32={stats['f32']})"
3194
+ )
3195
+ return stats
3196
+
3197
+
3198
  def main() -> None:
3199
  ap = argparse.ArgumentParser(description="HPC SlimShard / CheckFree single-shard LLM recovery")
3200
  sub = ap.add_subparsers(dest="cmd", required=False)