CompressedGemma commited on
Commit
12a5d5a
·
verified ·
1 Parent(s): 88d5ea8

Upload 5 files

Browse files
Files changed (3) hide show
  1. __main__.py +3 -0
  2. gguf.py +87 -0
  3. gui.py +59 -7
__main__.py CHANGED
@@ -22,6 +22,7 @@ from .config import HPCConfig
22
  from .factored import factor_only_solve
23
  from .gguf import (
24
  GGUFReader,
 
25
  expand_importance,
26
  is_q2k_eligible,
27
  lookup_imatrix,
@@ -126,6 +127,8 @@ def _run_gguf(args, cfg: HPCConfig) -> None:
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(
131
  f" {tag:4s} {ti.name:48s} {ti.type_name:6s} "
 
22
  from .factored import factor_only_solve
23
  from .gguf import (
24
  GGUFReader,
25
+ SUPPORTED_READ_TYPES,
26
  expand_importance,
27
  is_q2k_eligible,
28
  lookup_imatrix,
 
127
  source_type=ti.type,
128
  custom_quant_map=cfg.custom_quant_map or None,
129
  )
130
+ if tgt is not None and ti.type not in SUPPORTED_READ_TYPES:
131
+ tgt = None
132
  tag = tgt if tgt else "COPY"
133
  print(
134
  f" {tag:4s} {ti.name:48s} {ti.type_name:6s} "
gguf.py CHANGED
@@ -51,6 +51,19 @@ TYPE_NAME = {
51
  GGML_TYPE_Q2_K: "Q2_K",
52
  GGML_TYPE_BF16: "BF16",
53
  GGML_TYPE_Q1_0: "Q1_0",
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  }
55
 
56
  BLOCK_SIZE = {
@@ -64,6 +77,11 @@ BLOCK_SIZE = {
64
  GGML_TYPE_Q8_0: 32,
65
  GGML_TYPE_Q2_K: QK_K,
66
  GGML_TYPE_Q1_0: QK1_0,
 
 
 
 
 
67
  }
68
  BLOCK_BYTES = {
69
  GGML_TYPE_F32: 4,
@@ -76,6 +94,11 @@ BLOCK_BYTES = {
76
  GGML_TYPE_Q8_0: 34,
77
  GGML_TYPE_Q2_K: 84,
78
  GGML_TYPE_Q1_0: Q1_0_BLOCK_BYTES,
 
 
 
 
 
79
  }
80
  TYPE_BPW = {
81
  GGML_TYPE_F32: 32.0,
@@ -127,6 +150,7 @@ class TensorInfo:
127
  dims: tuple[int, ...]
128
  type: int
129
  offset: int
 
130
 
131
  @property
132
  def n_elements(self) -> int:
@@ -145,6 +169,8 @@ class TensorInfo:
145
 
146
  @property
147
  def n_bytes(self) -> int:
 
 
148
  if self.type not in BLOCK_SIZE:
149
  raise ValueError(f"unsupported GGUF type {self.type} ({self.type_name})")
150
  block = BLOCK_SIZE[self.type]
@@ -234,6 +260,18 @@ class GGUFReader:
234
  self.info_end = f.tell()
235
  self.alignment = int(self.metadata.get("general.alignment", DEFAULT_ALIGNMENT))
236
  self.data_start = _align(self.info_end, self.alignment)
 
 
 
 
 
 
 
 
 
 
 
 
237
  self._by_name = {ti.name: ti for ti in self.tensors}
238
 
239
  def info(self, name: str) -> TensorInfo:
@@ -1072,3 +1110,52 @@ def write_quantized_gguf(
1072
  "elements": float(total_elements),
1073
  "rmse": rmse,
1074
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  GGML_TYPE_Q2_K: "Q2_K",
52
  GGML_TYPE_BF16: "BF16",
53
  GGML_TYPE_Q1_0: "Q1_0",
54
+ 11: "Q3_K",
55
+ 12: "Q4_K",
56
+ 13: "Q5_K",
57
+ 14: "Q6_K",
58
+ 15: "Q8_K",
59
+ 16: "IQ2_XXS",
60
+ 17: "IQ2_XS",
61
+ 18: "IQ3_XXS",
62
+ 19: "IQ1_S",
63
+ 20: "IQ4_NL",
64
+ 21: "IQ3_S",
65
+ 22: "IQ2_S",
66
+ 23: "IQ4_XS",
67
  }
68
 
69
  BLOCK_SIZE = {
 
77
  GGML_TYPE_Q8_0: 32,
78
  GGML_TYPE_Q2_K: QK_K,
79
  GGML_TYPE_Q1_0: QK1_0,
80
+ 11: QK_K, # Q3_K
81
+ 12: QK_K, # Q4_K
82
+ 13: QK_K, # Q5_K
83
+ 14: QK_K, # Q6_K
84
+ 15: QK_K, # Q8_K
85
  }
86
  BLOCK_BYTES = {
87
  GGML_TYPE_F32: 4,
 
94
  GGML_TYPE_Q8_0: 34,
95
  GGML_TYPE_Q2_K: 84,
96
  GGML_TYPE_Q1_0: Q1_0_BLOCK_BYTES,
97
+ 11: 110, # Q3_K
98
+ 12: 144, # Q4_K
99
+ 13: 176, # Q5_K
100
+ 14: 210, # Q6_K
101
+ 15: 292, # Q8_K
102
  }
103
  TYPE_BPW = {
104
  GGML_TYPE_F32: 32.0,
 
150
  dims: tuple[int, ...]
151
  type: int
152
  offset: int
153
+ raw_size: int | None = None
154
 
155
  @property
156
  def n_elements(self) -> int:
 
169
 
170
  @property
171
  def n_bytes(self) -> int:
172
+ if self.raw_size is not None:
173
+ return self.raw_size
174
  if self.type not in BLOCK_SIZE:
175
  raise ValueError(f"unsupported GGUF type {self.type} ({self.type_name})")
176
  block = BLOCK_SIZE[self.type]
 
260
  self.info_end = f.tell()
261
  self.alignment = int(self.metadata.get("general.alignment", DEFAULT_ALIGNMENT))
262
  self.data_start = _align(self.info_end, self.alignment)
263
+ file_size = self.path.stat().st_size
264
+ for i, ti in enumerate(self.tensors):
265
+ if ti.type in BLOCK_SIZE:
266
+ continue
267
+ end = (
268
+ self.tensors[i + 1].offset
269
+ if i + 1 < len(self.tensors)
270
+ else file_size - self.data_start
271
+ )
272
+ if end < ti.offset:
273
+ raise ValueError(f"{self.path}: tensor '{ti.name}' has an invalid offset")
274
+ ti.raw_size = end - ti.offset
275
  self._by_name = {ti.name: ti for ti in self.tensors}
276
 
277
  def info(self, name: str) -> TensorInfo:
 
1110
  "elements": float(total_elements),
1111
  "rmse": rmse,
1112
  }
1113
+
1114
+
1115
+ def estimate_gguf_size(
1116
+ reader: GGUFReader,
1117
+ *,
1118
+ enable_q4_fallback: bool = True,
1119
+ quantize_embd_q4: bool = True,
1120
+ promote_attn_q4: bool = False,
1121
+ quant_format: str = "mixed",
1122
+ custom_quant_map: dict[str, str] | None = None,
1123
+ ) -> int:
1124
+ """Return the projected byte size of a full-model quantized GGUF."""
1125
+ plan: list[tuple[TensorInfo, str | None]] = []
1126
+ for ti in reader.tensors:
1127
+ tgt = target_quant_type(
1128
+ ti.name,
1129
+ ti.dims,
1130
+ enable_q4_fallback=enable_q4_fallback,
1131
+ quantize_embd_q4=quantize_embd_q4,
1132
+ promote_attn_q4=promote_attn_q4,
1133
+ quant_format=quant_format,
1134
+ source_type=ti.type,
1135
+ custom_quant_map=custom_quant_map,
1136
+ )
1137
+ if tgt is not None and ti.type not in SUPPORTED_READ_TYPES:
1138
+ tgt = None
1139
+ plan.append((ti, tgt))
1140
+
1141
+ header = 24
1142
+ for key, _vtype, raw in reader.kv_pairs:
1143
+ header += 8 + len(key.encode("utf-8")) + 4 + len(raw)
1144
+ for ti, _tgt in plan:
1145
+ header += 8 + len(ti.name.encode("utf-8")) + 4 + 8 * len(ti.dims) + 4 + 8
1146
+ data_start = _align(header, reader.alignment)
1147
+
1148
+ offset = 0
1149
+ final_end = data_start
1150
+ for ti, tgt in plan:
1151
+ if tgt == "Q2_K":
1152
+ out_size = (ti.n_elements // QK_K) * 84
1153
+ elif tgt == "Q4_0":
1154
+ out_size = (ti.n_elements // QK4_0) * Q4_0_BLOCK_BYTES
1155
+ elif tgt == "Q1_0":
1156
+ out_size = (ti.n_elements // QK1_0) * Q1_0_BLOCK_BYTES
1157
+ else:
1158
+ out_size = ti.n_bytes
1159
+ final_end = data_start + offset + out_size
1160
+ offset = _align(offset + out_size, reader.alignment)
1161
+ return final_end
gui.py CHANGED
@@ -62,6 +62,8 @@ from hpc_quantize_v2 import (
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,
@@ -174,6 +176,7 @@ class HPCQuantizeGUI:
174
  self.sse_budget_var = tk.DoubleVar(value=0.0005)
175
 
176
  self.cli_preview_var = tk.StringVar()
 
177
  self.status_var = tk.StringVar(value="Ready.")
178
  self.model_progress_var = tk.DoubleVar(value=0.0)
179
  self.tensor_progress_var = tk.DoubleVar(value=0.0)
@@ -363,6 +366,9 @@ class HPCQuantizeGUI:
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))
@@ -713,10 +719,20 @@ class HPCQuantizeGUI:
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:
@@ -832,6 +848,31 @@ class HPCQuantizeGUI:
832
  self.cli_preview_var.set(self.build_cli_command())
833
  except Exception:
834
  pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
835
 
836
  def _copy_cli(self) -> None:
837
  cmd = self.cli_preview_var.get()
@@ -872,7 +913,7 @@ class HPCQuantizeGUI:
872
  n_q2, n_q4, n_copy = 0, 0, 0
873
  n_q1 = 0
874
  for ti in self._reader.tensors:
875
- tgt = target_quant_type(
876
  ti.name,
877
  ti.dims,
878
  enable_q4_fallback=bool(self.q4_fallback_var.get()) and self.quant_format_var.get() != "q2_k",
@@ -882,6 +923,9 @@ class HPCQuantizeGUI:
882
  source_type=ti.type,
883
  custom_quant_map=self._custom_map_for_plan(),
884
  )
 
 
 
885
  if tgt == "Q2_K":
886
  n_q2 += 1
887
  elif tgt == "Q4_0":
@@ -905,11 +949,14 @@ class HPCQuantizeGUI:
905
  self._imatrix is not None
906
  and lookup_imatrix(self._imatrix, ti.name) is not None
907
  )
908
- state_str = (
909
- f"Pending ({tgt_label})"
910
- if tgt
911
- else (f"Keep {ti.type_name} (<= target)" if ti.type_name in ("Q1_0", "Q2_K", "Q4_0") else "Passthrough")
912
- )
 
 
 
913
  self.tree.insert(
914
  "",
915
  tk.END,
@@ -946,6 +993,7 @@ class HPCQuantizeGUI:
946
  custom_quant_map=self._custom_map_for_plan(),
947
  )
948
  is not None
 
949
  and self.tree.exists(ti.name)
950
  ]
951
  self.tree.selection_set(eligible_ids)
@@ -1029,6 +1077,10 @@ class HPCQuantizeGUI:
1029
  reader = GGUFReader(gguf_path)
1030
  tname = next(iter(selected))
1031
  ti = reader.info(tname)
 
 
 
 
1032
  x, row = reader.read_tensor(tname)
1033
  imp = None
1034
  if imat is not None:
 
62
  read_imatrix,
63
  )
64
  from hpc_quantize_v2.gguf import (
65
+ SUPPORTED_READ_TYPES,
66
+ estimate_gguf_size,
67
  is_q1_0_eligible,
68
  is_q2k_eligible,
69
  is_q4_0_eligible,
 
176
  self.sse_budget_var = tk.DoubleVar(value=0.0005)
177
 
178
  self.cli_preview_var = tk.StringVar()
179
+ self.custom_size_var = tk.StringVar(value="Projected GGUF size: load a source GGUF")
180
  self.status_var = tk.StringVar(value="Ready.")
181
  self.model_progress_var = tk.DoubleVar(value=0.0)
182
  self.tensor_progress_var = tk.DoubleVar(value=0.0)
 
366
  ttk.Label(
367
  self.custom_frame, textvariable=self.custom_hint_var, style="TeleKey.TLabel"
368
  ).pack(anchor=tk.W, pady=(4, 0))
369
+ ttk.Label(
370
+ self.custom_frame, textvariable=self.custom_size_var
371
+ ).pack(anchor=tk.W, pady=(2, 0))
372
 
373
  opt_row = ttk.Frame(opt_frame)
374
  opt_row.pack(fill=tk.X, pady=(0, 4))
 
719
  ).grid(row=r, column=c * 2 + 1, sticky=tk.W, padx=(0, 12), pady=1)
720
  rows += 1
721
 
722
+ hint = (
723
  "Quantizable tensor types only; norms/1D tensors and other non-eligible "
724
  "weights are copied unchanged."
725
  )
726
+ unsupported = sorted(
727
+ {ti.type_name for ti in self._reader.tensors if ti.type not in SUPPORTED_READ_TYPES}
728
+ )
729
+ if unsupported:
730
+ hint += (
731
+ " Copy-only source formats (cannot down-quantize): "
732
+ + ", ".join(unsupported)
733
+ + "."
734
+ )
735
+ self.custom_hint_var.set(hint)
736
  self._update_cli_preview()
737
 
738
  def _on_custom_type_changed(self) -> None:
 
848
  self.cli_preview_var.set(self.build_cli_command())
849
  except Exception:
850
  pass
851
+ self._update_projected_size()
852
+
853
+ def _update_projected_size(self) -> None:
854
+ if self.quant_format_var.get() != "custom":
855
+ self.custom_size_var.set("Projected GGUF size: switch to Custom mode")
856
+ return
857
+ if self._reader is None:
858
+ self.custom_size_var.set("Projected GGUF size: load a source GGUF")
859
+ return
860
+ try:
861
+ size = estimate_gguf_size(
862
+ self._reader,
863
+ enable_q4_fallback=bool(self.q4_fallback_var.get())
864
+ and self.quant_format_var.get() != "q2_k",
865
+ quantize_embd_q4=bool(self.embd_q4_var.get()),
866
+ promote_attn_q4=bool(self.promote_attn_q4_var.get()),
867
+ quant_format=self.quant_format_var.get(),
868
+ custom_quant_map=self._custom_map_for_plan(),
869
+ )
870
+ except Exception as exc:
871
+ self.custom_size_var.set(f"Projected GGUF size: unavailable ({exc})")
872
+ return
873
+ self.custom_size_var.set(
874
+ f"Projected GGUF size: {size / 1024**3:.2f} GiB ({size / 1e9:.2f} GB)"
875
+ )
876
 
877
  def _copy_cli(self) -> None:
878
  cmd = self.cli_preview_var.get()
 
913
  n_q2, n_q4, n_copy = 0, 0, 0
914
  n_q1 = 0
915
  for ti in self._reader.tensors:
916
+ requested_tgt = target_quant_type(
917
  ti.name,
918
  ti.dims,
919
  enable_q4_fallback=bool(self.q4_fallback_var.get()) and self.quant_format_var.get() != "q2_k",
 
923
  source_type=ti.type,
924
  custom_quant_map=self._custom_map_for_plan(),
925
  )
926
+ tgt = requested_tgt
927
+ if tgt is not None and ti.type not in SUPPORTED_READ_TYPES:
928
+ tgt = None
929
  if tgt == "Q2_K":
930
  n_q2 += 1
931
  elif tgt == "Q4_0":
 
949
  self._imatrix is not None
950
  and lookup_imatrix(self._imatrix, ti.name) is not None
951
  )
952
+ if tgt:
953
+ state_str = f"Pending ({tgt_label})"
954
+ elif requested_tgt:
955
+ state_str = f"Copy {ti.type_name} (cannot dequantize for {requested_tgt})"
956
+ elif ti.type_name in ("Q1_0", "Q2_K", "Q4_0"):
957
+ state_str = f"Keep {ti.type_name} (<= target)"
958
+ else:
959
+ state_str = "Passthrough"
960
  self.tree.insert(
961
  "",
962
  tk.END,
 
993
  custom_quant_map=self._custom_map_for_plan(),
994
  )
995
  is not None
996
+ and ti.type in SUPPORTED_READ_TYPES
997
  and self.tree.exists(ti.name)
998
  ]
999
  self.tree.selection_set(eligible_ids)
 
1077
  reader = GGUFReader(gguf_path)
1078
  tname = next(iter(selected))
1079
  ti = reader.info(tname)
1080
+ if ti.type not in SUPPORTED_READ_TYPES:
1081
+ raise ValueError(
1082
+ f"{tname}: cannot dequantize source type {ti.type_name} for .npz export"
1083
+ )
1084
  x, row = reader.read_tensor(tname)
1085
  imp = None
1086
  if imat is not None: