CompressedGemma commited on
Commit
88d5ea8
·
verified ·
1 Parent(s): 76422e0

Upload 5 files

Browse files
Files changed (4) hide show
  1. __main__.py +34 -2
  2. config.py +13 -3
  3. gguf.py +53 -5
  4. gui.py +168 -5
__main__.py CHANGED
@@ -57,6 +57,29 @@ def _config_from_args(args) -> HPCConfig:
57
  cfg.quant_format = args.format
58
  if args.format == "q2_k":
59
  cfg.enable_q4_fallback = False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  return cfg.validate()
61
 
62
 
@@ -101,6 +124,7 @@ def _run_gguf(args, cfg: HPCConfig) -> None:
101
  promote_attn_q4=cfg.promote_attn_q4,
102
  quant_format=cfg.quant_format,
103
  source_type=ti.type,
 
104
  )
105
  tag = tgt if tgt else "COPY"
106
  print(
@@ -254,9 +278,17 @@ def main() -> None:
254
  parser.add_argument("--no-spectral", action="store_true", help="disable spectral/DC objective")
255
  parser.add_argument(
256
  "--format",
257
- choices=("mixed", "mixed_q1", "q1_0", "q4_0", "q2_k"),
258
  default=None,
259
- help="quantization format mode: mixed (Q2_K+Q4_0), mixed_q1 (Q1_0+Q4_0), q1_0 (pure Q1_0), q4_0 (pure Q4_0), or q2_k (pure Q2_K)",
 
 
 
 
 
 
 
 
260
  )
261
  parser.add_argument("--no-q4-fallback", action="store_true", help="disable Q4_0 fallback for non-256-aligned tensors")
262
  parser.add_argument("--keep-embd", action="store_true", help="keep token_embd/output.weight at source precision")
 
57
  cfg.quant_format = args.format
58
  if args.format == "q2_k":
59
  cfg.enable_q4_fallback = False
60
+ if getattr(args, "tensor_type", None):
61
+ custom: dict[str, str] = {}
62
+ for item in args.tensor_type:
63
+ if "=" not in item:
64
+ raise SystemExit(f"--tensor-type expects TYPE=QUANT, got {item!r}")
65
+ key, value = (part.strip() for part in item.split("=", 1))
66
+ if not key:
67
+ raise SystemExit(f"--tensor-type has an empty tensor type: {item!r}")
68
+ canonical = {
69
+ "q1_0": "Q1_0",
70
+ "q2_k": "Q2_K",
71
+ "q4_0": "Q4_0",
72
+ "copy": "Copy",
73
+ "auto": "Auto",
74
+ }
75
+ norm = canonical.get(value.lower())
76
+ if norm is None:
77
+ raise SystemExit(
78
+ f"--tensor-type {key!r} has invalid quant {value!r}; "
79
+ "use Q1_0, Q2_K, Q4_0, Copy, or Auto"
80
+ )
81
+ custom[key] = norm
82
+ cfg.custom_quant_map = custom
83
  return cfg.validate()
84
 
85
 
 
124
  promote_attn_q4=cfg.promote_attn_q4,
125
  quant_format=cfg.quant_format,
126
  source_type=ti.type,
127
+ custom_quant_map=cfg.custom_quant_map or None,
128
  )
129
  tag = tgt if tgt else "COPY"
130
  print(
 
278
  parser.add_argument("--no-spectral", action="store_true", help="disable spectral/DC objective")
279
  parser.add_argument(
280
  "--format",
281
+ choices=("mixed", "mixed_q1", "custom", "q1_0", "q4_0", "q2_k"),
282
  default=None,
283
+ help="quantization format mode: mixed (Q2_K+Q4_0), mixed_q1 (Q1_0+Q4_0), custom (per-tensor-type overrides), q1_0 (pure Q1_0), q4_0 (pure Q4_0), or q2_k (pure Q2_K)",
284
+ )
285
+ parser.add_argument(
286
+ "--tensor-type",
287
+ action="append",
288
+ default=[],
289
+ metavar="TYPE=QUANT",
290
+ help="per-tensor-type override, e.g. ffn_up=Q1_0 or attn_output=Q1_0 "
291
+ "(QUANT: Q1_0, Q2_K, Q4_0, Copy, Auto; repeatable)",
292
  )
293
  parser.add_argument("--no-q4-fallback", action="store_true", help="disable Q4_0 fallback for non-256-aligned tensors")
294
  parser.add_argument("--keep-embd", action="store_true", help="keep token_embd/output.weight at source precision")
config.py CHANGED
@@ -8,7 +8,7 @@ The defaults are the C engine's production defaults unless marked
8
 
9
  from __future__ import annotations
10
 
11
- from dataclasses import dataclass
12
 
13
 
14
  @dataclass(slots=True)
@@ -69,6 +69,7 @@ class HPCConfig:
69
  use_candidate_floor: bool = True
70
  apply_dc_carry: bool = True
71
  quant_format: str = "mixed"
 
72
  enable_q4_fallback: bool = True
73
  quantize_embd_q4: bool = True
74
  promote_attn_q4: bool = False
@@ -120,6 +121,15 @@ class HPCConfig:
120
  raise ValueError("workers must be >= 0 (0 = auto CPU count)")
121
  if self.device not in ("auto", "cuda", "cpu") and not self.device.startswith("cuda:"):
122
  raise ValueError("device must be 'auto', 'cuda', 'cuda:N', or 'cpu'")
123
- if self.quant_format not in ("mixed", "mixed_q1", "q1_0", "q4_0", "q2_k"):
124
- raise ValueError("quant_format must be 'mixed', 'mixed_q1', 'q1_0', 'q4_0', or 'q2_k'")
 
 
 
 
 
 
 
 
 
125
  return self
 
8
 
9
  from __future__ import annotations
10
 
11
+ from dataclasses import dataclass, field
12
 
13
 
14
  @dataclass(slots=True)
 
69
  use_candidate_floor: bool = True
70
  apply_dc_carry: bool = True
71
  quant_format: str = "mixed"
72
+ custom_quant_map: dict[str, str] = field(default_factory=dict)
73
  enable_q4_fallback: bool = True
74
  quantize_embd_q4: bool = True
75
  promote_attn_q4: bool = False
 
121
  raise ValueError("workers must be >= 0 (0 = auto CPU count)")
122
  if self.device not in ("auto", "cuda", "cpu") and not self.device.startswith("cuda:"):
123
  raise ValueError("device must be 'auto', 'cuda', 'cuda:N', or 'cpu'")
124
+ if self.quant_format not in ("mixed", "mixed_q1", "custom", "q1_0", "q4_0", "q2_k"):
125
+ raise ValueError(
126
+ "quant_format must be 'mixed', 'mixed_q1', 'custom', 'q1_0', 'q4_0', or 'q2_k'"
127
+ )
128
+ allowed_custom = {"q1_0", "q2_k", "q4_0", "copy", "auto"}
129
+ for tensor_type, quant in self.custom_quant_map.items():
130
+ if str(quant).strip().lower() not in allowed_custom:
131
+ raise ValueError(
132
+ f"custom_quant_map[{tensor_type!r}] must be one of "
133
+ f"Q1_0, Q2_K, Q4_0, Copy, Auto, got {quant!r}"
134
+ )
135
  return self
gguf.py CHANGED
@@ -14,6 +14,7 @@ packed by an external GGUF writer.
14
 
15
  from __future__ import annotations
16
 
 
17
  import struct
18
  import time
19
  from dataclasses import dataclass
@@ -412,6 +413,18 @@ def expand_importance(
412
  )
413
 
414
 
 
 
 
 
 
 
 
 
 
 
 
 
415
  def _is_skipped_metadata_tensor(name: str, dims: tuple[int, ...]) -> bool:
416
  if len(dims) < 2:
417
  return True
@@ -539,6 +552,7 @@ def target_quant_type(
539
  promote_attn_q4: bool = False,
540
  quant_format: str = "mixed",
541
  source_type: int | None = None,
 
542
  ) -> str | None:
543
  """Determine target quantization format ('Q1_0', 'Q2_K', 'Q4_0', or None for Copy).
544
 
@@ -547,15 +561,39 @@ def target_quant_type(
547
  tensors (and embeddings/head if quantize_embd_q4) -> Q4_0.
548
  * 'mixed_q1': FFN/expert 128-aligned tensors -> Q1_0; attention/SSM projections,
549
  embeddings/head, and non-128-aligned 32-aligned tensors -> Q4_0.
 
 
550
  * 'q4_0': all 32-aligned eligible weight tensors -> Q4_0.
551
  * 'q2_k': only Q2_K-eligible tensors -> Q2_K; everything else copied.
552
  * 'q1_0': all 128-aligned eligible weight tensors -> Q1_0.
553
 
 
 
 
 
 
 
554
  Never promotes a lower-bit source tensor to a higher-bit target format
555
  (e.g., a Q2_K source tensor is never re-quantized to Q4_0).
556
  """
 
557
  tgt: str | None = None
558
- if quant_format == "q1_0":
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
559
  if promote_attn_q4 and _is_attention_projection(name) and is_q4_0_eligible(
560
  name, dims, include_embd=quantize_embd_q4, promote_attn=True, allow_q2k_tensors=True
561
  ):
@@ -570,7 +608,7 @@ def target_quant_type(
570
  name, dims, include_embd=quantize_embd_q4, promote_attn=True, allow_q2k_tensors=True
571
  ):
572
  tgt = "Q4_0"
573
- elif quant_format == "mixed_q1":
574
  if (_is_attention_projection(name) or _is_tiny_ssm_gate(name, dims)) and is_q4_0_eligible(
575
  name, dims, include_embd=quantize_embd_q4, promote_attn=True, allow_q2k_tensors=True
576
  ):
@@ -584,12 +622,12 @@ def target_quant_type(
584
  name, dims, include_embd=quantize_embd_q4, promote_attn=True, allow_q2k_tensors=True
585
  ):
586
  tgt = "Q4_0"
587
- elif quant_format == "q4_0":
588
  if is_q4_0_eligible(
589
  name, dims, include_embd=quantize_embd_q4, allow_q2k_tensors=True
590
  ):
591
  tgt = "Q4_0"
592
- elif quant_format == "q2_k":
593
  if is_q2k_eligible(name, dims):
594
  tgt = "Q2_K"
595
  else:
@@ -649,6 +687,7 @@ def write_quantized_gguf(
649
  embd_q4 = bool(getattr(cfg, "quantize_embd_q4", True))
650
  attn_q4 = bool(getattr(cfg, "promote_attn_q4", False))
651
  q_format = str(getattr(cfg, "quant_format", "mixed"))
 
652
 
653
  plan: list[str | None] = []
654
  quantized_count = 0
@@ -664,8 +703,16 @@ def write_quantized_gguf(
664
  promote_attn_q4=attn_q4,
665
  quant_format=q_format,
666
  source_type=ti.type,
 
 
 
 
 
 
 
 
667
  )
668
- if target_fmt is None:
669
  src_bpw = source_type_bpw(ti.type)
670
  if q_format == "q1_0" and len(ti.dims) >= 2 and ti.dims[0] % QK1_0 == 0 and src_bpw > 1.125:
671
  target_fmt = "Q1_0"
@@ -686,6 +733,7 @@ def write_quantized_gguf(
686
  promote_attn_q4=attn_q4,
687
  quant_format=q_format,
688
  source_type=ti.type,
 
689
  )
690
  if target_fmt and ti.type not in SUPPORTED_READ_TYPES:
691
  if verbose:
 
14
 
15
  from __future__ import annotations
16
 
17
+ import re
18
  import struct
19
  import time
20
  from dataclasses import dataclass
 
413
  )
414
 
415
 
416
+ _BLOCK_PREFIX_RE = re.compile(r"^blk\.\d+\.")
417
+
418
+
419
+ def tensor_type_key(name: str) -> str:
420
+ """Return the layer-independent tensor type (e.g. ``blk.4.ffn_up.weight`` -> ``ffn_up``)."""
421
+ key = _BLOCK_PREFIX_RE.sub("", name)
422
+ for suffix in (".weight", ".bias"):
423
+ if key.endswith(suffix):
424
+ return key[: -len(suffix)]
425
+ return key
426
+
427
+
428
  def _is_skipped_metadata_tensor(name: str, dims: tuple[int, ...]) -> bool:
429
  if len(dims) < 2:
430
  return True
 
552
  promote_attn_q4: bool = False,
553
  quant_format: str = "mixed",
554
  source_type: int | None = None,
555
+ custom_quant_map: dict[str, str] | None = None,
556
  ) -> str | None:
557
  """Determine target quantization format ('Q1_0', 'Q2_K', 'Q4_0', or None for Copy).
558
 
 
561
  tensors (and embeddings/head if quantize_embd_q4) -> Q4_0.
562
  * 'mixed_q1': FFN/expert 128-aligned tensors -> Q1_0; attention/SSM projections,
563
  embeddings/head, and non-128-aligned 32-aligned tensors -> Q4_0.
564
+ * 'custom': per-tensor-type overrides from ``custom_quant_map``; unlisted
565
+ tensor types fall back to the 'mixed' plan.
566
  * 'q4_0': all 32-aligned eligible weight tensors -> Q4_0.
567
  * 'q2_k': only Q2_K-eligible tensors -> Q2_K; everything else copied.
568
  * 'q1_0': all 128-aligned eligible weight tensors -> Q1_0.
569
 
570
+ ``custom_quant_map`` maps a layer-independent tensor type (see
571
+ :func:`tensor_type_key`) to 'Q1_0', 'Q2_K', 'Q4_0', 'Copy', or 'Auto'.
572
+ Non-Auto entries override the selected mode for that tensor type. A target
573
+ is applied only when the tensor is actually eligible for it; explicit
574
+ 'Copy' (and ineligible targets) leave the tensor at its source precision.
575
+
576
  Never promotes a lower-bit source tensor to a higher-bit target format
577
  (e.g., a Q2_K source tensor is never re-quantized to Q4_0).
578
  """
579
+ fmt = "mixed" if quant_format == "custom" else quant_format
580
  tgt: str | None = None
581
+ custom_choice = None
582
+ if custom_quant_map:
583
+ custom_choice = custom_quant_map.get(tensor_type_key(name))
584
+ if custom_choice is not None and str(custom_choice).strip().lower() not in ("", "auto"):
585
+ choice = str(custom_choice).strip().upper()
586
+ if choice == "Q1_0":
587
+ if is_q1_0_eligible(name, dims, include_embd=True):
588
+ tgt = "Q1_0"
589
+ elif choice == "Q2_K":
590
+ if is_q2k_eligible(name, dims):
591
+ tgt = "Q2_K"
592
+ elif choice == "Q4_0":
593
+ if is_q4_0_eligible(name, dims, include_embd=True, allow_q2k_tensors=True):
594
+ tgt = "Q4_0"
595
+ # 'COPY', unknown values, and ineligible targets leave tgt as None.
596
+ elif fmt == "q1_0":
597
  if promote_attn_q4 and _is_attention_projection(name) and is_q4_0_eligible(
598
  name, dims, include_embd=quantize_embd_q4, promote_attn=True, allow_q2k_tensors=True
599
  ):
 
608
  name, dims, include_embd=quantize_embd_q4, promote_attn=True, allow_q2k_tensors=True
609
  ):
610
  tgt = "Q4_0"
611
+ elif fmt == "mixed_q1":
612
  if (_is_attention_projection(name) or _is_tiny_ssm_gate(name, dims)) and is_q4_0_eligible(
613
  name, dims, include_embd=quantize_embd_q4, promote_attn=True, allow_q2k_tensors=True
614
  ):
 
622
  name, dims, include_embd=quantize_embd_q4, promote_attn=True, allow_q2k_tensors=True
623
  ):
624
  tgt = "Q4_0"
625
+ elif fmt == "q4_0":
626
  if is_q4_0_eligible(
627
  name, dims, include_embd=quantize_embd_q4, allow_q2k_tensors=True
628
  ):
629
  tgt = "Q4_0"
630
+ elif fmt == "q2_k":
631
  if is_q2k_eligible(name, dims):
632
  tgt = "Q2_K"
633
  else:
 
687
  embd_q4 = bool(getattr(cfg, "quantize_embd_q4", True))
688
  attn_q4 = bool(getattr(cfg, "promote_attn_q4", False))
689
  q_format = str(getattr(cfg, "quant_format", "mixed"))
690
+ custom_map = getattr(cfg, "custom_quant_map", None) or None
691
 
692
  plan: list[str | None] = []
693
  quantized_count = 0
 
703
  promote_attn_q4=attn_q4,
704
  quant_format=q_format,
705
  source_type=ti.type,
706
+ custom_quant_map=custom_map,
707
+ )
708
+ custom_choice = None
709
+ if custom_map:
710
+ custom_choice = custom_map.get(tensor_type_key(ti.name))
711
+ explicit_custom = (
712
+ custom_choice is not None
713
+ and str(custom_choice).strip().lower() not in ("", "auto")
714
  )
715
+ if target_fmt is None and not explicit_custom:
716
  src_bpw = source_type_bpw(ti.type)
717
  if q_format == "q1_0" and len(ti.dims) >= 2 and ti.dims[0] % QK1_0 == 0 and src_bpw > 1.125:
718
  target_fmt = "Q1_0"
 
733
  promote_attn_q4=attn_q4,
734
  quant_format=q_format,
735
  source_type=ti.type,
736
+ custom_quant_map=custom_map,
737
  )
738
  if target_fmt and ti.type not in SUPPORTED_READ_TYPES:
739
  if verbose:
gui.py CHANGED
@@ -61,10 +61,39 @@ from hpc_quantize_v2 import (
61
  quantize_tensor_q4_0,
62
  read_imatrix,
63
  )
64
- from hpc_quantize_v2.gguf import is_q2k_eligible, target_quant_type, write_quantized_gguf
 
 
 
 
 
 
 
65
  from hpc_quantize_v2.reference import reference_solve, synthetic_cases
66
 
67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  def _ts() -> str:
69
  return dt.datetime.now().strftime("%H:%M:%S.%f")[:-3]
70
 
@@ -100,6 +129,8 @@ class HPCQuantizeGUI:
100
  self._init_vars()
101
  self._apply_theme()
102
  self._build_layout()
 
 
103
  self._auto_populate_defaults()
104
  self._update_cli_preview()
105
  self.root.after(80, self._poll_queue)
@@ -133,8 +164,9 @@ class HPCQuantizeGUI:
133
  self.q4_fallback_var = tk.BooleanVar(value=True)
134
  self.embd_q4_var = tk.BooleanVar(value=True)
135
  self.promote_attn_q4_var = tk.BooleanVar(value=False)
136
- self.quant_format_var = tk.StringVar(value="mixed")
137
  self.plan_filter_var = tk.StringVar(value="ALL")
 
138
 
139
  self.dc_lambda_var = tk.DoubleVar(value=1.0)
140
  self.vw_lambda_var = tk.DoubleVar(value=1.0)
@@ -310,8 +342,31 @@ class HPCQuantizeGUI:
310
  command=self._on_format_changed,
311
  ).pack(side=tk.LEFT, padx=3)
312
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
313
  opt_row = ttk.Frame(opt_frame)
314
  opt_row.pack(fill=tk.X, pady=(0, 4))
 
315
  ttk.Label(opt_row, text="Global Optimizer:").pack(side=tk.LEFT, padx=(0, 8))
316
  ttk.Radiobutton(
317
  opt_row, text="HPC (Sieve + 36-State Viterbi)", variable=self.optimizer_var, value="hpc"
@@ -566,6 +621,8 @@ class HPCQuantizeGUI:
566
  return "-Q1_0.gguf"
567
  if fmt == "mixed_q1":
568
  return "-Q1_0-Q4_0.gguf"
 
 
569
  if fmt == "q4_0":
570
  return "-Q4_0.gguf"
571
  return "-Q2K.gguf"
@@ -575,11 +632,96 @@ class HPCQuantizeGUI:
575
  gguf_p = self.gguf_var.get().strip()
576
  if gguf_p and (
577
  not cur_out
578
- or any(cur_out.endswith(sfx) for sfx in ("-Q2K.gguf", "-Q1_0.gguf", "-Q1_0-Q4_0.gguf", "-Q4_0.gguf"))
 
 
 
579
  ):
580
  p = Path(gguf_p)
581
  self.output_var.set(str(p.with_name(f"{p.stem}{self._default_out_suffix()}")))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
582
  self._populate_tensor_tree()
 
583
 
584
  def _browse_gguf(self) -> None:
585
  path = filedialog.askopenfilename(
@@ -636,6 +778,7 @@ class HPCQuantizeGUI:
636
  dc_decay=float(self.dc_decay_var.get()),
637
  sse_budget=float(self.sse_budget_var.get()),
638
  quant_format=self.quant_format_var.get(),
 
639
  enable_q4_fallback=bool(self.q4_fallback_var.get()) and self.quant_format_var.get() != "q2_k",
640
  quantize_embd_q4=bool(self.embd_q4_var.get()),
641
  promote_attn_q4=bool(self.promote_attn_q4_var.get()),
@@ -664,6 +807,10 @@ class HPCQuantizeGUI:
664
  if self.limit_var.get() > 0:
665
  cmd += ["--limit", str(self.limit_var.get())]
666
  cmd += ["--format", self.quant_format_var.get()]
 
 
 
 
667
  cmd += ["--device", self.device_var.get()]
668
  cmd += ["--workers", str(self.workers_var.get())]
669
  cmd += ["--cand-d", str(self.cand_d_var.get()), "--cand-m", str(self.cand_m_var.get())]
@@ -709,6 +856,8 @@ class HPCQuantizeGUI:
709
  return
710
  try:
711
  self._reader = GGUFReader(gguf_path)
 
 
712
  self._populate_tensor_tree()
713
  except Exception as exc:
714
  self._reader = None
@@ -731,6 +880,7 @@ class HPCQuantizeGUI:
731
  promote_attn_q4=bool(self.promote_attn_q4_var.get()),
732
  quant_format=self.quant_format_var.get(),
733
  source_type=ti.type,
 
734
  )
735
  if tgt == "Q2_K":
736
  n_q2 += 1
@@ -793,6 +943,7 @@ class HPCQuantizeGUI:
793
  promote_attn_q4=bool(self.promote_attn_q4_var.get()),
794
  quant_format=self.quant_format_var.get(),
795
  source_type=ti.type,
 
796
  )
797
  is not None
798
  and self.tree.exists(ti.name)
@@ -884,7 +1035,17 @@ class HPCQuantizeGUI:
884
  raw = lookup_imatrix(imat, tname)
885
  if raw is not None:
886
  imp = expand_importance(raw, x.size, row)
887
- if cfg.quant_format in ("q1_0", "mixed_q1"):
 
 
 
 
 
 
 
 
 
 
888
  raw_q1, nb_q1, rmse_q1 = quantize_tensor_q1_0(x, importance=imp, cfg=cfg)
889
  np.savez_compressed(
890
  out_path,
@@ -896,7 +1057,7 @@ class HPCQuantizeGUI:
896
  ("done", f"Saved Q1_0 {out_path} (RMSE={rmse_q1:.6e}, {time.time() - t0:.1f}s)")
897
  )
898
  return
899
- if cfg.quant_format == "q4_0":
900
  raw_q4, nb_q4, rmse_q4 = quantize_tensor_q4_0(x, importance=imp, cfg=cfg)
901
  np.savez_compressed(
902
  out_path,
@@ -908,6 +1069,8 @@ class HPCQuantizeGUI:
908
  ("done", f"Saved Q4_0 {out_path} (RMSE={rmse_q4:.6e}, {time.time() - t0:.1f}s)")
909
  )
910
  return
 
 
911
  res = quantizer.quantize(
912
  x,
913
  importance=imp,
 
61
  quantize_tensor_q4_0,
62
  read_imatrix,
63
  )
64
+ from hpc_quantize_v2.gguf import (
65
+ is_q1_0_eligible,
66
+ is_q2k_eligible,
67
+ is_q4_0_eligible,
68
+ target_quant_type,
69
+ tensor_type_key,
70
+ write_quantized_gguf,
71
+ )
72
  from hpc_quantize_v2.reference import reference_solve, synthetic_cases
73
 
74
 
75
+ DEFAULT_CUSTOM_RECIPE: dict[str, str] = {
76
+ # Q4_0: quality-critical embeddings, attention, and SSM projections
77
+ "token_embd": "Q4_0",
78
+ "output": "Q4_0",
79
+ "attn_gate": "Q4_0",
80
+ "ssm_out": "Q4_0",
81
+ "attn_q": "Q4_0",
82
+ "attn_k": "Q4_0",
83
+ "attn_v": "Q4_0",
84
+ # Q1_0: the one tensor type that tolerates it well
85
+ "attn_output": "Q1_0",
86
+ # Q2_K: the remaining compute-heavy tensors
87
+ "attn_qkv": "Q2_K",
88
+ "ffn_up": "Q2_K",
89
+ "ffn_gate": "Q2_K",
90
+ "ffn_down": "Q2_K",
91
+ "ssm_alpha": "Q2_K",
92
+ "ssm_beta": "Q2_K",
93
+ "nextn.eh_proj": "Q2_K",
94
+ }
95
+
96
+
97
  def _ts() -> str:
98
  return dt.datetime.now().strftime("%H:%M:%S.%f")[:-3]
99
 
 
129
  self._init_vars()
130
  self._apply_theme()
131
  self._build_layout()
132
+ if self.quant_format_var.get() == "custom":
133
+ self._on_format_changed()
134
  self._auto_populate_defaults()
135
  self._update_cli_preview()
136
  self.root.after(80, self._poll_queue)
 
164
  self.q4_fallback_var = tk.BooleanVar(value=True)
165
  self.embd_q4_var = tk.BooleanVar(value=True)
166
  self.promote_attn_q4_var = tk.BooleanVar(value=False)
167
+ self.quant_format_var = tk.StringVar(value="custom")
168
  self.plan_filter_var = tk.StringVar(value="ALL")
169
+ self.custom_type_vars: dict[str, tk.StringVar] = {}
170
 
171
  self.dc_lambda_var = tk.DoubleVar(value=1.0)
172
  self.vw_lambda_var = tk.DoubleVar(value=1.0)
 
342
  command=self._on_format_changed,
343
  ).pack(side=tk.LEFT, padx=3)
344
 
345
+ custom_row = ttk.Frame(opt_frame)
346
+ custom_row.pack(fill=tk.X, pady=(0, 4))
347
+ ttk.Radiobutton(
348
+ custom_row,
349
+ text="Custom (per tensor type)",
350
+ variable=self.quant_format_var,
351
+ value="custom",
352
+ command=self._on_format_changed,
353
+ ).pack(side=tk.LEFT, padx=4)
354
+ ttk.Label(
355
+ custom_row,
356
+ text="Override the quant type per tensor category (Auto = mixed plan).",
357
+ ).pack(side=tk.LEFT, padx=6)
358
+
359
+ self.custom_frame = ttk.LabelFrame(opt_frame, text="Custom Tensor-Type Targets", padding=6)
360
+ self.custom_body = ttk.Frame(self.custom_frame)
361
+ self.custom_body.pack(fill=tk.X)
362
+ self.custom_hint_var = tk.StringVar(value="Load a source GGUF to list tensor types.")
363
+ ttk.Label(
364
+ self.custom_frame, textvariable=self.custom_hint_var, style="TeleKey.TLabel"
365
+ ).pack(anchor=tk.W, pady=(4, 0))
366
+
367
  opt_row = ttk.Frame(opt_frame)
368
  opt_row.pack(fill=tk.X, pady=(0, 4))
369
+ self._custom_anchor = opt_row
370
  ttk.Label(opt_row, text="Global Optimizer:").pack(side=tk.LEFT, padx=(0, 8))
371
  ttk.Radiobutton(
372
  opt_row, text="HPC (Sieve + 36-State Viterbi)", variable=self.optimizer_var, value="hpc"
 
621
  return "-Q1_0.gguf"
622
  if fmt == "mixed_q1":
623
  return "-Q1_0-Q4_0.gguf"
624
+ if fmt == "custom":
625
+ return "-Custom.gguf"
626
  if fmt == "q4_0":
627
  return "-Q4_0.gguf"
628
  return "-Q2K.gguf"
 
632
  gguf_p = self.gguf_var.get().strip()
633
  if gguf_p and (
634
  not cur_out
635
+ or any(
636
+ cur_out.endswith(sfx)
637
+ for sfx in ("-Q2K.gguf", "-Q1_0.gguf", "-Q1_0-Q4_0.gguf", "-Custom.gguf", "-Q4_0.gguf")
638
+ )
639
  ):
640
  p = Path(gguf_p)
641
  self.output_var.set(str(p.with_name(f"{p.stem}{self._default_out_suffix()}")))
642
+ if self.quant_format_var.get() == "custom":
643
+ self.custom_frame.pack(fill=tk.X, pady=(0, 4), before=self._custom_anchor)
644
+ self._populate_custom_tensor_rows()
645
+ else:
646
+ self.custom_frame.pack_forget()
647
+ self._populate_tensor_tree()
648
+
649
+ def _custom_quant_map(self) -> dict[str, str]:
650
+ return {
651
+ key: var.get()
652
+ for key, var in self.custom_type_vars.items()
653
+ if var.get() not in ("", "Auto")
654
+ }
655
+
656
+ def _custom_map_for_plan(self) -> dict[str, str] | None:
657
+ if self.quant_format_var.get() != "custom":
658
+ return None
659
+ return self._custom_quant_map() or None
660
+
661
+ def _populate_custom_tensor_rows(self) -> None:
662
+ if not hasattr(self, "custom_body"):
663
+ return
664
+ for child in self.custom_body.winfo_children():
665
+ child.destroy()
666
+
667
+ if self._reader is None:
668
+ self.custom_hint_var.set("Load a source GGUF to list tensor types.")
669
+ self.custom_type_vars = {}
670
+ return
671
+
672
+ groups: dict[str, list] = {}
673
+ for ti in self._reader.tensors:
674
+ groups.setdefault(tensor_type_key(ti.name), []).append(ti)
675
+
676
+ previous = {key: var.get() for key, var in self.custom_type_vars.items()}
677
+ self.custom_type_vars = {}
678
+ rows = 0
679
+ for key in sorted(groups):
680
+ tensors = groups[key]
681
+ options = ["Auto", "Copy"]
682
+ if any(is_q1_0_eligible(t.name, t.dims) for t in tensors):
683
+ options.append("Q1_0")
684
+ if any(is_q2k_eligible(t.name, t.dims) for t in tensors):
685
+ options.append("Q2_K")
686
+ if any(
687
+ is_q4_0_eligible(t.name, t.dims, include_embd=True, allow_q2k_tensors=True)
688
+ for t in tensors
689
+ ):
690
+ options.append("Q4_0")
691
+ if len(options) == 2:
692
+ continue
693
+ var = tk.StringVar(
694
+ value=previous.get(key, DEFAULT_CUSTOM_RECIPE.get(key, "Auto"))
695
+ )
696
+ if var.get() not in options:
697
+ var.set("Auto")
698
+ var.trace_add(
699
+ "write",
700
+ lambda *_a: self._on_custom_type_changed(),
701
+ )
702
+ self.custom_type_vars[key] = var
703
+ r, c = divmod(rows, 2)
704
+ ttk.Label(self.custom_body, text=key, width=18, anchor=tk.W).grid(
705
+ row=r, column=c * 2, sticky=tk.W, padx=(0, 4), pady=1
706
+ )
707
+ ttk.Combobox(
708
+ self.custom_body,
709
+ textvariable=var,
710
+ values=options,
711
+ state="readonly",
712
+ width=8,
713
+ ).grid(row=r, column=c * 2 + 1, sticky=tk.W, padx=(0, 12), pady=1)
714
+ rows += 1
715
+
716
+ self.custom_hint_var.set(
717
+ "Quantizable tensor types only; norms/1D tensors and other non-eligible "
718
+ "weights are copied unchanged."
719
+ )
720
+ self._update_cli_preview()
721
+
722
+ def _on_custom_type_changed(self) -> None:
723
  self._populate_tensor_tree()
724
+ self._update_cli_preview()
725
 
726
  def _browse_gguf(self) -> None:
727
  path = filedialog.askopenfilename(
 
778
  dc_decay=float(self.dc_decay_var.get()),
779
  sse_budget=float(self.sse_budget_var.get()),
780
  quant_format=self.quant_format_var.get(),
781
+ custom_quant_map=self._custom_map_for_plan() or {},
782
  enable_q4_fallback=bool(self.q4_fallback_var.get()) and self.quant_format_var.get() != "q2_k",
783
  quantize_embd_q4=bool(self.embd_q4_var.get()),
784
  promote_attn_q4=bool(self.promote_attn_q4_var.get()),
 
807
  if self.limit_var.get() > 0:
808
  cmd += ["--limit", str(self.limit_var.get())]
809
  cmd += ["--format", self.quant_format_var.get()]
810
+ if self.quant_format_var.get() == "custom":
811
+ custom = self._custom_quant_map()
812
+ for key in sorted(custom):
813
+ cmd += ["--tensor-type", f"{key}={custom[key]}"]
814
  cmd += ["--device", self.device_var.get()]
815
  cmd += ["--workers", str(self.workers_var.get())]
816
  cmd += ["--cand-d", str(self.cand_d_var.get()), "--cand-m", str(self.cand_m_var.get())]
 
856
  return
857
  try:
858
  self._reader = GGUFReader(gguf_path)
859
+ if self.quant_format_var.get() == "custom":
860
+ self._populate_custom_tensor_rows()
861
  self._populate_tensor_tree()
862
  except Exception as exc:
863
  self._reader = None
 
880
  promote_attn_q4=bool(self.promote_attn_q4_var.get()),
881
  quant_format=self.quant_format_var.get(),
882
  source_type=ti.type,
883
+ custom_quant_map=self._custom_map_for_plan(),
884
  )
885
  if tgt == "Q2_K":
886
  n_q2 += 1
 
943
  promote_attn_q4=bool(self.promote_attn_q4_var.get()),
944
  quant_format=self.quant_format_var.get(),
945
  source_type=ti.type,
946
+ custom_quant_map=self._custom_map_for_plan(),
947
  )
948
  is not None
949
  and self.tree.exists(ti.name)
 
1035
  raw = lookup_imatrix(imat, tname)
1036
  if raw is not None:
1037
  imp = expand_importance(raw, x.size, row)
1038
+ tgt = target_quant_type(
1039
+ tname,
1040
+ ti.dims,
1041
+ enable_q4_fallback=bool(getattr(cfg, "enable_q4_fallback", True)),
1042
+ quantize_embd_q4=bool(getattr(cfg, "quantize_embd_q4", True)),
1043
+ promote_attn_q4=bool(getattr(cfg, "promote_attn_q4", False)),
1044
+ quant_format=str(getattr(cfg, "quant_format", "mixed")),
1045
+ source_type=ti.type,
1046
+ custom_quant_map=getattr(cfg, "custom_quant_map", None) or None,
1047
+ )
1048
+ if tgt == "Q1_0":
1049
  raw_q1, nb_q1, rmse_q1 = quantize_tensor_q1_0(x, importance=imp, cfg=cfg)
1050
  np.savez_compressed(
1051
  out_path,
 
1057
  ("done", f"Saved Q1_0 {out_path} (RMSE={rmse_q1:.6e}, {time.time() - t0:.1f}s)")
1058
  )
1059
  return
1060
+ if tgt == "Q4_0":
1061
  raw_q4, nb_q4, rmse_q4 = quantize_tensor_q4_0(x, importance=imp, cfg=cfg)
1062
  np.savez_compressed(
1063
  out_path,
 
1069
  ("done", f"Saved Q4_0 {out_path} (RMSE={rmse_q4:.6e}, {time.time() - t0:.1f}s)")
1070
  )
1071
  return
1072
+ if tgt != "Q2_K":
1073
+ raise ValueError(f"{tname}: target {tgt!r} is not quantizable to .npz")
1074
  res = quantizer.quantize(
1075
  x,
1076
  importance=imp,