Revert to keep stock llama compatibility
Browse files- __main__.py +0 -34
- config.py +0 -19
- gguf.py +8 -133
- gui.py +15 -96
- pipeline.py +1 -77
- q3_k.py +2 -41
- q4_0.py +0 -14
__main__.py
CHANGED
|
@@ -53,14 +53,6 @@ def _config_from_args(args) -> HPCConfig:
|
|
| 53 |
cfg.therm_lambda_tilt = float(args.thermal_tilt)
|
| 54 |
if args.pin_dc:
|
| 55 |
cfg.pin_dc = True
|
| 56 |
-
if getattr(args, "segment", False):
|
| 57 |
-
cfg.segment = True
|
| 58 |
-
if getattr(args, "segment_k", None) is not None:
|
| 59 |
-
cfg.segment_k = int(args.segment_k)
|
| 60 |
-
if getattr(args, "segment_iters", None) is not None:
|
| 61 |
-
cfg.segment_iters = int(args.segment_iters)
|
| 62 |
-
if getattr(args, "segment_table", None) is not None:
|
| 63 |
-
cfg.segment_table_size = int(args.segment_table)
|
| 64 |
if args.no_q4_fallback:
|
| 65 |
cfg.enable_q4_fallback = False
|
| 66 |
if args.keep_embd:
|
|
@@ -312,32 +304,6 @@ def main() -> None:
|
|
| 312 |
help="zero-DC pin (Q2_K free lunch): re-solve (d, m) on the exact dc=0 line "
|
| 313 |
"after assembly/thermal; strictly lowers SSE while driving row-DC residual to ~0",
|
| 314 |
)
|
| 315 |
-
parser.add_argument(
|
| 316 |
-
"--segment",
|
| 317 |
-
action="store_true",
|
| 318 |
-
help="band-major superblock segmentation for Q2_K / Q3_K (emits HPCQ.SEG.V1 label channels)",
|
| 319 |
-
)
|
| 320 |
-
parser.add_argument(
|
| 321 |
-
"--segment-k",
|
| 322 |
-
type=int,
|
| 323 |
-
default=None,
|
| 324 |
-
metavar="K",
|
| 325 |
-
help="band count k for superblock segmentation (default 16)",
|
| 326 |
-
)
|
| 327 |
-
parser.add_argument(
|
| 328 |
-
"--segment-iters",
|
| 329 |
-
type=int,
|
| 330 |
-
default=None,
|
| 331 |
-
metavar="N",
|
| 332 |
-
help="proxy fixed-point rounds for superblock segmentation (default 4)",
|
| 333 |
-
)
|
| 334 |
-
parser.add_argument(
|
| 335 |
-
"--segment-table",
|
| 336 |
-
type=int,
|
| 337 |
-
default=None,
|
| 338 |
-
metavar="M",
|
| 339 |
-
help="generalized permutation lookup table size per tensor (default 256 = +0.031 bpw; 0 = full per-block)",
|
| 340 |
-
)
|
| 341 |
parser.add_argument(
|
| 342 |
"--format",
|
| 343 |
choices=("mixed", "mixed_q1", "custom", "q1_0", "q3_k", "q4_0", "q2_k"),
|
|
|
|
| 53 |
cfg.therm_lambda_tilt = float(args.thermal_tilt)
|
| 54 |
if args.pin_dc:
|
| 55 |
cfg.pin_dc = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
if args.no_q4_fallback:
|
| 57 |
cfg.enable_q4_fallback = False
|
| 58 |
if args.keep_embd:
|
|
|
|
| 304 |
help="zero-DC pin (Q2_K free lunch): re-solve (d, m) on the exact dc=0 line "
|
| 305 |
"after assembly/thermal; strictly lowers SSE while driving row-DC residual to ~0",
|
| 306 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 307 |
parser.add_argument(
|
| 308 |
"--format",
|
| 309 |
choices=("mixed", "mixed_q1", "custom", "q1_0", "q3_k", "q4_0", "q2_k"),
|
config.py
CHANGED
|
@@ -103,18 +103,6 @@ class HPCConfig:
|
|
| 103 |
# (the Q2_K closed-form pin never spends any). 0 disables the expense.
|
| 104 |
pin_budget: float = 0.05
|
| 105 |
|
| 106 |
-
# ---- self-describing segmentation (V2-only, opt-in) -----------------
|
| 107 |
-
# Per-superblock deterministic band clustering. Labels are a pure
|
| 108 |
-
# function of the block's own dequantized values, so the decoder
|
| 109 |
-
# recovers the slot->position permutation by recomputation -- no
|
| 110 |
-
# sidecar, GGUF layout untouched. Q2_K / Q3_K use segment_k bands
|
| 111 |
-
# over the 256-weight superblock; Q4_0's 32-wide unit block uses k=1
|
| 112 |
-
# (ascending value order).
|
| 113 |
-
segment: bool = False
|
| 114 |
-
segment_k: int = 16
|
| 115 |
-
segment_iters: int = 4
|
| 116 |
-
segment_table_size: int = 256
|
| 117 |
-
|
| 118 |
# ---- seed clamp -----------------------------------------------------
|
| 119 |
clamp_kurtosis_off: float = 6.0
|
| 120 |
clamp_kurtosis_soft: float = 20.0
|
|
@@ -172,13 +160,6 @@ class HPCConfig:
|
|
| 172 |
raise ValueError("therm_t_decay must lie in (0, 1)")
|
| 173 |
if self.therm_lambda_tilt < 1.0:
|
| 174 |
raise ValueError("therm_lambda_tilt must be >= 1.0 (1.0 = off)")
|
| 175 |
-
if self.segment:
|
| 176 |
-
if not (2 <= self.segment_k <= 256):
|
| 177 |
-
raise ValueError("segment_k must lie in [2, 256]")
|
| 178 |
-
if self.segment_iters < 1:
|
| 179 |
-
raise ValueError("segment_iters must be >= 1")
|
| 180 |
-
if self.segment_table_size < 0 or (0 < self.segment_table_size < 4) or self.segment_table_size > 65535:
|
| 181 |
-
raise ValueError("segment_table_size must be 0 (full per-block) or lie in [4, 65535]")
|
| 182 |
if self.device not in ("auto", "cuda", "cpu") and not self.device.startswith("cuda:"):
|
| 183 |
raise ValueError("device must be 'auto', 'cuda', 'cuda:N', or 'cpu'")
|
| 184 |
if self.quant_format not in ("mixed", "mixed_q1", "custom", "q1_0", "q3_k", "q4_0", "q2_k"):
|
|
|
|
| 103 |
# (the Q2_K closed-form pin never spends any). 0 disables the expense.
|
| 104 |
pin_budget: float = 0.05
|
| 105 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 106 |
# ---- seed clamp -----------------------------------------------------
|
| 107 |
clamp_kurtosis_off: float = 6.0
|
| 108 |
clamp_kurtosis_soft: float = 20.0
|
|
|
|
| 160 |
raise ValueError("therm_t_decay must lie in (0, 1)")
|
| 161 |
if self.therm_lambda_tilt < 1.0:
|
| 162 |
raise ValueError("therm_lambda_tilt must be >= 1.0 (1.0 = off)")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 163 |
if self.device not in ("auto", "cuda", "cpu") and not self.device.startswith("cuda:"):
|
| 164 |
raise ValueError("device must be 'auto', 'cuda', 'cuda:N', or 'cpu'")
|
| 165 |
if self.quant_format not in ("mixed", "mixed_q1", "custom", "q1_0", "q3_k", "q4_0", "q2_k"):
|
gguf.py
CHANGED
|
@@ -26,16 +26,8 @@ from .q2k import QK_K, blocks_to_bytes, dequantize_params_batch, unpack_codes
|
|
| 26 |
from .q3_k import Q3_K_BLOCK_BYTES, QK3_K, dequantize_q3_k_bytes, quantize_tensor_q3_k
|
| 27 |
from .q4_0 import Q4_0_BLOCK_BYTES, QK4_0, quantize_tensor_q4_0
|
| 28 |
from .q1_0 import QK1_0, Q1_0_BLOCK_BYTES, quantize_tensor_q1_0
|
| 29 |
-
from .segmentation import (
|
| 30 |
-
label_channel_bytes,
|
| 31 |
-
pack_label_channel,
|
| 32 |
-
recover_order,
|
| 33 |
-
scatter_to_original,
|
| 34 |
-
unpack_label_channel,
|
| 35 |
-
)
|
| 36 |
|
| 37 |
GGUF_MAGIC = 0x46554747
|
| 38 |
-
SEG_KV_PREFIX = "HPCQ.SEG.V1."
|
| 39 |
DEFAULT_ALIGNMENT = 32
|
| 40 |
|
| 41 |
GGML_TYPE_F32 = 0
|
|
@@ -282,15 +274,10 @@ class GGUFReader:
|
|
| 282 |
|
| 283 |
def read_tensor(self, name: str) -> tuple[np.ndarray, int]:
|
| 284 |
raw = self.read_tensor_raw(name)
|
| 285 |
-
|
| 286 |
-
return self._unsegment(x, name), self.info(name).row_width
|
| 287 |
|
| 288 |
def iter_tensor_row_chunks(self, name: str, max_elements: int = 8_388_608):
|
| 289 |
-
"""Stream a tensor in row-aligned float32 chunks to bound peak RAM.
|
| 290 |
-
|
| 291 |
-
Chunks are unsegmented: if the tensor carries an HPCQ label channel,
|
| 292 |
-
each yielded chunk is scattered back to original order.
|
| 293 |
-
"""
|
| 294 |
ti = self.info(name)
|
| 295 |
row = ti.row_width
|
| 296 |
blk = BLOCK_SIZE[ti.type]
|
|
@@ -298,10 +285,6 @@ class GGUFReader:
|
|
| 298 |
x, r = self.read_tensor(name)
|
| 299 |
yield x, r, 0, ti.n_elements // max(r, 1)
|
| 300 |
return
|
| 301 |
-
seg_2d = None
|
| 302 |
-
seg = self.seg_labels(name)
|
| 303 |
-
if seg is not None:
|
| 304 |
-
seg_2d = seg[0]
|
| 305 |
n_rows = ti.n_elements // row
|
| 306 |
rows_per_chunk = max(1, max_elements // row)
|
| 307 |
bytes_per_row = (row // blk) * BLOCK_BYTES[ti.type]
|
|
@@ -314,69 +297,8 @@ class GGUFReader:
|
|
| 314 |
raw = f.read(chunk_bytes)
|
| 315 |
if len(raw) != chunk_bytes:
|
| 316 |
raise ValueError(f"{name}: truncated tensor data")
|
| 317 |
-
|
| 318 |
-
|
| 319 |
-
b0 = r0 * (row // blk)
|
| 320 |
-
b1 = b0 + (r1 - r0) * (row // blk)
|
| 321 |
-
sub = _scatter_rows(sub, seg_2d[b0:b1])
|
| 322 |
-
yield sub, row, r0, r1
|
| 323 |
-
|
| 324 |
-
def _seg_content(self, name: str) -> bytes | None:
|
| 325 |
-
"""Raw packed label channel bytes for ``name`` (undecoded KV value)."""
|
| 326 |
-
for key, vtype, raw in self.kv_pairs:
|
| 327 |
-
if key == SEG_KV_PREFIX + name:
|
| 328 |
-
if vtype == 8:
|
| 329 |
-
# legacy: string value, u64 length prefix then raw bytes
|
| 330 |
-
if len(raw) < 8:
|
| 331 |
-
raise ValueError(f"{name}: corrupt label channel KV")
|
| 332 |
-
return raw[8:]
|
| 333 |
-
if vtype == 9:
|
| 334 |
-
# uint8 array: u32 element type + u64 count + data
|
| 335 |
-
if len(raw) < 12:
|
| 336 |
-
raise ValueError(f"{name}: corrupt label channel KV")
|
| 337 |
-
if struct.unpack("<I", raw[:4])[0] != 0:
|
| 338 |
-
raise ValueError(f"{name}: label channel array is not uint8")
|
| 339 |
-
n = struct.unpack("<Q", raw[4:12])[0]
|
| 340 |
-
if len(raw) < 12 + n:
|
| 341 |
-
raise ValueError(f"{name}: truncated label channel array")
|
| 342 |
-
return raw[12 : 12 + n]
|
| 343 |
-
raise ValueError(f"{name}: label channel KV has bad type {vtype}")
|
| 344 |
-
return None
|
| 345 |
-
return None
|
| 346 |
-
|
| 347 |
-
def seg_labels(self, name: str) -> tuple[np.ndarray, int] | None:
|
| 348 |
-
"""Decode a tensor's label channel (labels per ORIGINAL position).
|
| 349 |
-
|
| 350 |
-
Returns ``(labels_2d, k)`` where ``labels_2d`` is shaped
|
| 351 |
-
``(n_blocks, block_qk)``, or ``None`` when no channel is present.
|
| 352 |
-
"""
|
| 353 |
-
content = self._seg_content(name)
|
| 354 |
-
if content is None:
|
| 355 |
-
return None
|
| 356 |
-
ti = self.info(name)
|
| 357 |
-
if ti.type not in (GGML_TYPE_Q2_K, GGML_TYPE_Q3_K):
|
| 358 |
-
raise ValueError(f"{name}: label channel on non-segmentable type {ti.type_name}")
|
| 359 |
-
blk = QK_K if ti.type == GGML_TYPE_Q2_K else QK3_K
|
| 360 |
-
k, labels = unpack_label_channel(content)
|
| 361 |
-
if labels.size != ti.n_elements:
|
| 362 |
-
raise ValueError(
|
| 363 |
-
f"{name}: label channel size {labels.size} != tensor elements {ti.n_elements}"
|
| 364 |
-
)
|
| 365 |
-
return labels.reshape(ti.n_elements // blk, blk), k
|
| 366 |
-
|
| 367 |
-
def _unsegment(self, x: np.ndarray, name: str) -> np.ndarray:
|
| 368 |
-
seg = self.seg_labels(name)
|
| 369 |
-
if seg is None:
|
| 370 |
-
return x
|
| 371 |
-
return _scatter_rows(x, seg[0])
|
| 372 |
-
|
| 373 |
-
|
| 374 |
-
def _scatter_rows(x: np.ndarray, labels_2d: np.ndarray) -> np.ndarray:
|
| 375 |
-
"""Scatter slot-order values back to original positions via the channel."""
|
| 376 |
-
out = scatter_to_original(
|
| 377 |
-
x.reshape(labels_2d.shape).astype(np.float32), recover_order(labels_2d)
|
| 378 |
-
)
|
| 379 |
-
return out.reshape(-1)
|
| 380 |
|
| 381 |
|
| 382 |
def _dequantize(raw: bytes, ti: TensorInfo) -> np.ndarray:
|
|
@@ -796,9 +718,6 @@ def write_quantized_gguf(
|
|
| 796 |
attn_q4 = bool(getattr(cfg, "promote_attn_q4", False))
|
| 797 |
q_format = str(getattr(cfg, "quant_format", "mixed"))
|
| 798 |
custom_map = getattr(cfg, "custom_quant_map", None) or None
|
| 799 |
-
seg_active = bool(getattr(cfg, "segment", False))
|
| 800 |
-
seg_k = max(2, int(getattr(cfg, "segment_k", 16)))
|
| 801 |
-
seg_table_size = int(getattr(cfg, "segment_table_size", 256))
|
| 802 |
|
| 803 |
plan: list[str | None] = []
|
| 804 |
quantized_count = 0
|
|
@@ -893,27 +812,11 @@ def write_quantized_gguf(
|
|
| 893 |
ftype_code = 11 if has_q3k else (10 if has_q2k else (40 if has_q1_0 else 2))
|
| 894 |
kv_pairs = []
|
| 895 |
for key, vtype, raw in reader.kv_pairs:
|
| 896 |
-
if key.startswith(SEG_KV_PREFIX):
|
| 897 |
-
continue
|
| 898 |
if quantized_count and key == "general.file_type" and vtype == 4:
|
| 899 |
raw = struct.pack("<I", ftype_code)
|
| 900 |
elif quantized_count and key == "general.quantization_version" and vtype == 4:
|
| 901 |
raw = struct.pack("<I", 2)
|
| 902 |
kv_pairs.append((key, vtype, raw))
|
| 903 |
-
# Reserve label channels for every planned segmented tensor so the KV
|
| 904 |
-
# section layout is final before data streaming; contents are patched
|
| 905 |
-
# in place (same length) after each tensor is quantized.
|
| 906 |
-
seg_reserve: dict[str, int] = {}
|
| 907 |
-
if seg_active:
|
| 908 |
-
for ti, fmt in zip(reader.tensors, plan):
|
| 909 |
-
if fmt in ("Q2_K", "Q3_K"):
|
| 910 |
-
key = SEG_KV_PREFIX + ti.name
|
| 911 |
-
content_len = label_channel_bytes(ti.n_elements, seg_k, seg_table_size)
|
| 912 |
-
seg_reserve[key] = content_len
|
| 913 |
-
# GGUF uint8 array: u32 element type + u64 count + zeros
|
| 914 |
-
kv_pairs.append(
|
| 915 |
-
(key, 9, struct.pack("<I", 0) + struct.pack("<Q", content_len) + bytes(content_len))
|
| 916 |
-
)
|
| 917 |
|
| 918 |
output_path = Path(output_path)
|
| 919 |
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
@@ -928,22 +831,10 @@ def write_quantized_gguf(
|
|
| 928 |
model_t0 = time.time()
|
| 929 |
with output_path.open("wb") as fout:
|
| 930 |
fout.write(struct.pack("<IIQQ", GGUF_MAGIC, reader.version, len(out_infos), len(kv_pairs)))
|
| 931 |
-
seg_patch_offsets: dict[str, int] = {}
|
| 932 |
for key, vtype, raw in kv_pairs:
|
| 933 |
_write_string(fout, key)
|
| 934 |
fout.write(struct.pack("<I", vtype))
|
| 935 |
-
if key in seg_reserve:
|
| 936 |
-
seg_patch_offsets[key] = fout.tell()
|
| 937 |
fout.write(raw)
|
| 938 |
-
|
| 939 |
-
def _patch_seg_kv(fout, key: str, labels: np.ndarray) -> None:
|
| 940 |
-
packed = pack_label_channel(labels, seg_k, seg_table_size)
|
| 941 |
-
if len(packed) != seg_reserve.get(key, -1):
|
| 942 |
-
raise RuntimeError(f"{key}: label channel size {len(packed)} != reserved")
|
| 943 |
-
pos = fout.tell()
|
| 944 |
-
fout.seek(seg_patch_offsets[key] + 12) # skip u32 array type + u64 count
|
| 945 |
-
fout.write(packed)
|
| 946 |
-
fout.seek(pos)
|
| 947 |
for ti, out_type, out_size, offset in out_infos:
|
| 948 |
_write_string(fout, ti.name)
|
| 949 |
fout.write(struct.pack("<I", len(ti.dims)))
|
|
@@ -1027,8 +918,6 @@ def write_quantized_gguf(
|
|
| 1027 |
if len(payload) != out_size:
|
| 1028 |
raise RuntimeError(f"{ti.name}: Q2_K payload size mismatch")
|
| 1029 |
fout.write(payload)
|
| 1030 |
-
if seg_active and res.segment_labels is not None:
|
| 1031 |
-
_patch_seg_kv(fout, SEG_KV_PREFIX + ti.name, res.segment_labels)
|
| 1032 |
total_rmse += res.stats.rmse * res.stats.rmse * x.size
|
| 1033 |
total_elements += x.size
|
| 1034 |
total_quantized += 1
|
|
@@ -1056,26 +945,14 @@ def write_quantized_gguf(
|
|
| 1056 |
sse_q3 = 0.0
|
| 1057 |
done_q3_blks = 0
|
| 1058 |
t_q3_start = time.time()
|
| 1059 |
-
q3_labels: list[np.ndarray] = []
|
| 1060 |
|
| 1061 |
-
|
| 1062 |
-
for x_chunk, row, _r0, _r1 in reader.iter_tensor_row_chunks(ti.name, max_elements=q3_max_elems):
|
| 1063 |
if stop_event is not None and stop_event.is_set():
|
| 1064 |
raise InterruptedError("Quantization cancelled by user")
|
| 1065 |
imp_chunk = expand_importance(raw_imp, x_chunk.size, row) if has_imat else None
|
| 1066 |
-
|
| 1067 |
-
|
| 1068 |
-
|
| 1069 |
-
importance=imp_chunk,
|
| 1070 |
-
cfg=cfg,
|
| 1071 |
-
chunk_blocks=8192,
|
| 1072 |
-
return_labels=True,
|
| 1073 |
-
)
|
| 1074 |
-
q3_labels.append(np.asarray(chunk_labels, dtype=np.int64).ravel())
|
| 1075 |
-
else:
|
| 1076 |
-
q3_bytes, nb_chunk, chunk_rmse = quantize_tensor_q3_k(
|
| 1077 |
-
x_chunk, importance=imp_chunk, cfg=cfg, chunk_blocks=8192
|
| 1078 |
-
)
|
| 1079 |
fout.write(q3_bytes)
|
| 1080 |
written_bytes += len(q3_bytes)
|
| 1081 |
sse_q3 += (chunk_rmse * chunk_rmse) * x_chunk.size
|
|
@@ -1111,8 +988,6 @@ def write_quantized_gguf(
|
|
| 1111 |
|
| 1112 |
if written_bytes != out_size:
|
| 1113 |
raise RuntimeError(f"{ti.name}: Q3_K payload size mismatch")
|
| 1114 |
-
if seg_active:
|
| 1115 |
-
_patch_seg_kv(fout, SEG_KV_PREFIX + ti.name, np.concatenate(q3_labels))
|
| 1116 |
completed_planned_blocks += eff_tb
|
| 1117 |
q3_rmse = float(np.sqrt(sse_q3 / ti.n_elements))
|
| 1118 |
total_rmse += sse_q3
|
|
|
|
| 26 |
from .q3_k import Q3_K_BLOCK_BYTES, QK3_K, dequantize_q3_k_bytes, quantize_tensor_q3_k
|
| 27 |
from .q4_0 import Q4_0_BLOCK_BYTES, QK4_0, quantize_tensor_q4_0
|
| 28 |
from .q1_0 import QK1_0, Q1_0_BLOCK_BYTES, quantize_tensor_q1_0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
|
| 30 |
GGUF_MAGIC = 0x46554747
|
|
|
|
| 31 |
DEFAULT_ALIGNMENT = 32
|
| 32 |
|
| 33 |
GGML_TYPE_F32 = 0
|
|
|
|
| 274 |
|
| 275 |
def read_tensor(self, name: str) -> tuple[np.ndarray, int]:
|
| 276 |
raw = self.read_tensor_raw(name)
|
| 277 |
+
return _dequantize(raw, self.info(name)), self.info(name).row_width
|
|
|
|
| 278 |
|
| 279 |
def iter_tensor_row_chunks(self, name: str, max_elements: int = 8_388_608):
|
| 280 |
+
"""Stream a tensor in row-aligned float32 chunks to bound peak RAM."""
|
|
|
|
|
|
|
|
|
|
|
|
|
| 281 |
ti = self.info(name)
|
| 282 |
row = ti.row_width
|
| 283 |
blk = BLOCK_SIZE[ti.type]
|
|
|
|
| 285 |
x, r = self.read_tensor(name)
|
| 286 |
yield x, r, 0, ti.n_elements // max(r, 1)
|
| 287 |
return
|
|
|
|
|
|
|
|
|
|
|
|
|
| 288 |
n_rows = ti.n_elements // row
|
| 289 |
rows_per_chunk = max(1, max_elements // row)
|
| 290 |
bytes_per_row = (row // blk) * BLOCK_BYTES[ti.type]
|
|
|
|
| 297 |
raw = f.read(chunk_bytes)
|
| 298 |
if len(raw) != chunk_bytes:
|
| 299 |
raise ValueError(f"{name}: truncated tensor data")
|
| 300 |
+
sub_ti = TensorInfo(ti.name, (chunk_elems,), ti.type, 0)
|
| 301 |
+
yield _dequantize(raw, sub_ti), row, r0, r1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 302 |
|
| 303 |
|
| 304 |
def _dequantize(raw: bytes, ti: TensorInfo) -> np.ndarray:
|
|
|
|
| 718 |
attn_q4 = bool(getattr(cfg, "promote_attn_q4", False))
|
| 719 |
q_format = str(getattr(cfg, "quant_format", "mixed"))
|
| 720 |
custom_map = getattr(cfg, "custom_quant_map", None) or None
|
|
|
|
|
|
|
|
|
|
| 721 |
|
| 722 |
plan: list[str | None] = []
|
| 723 |
quantized_count = 0
|
|
|
|
| 812 |
ftype_code = 11 if has_q3k else (10 if has_q2k else (40 if has_q1_0 else 2))
|
| 813 |
kv_pairs = []
|
| 814 |
for key, vtype, raw in reader.kv_pairs:
|
|
|
|
|
|
|
| 815 |
if quantized_count and key == "general.file_type" and vtype == 4:
|
| 816 |
raw = struct.pack("<I", ftype_code)
|
| 817 |
elif quantized_count and key == "general.quantization_version" and vtype == 4:
|
| 818 |
raw = struct.pack("<I", 2)
|
| 819 |
kv_pairs.append((key, vtype, raw))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 820 |
|
| 821 |
output_path = Path(output_path)
|
| 822 |
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
| 831 |
model_t0 = time.time()
|
| 832 |
with output_path.open("wb") as fout:
|
| 833 |
fout.write(struct.pack("<IIQQ", GGUF_MAGIC, reader.version, len(out_infos), len(kv_pairs)))
|
|
|
|
| 834 |
for key, vtype, raw in kv_pairs:
|
| 835 |
_write_string(fout, key)
|
| 836 |
fout.write(struct.pack("<I", vtype))
|
|
|
|
|
|
|
| 837 |
fout.write(raw)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 838 |
for ti, out_type, out_size, offset in out_infos:
|
| 839 |
_write_string(fout, ti.name)
|
| 840 |
fout.write(struct.pack("<I", len(ti.dims)))
|
|
|
|
| 918 |
if len(payload) != out_size:
|
| 919 |
raise RuntimeError(f"{ti.name}: Q2_K payload size mismatch")
|
| 920 |
fout.write(payload)
|
|
|
|
|
|
|
| 921 |
total_rmse += res.stats.rmse * res.stats.rmse * x.size
|
| 922 |
total_elements += x.size
|
| 923 |
total_quantized += 1
|
|
|
|
| 945 |
sse_q3 = 0.0
|
| 946 |
done_q3_blks = 0
|
| 947 |
t_q3_start = time.time()
|
|
|
|
| 948 |
|
| 949 |
+
for x_chunk, row, _r0, _r1 in reader.iter_tensor_row_chunks(ti.name, max_elements=8_388_608):
|
|
|
|
| 950 |
if stop_event is not None and stop_event.is_set():
|
| 951 |
raise InterruptedError("Quantization cancelled by user")
|
| 952 |
imp_chunk = expand_importance(raw_imp, x_chunk.size, row) if has_imat else None
|
| 953 |
+
q3_bytes, nb_chunk, chunk_rmse = quantize_tensor_q3_k(
|
| 954 |
+
x_chunk, importance=imp_chunk, cfg=cfg, chunk_blocks=8192
|
| 955 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 956 |
fout.write(q3_bytes)
|
| 957 |
written_bytes += len(q3_bytes)
|
| 958 |
sse_q3 += (chunk_rmse * chunk_rmse) * x_chunk.size
|
|
|
|
| 988 |
|
| 989 |
if written_bytes != out_size:
|
| 990 |
raise RuntimeError(f"{ti.name}: Q3_K payload size mismatch")
|
|
|
|
|
|
|
| 991 |
completed_planned_blocks += eff_tb
|
| 992 |
q3_rmse = float(np.sqrt(sse_q3 / ti.n_elements))
|
| 993 |
total_rmse += sse_q3
|
gui.py
CHANGED
|
@@ -70,12 +70,10 @@ from hpc_quantize_v2 import (
|
|
| 70 |
read_imatrix,
|
| 71 |
)
|
| 72 |
from hpc_quantize_v2.gguf import (
|
| 73 |
-
SEG_KV_PREFIX,
|
| 74 |
is_q1_0_eligible,
|
| 75 |
is_q2k_eligible,
|
| 76 |
is_q3_k_eligible,
|
| 77 |
is_q4_0_eligible,
|
| 78 |
-
label_channel_bytes,
|
| 79 |
target_quant_type,
|
| 80 |
tensor_type_key,
|
| 81 |
write_quantized_gguf,
|
|
@@ -186,10 +184,6 @@ class HPCQuantizeGUI:
|
|
| 186 |
self.thermal_var = tk.IntVar(value=0)
|
| 187 |
self.thermal_tilt_var = tk.DoubleVar(value=1.0)
|
| 188 |
self.pin_dc_var = tk.BooleanVar(value=False)
|
| 189 |
-
self.segment_var = tk.BooleanVar(value=False)
|
| 190 |
-
self.segment_k_var = tk.IntVar(value=16)
|
| 191 |
-
self.segment_iters_var = tk.IntVar(value=4)
|
| 192 |
-
self.segment_table_var = tk.IntVar(value=256)
|
| 193 |
|
| 194 |
self.cli_preview_var = tk.StringVar()
|
| 195 |
self.status_var = tk.StringVar(value="Ready.")
|
|
@@ -223,16 +217,8 @@ class HPCQuantizeGUI:
|
|
| 223 |
self.promote_attn_q4_var,
|
| 224 |
self.quant_format_var,
|
| 225 |
self.thermal_var,
|
| 226 |
-
self.thermal_tilt_var,
|
| 227 |
-
self.pin_dc_var,
|
| 228 |
-
self.segment_var,
|
| 229 |
-
self.segment_k_var,
|
| 230 |
-
self.segment_iters_var,
|
| 231 |
-
self.segment_table_var,
|
| 232 |
):
|
| 233 |
v.trace_add("write", lambda *_: self._update_cli_preview())
|
| 234 |
-
for v in (self.segment_var, self.segment_k_var, self.segment_table_var):
|
| 235 |
-
v.trace_add("write", lambda *_: self._refresh_plan_view())
|
| 236 |
|
| 237 |
def _apply_theme(self) -> None:
|
| 238 |
style = ttk.Style(self.root)
|
|
@@ -497,30 +483,10 @@ class HPCQuantizeGUI:
|
|
| 497 |
text="Pin DC residual to 0 (Q2_K free lunch)",
|
| 498 |
variable=self.pin_dc_var,
|
| 499 |
).grid(row=3, column=0, columnspan=2, sticky=tk.W, padx=4, pady=1)
|
| 500 |
-
ttk.Checkbutton(
|
| 501 |
-
spec_f,
|
| 502 |
-
text="Band-Major Segmentation (Q2_K / Q3_K)",
|
| 503 |
-
variable=self.segment_var,
|
| 504 |
-
).grid(row=3, column=2, columnspan=2, sticky=tk.W, padx=4, pady=1)
|
| 505 |
-
ttk.Label(spec_f, text="Seg Bands (k):").grid(row=4, column=0, sticky=tk.W, padx=4, pady=2)
|
| 506 |
-
ttk.Spinbox(
|
| 507 |
-
spec_f, from_=2, to=16, increment=1, textvariable=self.segment_k_var, width=8
|
| 508 |
-
).grid(row=4, column=1, sticky=tk.EW, padx=4, pady=2)
|
| 509 |
-
ttk.Label(spec_f, text="Seg Iters:").grid(row=4, column=2, sticky=tk.W, padx=4, pady=2)
|
| 510 |
-
ttk.Spinbox(
|
| 511 |
-
spec_f, from_=1, to=12, increment=1, textvariable=self.segment_iters_var, width=8
|
| 512 |
-
).grid(row=4, column=3, sticky=tk.EW, padx=4, pady=2)
|
| 513 |
-
ttk.Label(spec_f, text="Seg Lookup Table (0=full):").grid(row=5, column=0, columnspan=2, sticky=tk.W, padx=4, pady=2)
|
| 514 |
-
ttk.Combobox(
|
| 515 |
-
spec_f,
|
| 516 |
-
textvariable=self.segment_table_var,
|
| 517 |
-
values=(0, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096),
|
| 518 |
-
width=8,
|
| 519 |
-
).grid(row=5, column=2, columnspan=2, sticky=tk.EW, padx=4, pady=2)
|
| 520 |
ttk.Label(
|
| 521 |
spec_f, text="(λ multiplier ≥1 during thermal anneal; ~1e2–1e3 ≈ zero-coherent-residual '0-error' anneal)",
|
| 522 |
foreground="#93c5fd",
|
| 523 |
-
).grid(row=
|
| 524 |
|
| 525 |
# Right: GGUF Tensor Browser
|
| 526 |
browser_frame = ttk.LabelFrame(right_pane, text="3. GGUF Tensor Inspector & Live Status", padding=8)
|
|
@@ -850,10 +816,6 @@ class HPCQuantizeGUI:
|
|
| 850 |
therm_passes=max(0, int(self.thermal_var.get())),
|
| 851 |
therm_lambda_tilt=max(1.0, float(self.thermal_tilt_var.get())),
|
| 852 |
pin_dc=bool(self.pin_dc_var.get()),
|
| 853 |
-
segment=bool(self.segment_var.get()),
|
| 854 |
-
segment_k=max(2, int(self.segment_k_var.get())),
|
| 855 |
-
segment_iters=max(1, int(self.segment_iters_var.get())),
|
| 856 |
-
segment_table_size=max(0, int(self.segment_table_var.get())),
|
| 857 |
quant_format=self.quant_format_var.get(),
|
| 858 |
custom_quant_map=self._custom_map_for_plan() or {},
|
| 859 |
enable_q4_fallback=bool(self.q4_fallback_var.get()) and self.quant_format_var.get() not in ("q2_k", "q3_k"),
|
|
@@ -907,14 +869,6 @@ class HPCQuantizeGUI:
|
|
| 907 |
cmd += ["--thermal-tilt", str(float(self.thermal_tilt_var.get()))]
|
| 908 |
if self.pin_dc_var.get():
|
| 909 |
cmd += ["--pin-dc"]
|
| 910 |
-
if self.segment_var.get():
|
| 911 |
-
cmd += ["--segment"]
|
| 912 |
-
if int(self.segment_k_var.get()) != 16:
|
| 913 |
-
cmd += ["--segment-k", str(int(self.segment_k_var.get()))]
|
| 914 |
-
if int(self.segment_iters_var.get()) != 4:
|
| 915 |
-
cmd += ["--segment-iters", str(int(self.segment_iters_var.get()))]
|
| 916 |
-
if int(self.segment_table_var.get()) != 256:
|
| 917 |
-
cmd += ["--segment-table", str(int(self.segment_table_var.get()))]
|
| 918 |
cmd.append("--verbose")
|
| 919 |
return " ".join(shlex.quote(part) for part in cmd)
|
| 920 |
|
|
@@ -978,43 +932,6 @@ class HPCQuantizeGUI:
|
|
| 978 |
self._refresh_plan_view()
|
| 979 |
self._update_cli_preview()
|
| 980 |
|
| 981 |
-
def _estimate_seg_bytes(self, ti, tgt: str | None) -> int:
|
| 982 |
-
if not bool(self.segment_var.get()) or tgt not in ("Q2_K", "Q3_K"):
|
| 983 |
-
return 0
|
| 984 |
-
try:
|
| 985 |
-
seg_k = max(2, int(self.segment_k_var.get()))
|
| 986 |
-
except Exception:
|
| 987 |
-
seg_k = 16
|
| 988 |
-
try:
|
| 989 |
-
seg_tbl = max(0, int(self.segment_table_var.get()))
|
| 990 |
-
except Exception:
|
| 991 |
-
seg_tbl = 256
|
| 992 |
-
content_len = label_channel_bytes(ti.n_elements, seg_k, seg_tbl)
|
| 993 |
-
key_len = len((SEG_KV_PREFIX + ti.name).encode("utf-8"))
|
| 994 |
-
return 8 + key_len + 4 + 12 + content_len
|
| 995 |
-
|
| 996 |
-
def _format_size_summary(self, planned_bytes: int, total_seg_bytes: int) -> str:
|
| 997 |
-
if planned_bytes >= 1024 ** 3:
|
| 998 |
-
planned_text = f"{planned_bytes / (1024 ** 3):.2f} GiB"
|
| 999 |
-
elif planned_bytes >= 1024 ** 2:
|
| 1000 |
-
planned_text = f"{planned_bytes / (1024 ** 2):.1f} MiB"
|
| 1001 |
-
else:
|
| 1002 |
-
planned_text = f"{planned_bytes / 1024:.1f} KiB"
|
| 1003 |
-
if total_seg_bytes > 0:
|
| 1004 |
-
try:
|
| 1005 |
-
seg_tbl = max(0, int(self.segment_table_var.get()))
|
| 1006 |
-
except Exception:
|
| 1007 |
-
seg_tbl = 256
|
| 1008 |
-
if total_seg_bytes >= 1024 ** 3:
|
| 1009 |
-
seg_txt = f"+{total_seg_bytes / (1024 ** 3):.2f} GiB"
|
| 1010 |
-
elif total_seg_bytes >= 1024 ** 2:
|
| 1011 |
-
seg_txt = f"+{total_seg_bytes / (1024 ** 2):.1f} MiB"
|
| 1012 |
-
else:
|
| 1013 |
-
seg_txt = f"+{total_seg_bytes / 1024:.1f} KiB"
|
| 1014 |
-
lut_lbl = f"LUT={seg_tbl}" if seg_tbl > 0 else "full"
|
| 1015 |
-
planned_text = f"{planned_text} [seg {seg_txt}, {lut_lbl}]"
|
| 1016 |
-
return planned_text
|
| 1017 |
-
|
| 1018 |
def _refresh_plan_view(self) -> None:
|
| 1019 |
if self._reader is None:
|
| 1020 |
return
|
|
@@ -1022,8 +939,7 @@ class HPCQuantizeGUI:
|
|
| 1022 |
scope_selected = self.mode_var.get() == "selected"
|
| 1023 |
n_q2, n_q3, n_q4, n_copy = 0, 0, 0, 0
|
| 1024 |
n_q1 = 0
|
| 1025 |
-
planned_bytes =
|
| 1026 |
-
total_seg_bytes = 0
|
| 1027 |
for ti in self._reader.tensors:
|
| 1028 |
tgt = self._plan_target(ti, chosen, scope_selected)
|
| 1029 |
if tgt == "Q2_K":
|
|
@@ -1047,9 +963,6 @@ class HPCQuantizeGUI:
|
|
| 1047 |
planned_bytes += (ti.n_elements // QK1_0) * Q1_0_BLOCK_BYTES
|
| 1048 |
else:
|
| 1049 |
planned_bytes += ti.n_bytes
|
| 1050 |
-
seg_b = self._estimate_seg_bytes(ti, tgt)
|
| 1051 |
-
planned_bytes += seg_b
|
| 1052 |
-
total_seg_bytes += seg_b
|
| 1053 |
|
| 1054 |
if not self.tree.exists(ti.name):
|
| 1055 |
continue
|
|
@@ -1067,7 +980,12 @@ class HPCQuantizeGUI:
|
|
| 1067 |
vals[6] = state_str
|
| 1068 |
self.tree.item(ti.name, tags=(tgt_label,), values=vals)
|
| 1069 |
|
| 1070 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1071 |
scope_text = "selected" if scope_selected else "all"
|
| 1072 |
self.status_var.set(
|
| 1073 |
f"Plan ({self.quant_format_var.get().upper()}, {scope_text}): {n_q1} Q1_0 | {n_q2} Q2_K | {n_q3} Q3_K | {n_q4} Q4_0 | {n_copy} Copy "
|
|
@@ -1084,8 +1002,7 @@ class HPCQuantizeGUI:
|
|
| 1084 |
plan_filt = self.plan_filter_var.get()
|
| 1085 |
n_q2, n_q3, n_q4, n_copy = 0, 0, 0, 0
|
| 1086 |
n_q1 = 0
|
| 1087 |
-
planned_bytes =
|
| 1088 |
-
total_seg_bytes = 0
|
| 1089 |
for ti in self._reader.tensors:
|
| 1090 |
tgt = self._plan_target(ti, chosen, scope_selected)
|
| 1091 |
if tgt == "Q2_K":
|
|
@@ -1109,9 +1026,6 @@ class HPCQuantizeGUI:
|
|
| 1109 |
planned_bytes += (ti.n_elements // QK1_0) * Q1_0_BLOCK_BYTES
|
| 1110 |
else:
|
| 1111 |
planned_bytes += ti.n_bytes
|
| 1112 |
-
seg_b = self._estimate_seg_bytes(ti, tgt)
|
| 1113 |
-
planned_bytes += seg_b
|
| 1114 |
-
total_seg_bytes += seg_b
|
| 1115 |
|
| 1116 |
tgt_label = tgt if tgt else "Copy"
|
| 1117 |
if plan_filt != "ALL" and tgt_label.upper() != plan_filt:
|
|
@@ -1153,7 +1067,12 @@ class HPCQuantizeGUI:
|
|
| 1153 |
keep_selected = [n for n in chosen if self.tree.exists(n)]
|
| 1154 |
if keep_selected:
|
| 1155 |
self.tree.selection_set(keep_selected)
|
| 1156 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1157 |
scope_text = "selected" if scope_selected else "all"
|
| 1158 |
self.status_var.set(
|
| 1159 |
f"Plan ({self.quant_format_var.get().upper()}, {scope_text}): {n_q1} Q1_0 | {n_q2} Q2_K | {n_q3} Q3_K | {n_q4} Q4_0 | {n_copy} Copy "
|
|
|
|
| 70 |
read_imatrix,
|
| 71 |
)
|
| 72 |
from hpc_quantize_v2.gguf import (
|
|
|
|
| 73 |
is_q1_0_eligible,
|
| 74 |
is_q2k_eligible,
|
| 75 |
is_q3_k_eligible,
|
| 76 |
is_q4_0_eligible,
|
|
|
|
| 77 |
target_quant_type,
|
| 78 |
tensor_type_key,
|
| 79 |
write_quantized_gguf,
|
|
|
|
| 184 |
self.thermal_var = tk.IntVar(value=0)
|
| 185 |
self.thermal_tilt_var = tk.DoubleVar(value=1.0)
|
| 186 |
self.pin_dc_var = tk.BooleanVar(value=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 187 |
|
| 188 |
self.cli_preview_var = tk.StringVar()
|
| 189 |
self.status_var = tk.StringVar(value="Ready.")
|
|
|
|
| 217 |
self.promote_attn_q4_var,
|
| 218 |
self.quant_format_var,
|
| 219 |
self.thermal_var,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 220 |
):
|
| 221 |
v.trace_add("write", lambda *_: self._update_cli_preview())
|
|
|
|
|
|
|
| 222 |
|
| 223 |
def _apply_theme(self) -> None:
|
| 224 |
style = ttk.Style(self.root)
|
|
|
|
| 483 |
text="Pin DC residual to 0 (Q2_K free lunch)",
|
| 484 |
variable=self.pin_dc_var,
|
| 485 |
).grid(row=3, column=0, columnspan=2, sticky=tk.W, padx=4, pady=1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 486 |
ttk.Label(
|
| 487 |
spec_f, text="(λ multiplier ≥1 during thermal anneal; ~1e2–1e3 ≈ zero-coherent-residual '0-error' anneal)",
|
| 488 |
foreground="#93c5fd",
|
| 489 |
+
).grid(row=4, column=0, columnspan=4, sticky=tk.W, padx=4, pady=(0, 2))
|
| 490 |
|
| 491 |
# Right: GGUF Tensor Browser
|
| 492 |
browser_frame = ttk.LabelFrame(right_pane, text="3. GGUF Tensor Inspector & Live Status", padding=8)
|
|
|
|
| 816 |
therm_passes=max(0, int(self.thermal_var.get())),
|
| 817 |
therm_lambda_tilt=max(1.0, float(self.thermal_tilt_var.get())),
|
| 818 |
pin_dc=bool(self.pin_dc_var.get()),
|
|
|
|
|
|
|
|
|
|
|
|
|
| 819 |
quant_format=self.quant_format_var.get(),
|
| 820 |
custom_quant_map=self._custom_map_for_plan() or {},
|
| 821 |
enable_q4_fallback=bool(self.q4_fallback_var.get()) and self.quant_format_var.get() not in ("q2_k", "q3_k"),
|
|
|
|
| 869 |
cmd += ["--thermal-tilt", str(float(self.thermal_tilt_var.get()))]
|
| 870 |
if self.pin_dc_var.get():
|
| 871 |
cmd += ["--pin-dc"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 872 |
cmd.append("--verbose")
|
| 873 |
return " ".join(shlex.quote(part) for part in cmd)
|
| 874 |
|
|
|
|
| 932 |
self._refresh_plan_view()
|
| 933 |
self._update_cli_preview()
|
| 934 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 935 |
def _refresh_plan_view(self) -> None:
|
| 936 |
if self._reader is None:
|
| 937 |
return
|
|
|
|
| 939 |
scope_selected = self.mode_var.get() == "selected"
|
| 940 |
n_q2, n_q3, n_q4, n_copy = 0, 0, 0, 0
|
| 941 |
n_q1 = 0
|
| 942 |
+
planned_bytes = 0
|
|
|
|
| 943 |
for ti in self._reader.tensors:
|
| 944 |
tgt = self._plan_target(ti, chosen, scope_selected)
|
| 945 |
if tgt == "Q2_K":
|
|
|
|
| 963 |
planned_bytes += (ti.n_elements // QK1_0) * Q1_0_BLOCK_BYTES
|
| 964 |
else:
|
| 965 |
planned_bytes += ti.n_bytes
|
|
|
|
|
|
|
|
|
|
| 966 |
|
| 967 |
if not self.tree.exists(ti.name):
|
| 968 |
continue
|
|
|
|
| 980 |
vals[6] = state_str
|
| 981 |
self.tree.item(ti.name, tags=(tgt_label,), values=vals)
|
| 982 |
|
| 983 |
+
if planned_bytes >= 1024 ** 3:
|
| 984 |
+
planned_text = f"{planned_bytes / (1024 ** 3):.2f} GiB"
|
| 985 |
+
elif planned_bytes >= 1024 ** 2:
|
| 986 |
+
planned_text = f"{planned_bytes / (1024 ** 2):.1f} MiB"
|
| 987 |
+
else:
|
| 988 |
+
planned_text = f"{planned_bytes / 1024:.1f} KiB"
|
| 989 |
scope_text = "selected" if scope_selected else "all"
|
| 990 |
self.status_var.set(
|
| 991 |
f"Plan ({self.quant_format_var.get().upper()}, {scope_text}): {n_q1} Q1_0 | {n_q2} Q2_K | {n_q3} Q3_K | {n_q4} Q4_0 | {n_copy} Copy "
|
|
|
|
| 1002 |
plan_filt = self.plan_filter_var.get()
|
| 1003 |
n_q2, n_q3, n_q4, n_copy = 0, 0, 0, 0
|
| 1004 |
n_q1 = 0
|
| 1005 |
+
planned_bytes = 0
|
|
|
|
| 1006 |
for ti in self._reader.tensors:
|
| 1007 |
tgt = self._plan_target(ti, chosen, scope_selected)
|
| 1008 |
if tgt == "Q2_K":
|
|
|
|
| 1026 |
planned_bytes += (ti.n_elements // QK1_0) * Q1_0_BLOCK_BYTES
|
| 1027 |
else:
|
| 1028 |
planned_bytes += ti.n_bytes
|
|
|
|
|
|
|
|
|
|
| 1029 |
|
| 1030 |
tgt_label = tgt if tgt else "Copy"
|
| 1031 |
if plan_filt != "ALL" and tgt_label.upper() != plan_filt:
|
|
|
|
| 1067 |
keep_selected = [n for n in chosen if self.tree.exists(n)]
|
| 1068 |
if keep_selected:
|
| 1069 |
self.tree.selection_set(keep_selected)
|
| 1070 |
+
if planned_bytes >= 1024 ** 3:
|
| 1071 |
+
planned_text = f"{planned_bytes / (1024 ** 3):.2f} GiB"
|
| 1072 |
+
elif planned_bytes >= 1024 ** 2:
|
| 1073 |
+
planned_text = f"{planned_bytes / (1024 ** 2):.1f} MiB"
|
| 1074 |
+
else:
|
| 1075 |
+
planned_text = f"{planned_bytes / 1024:.1f} KiB"
|
| 1076 |
scope_text = "selected" if scope_selected else "all"
|
| 1077 |
self.status_var.set(
|
| 1078 |
f"Plan ({self.quant_format_var.get().upper()}, {scope_text}): {n_q1} Q1_0 | {n_q2} Q2_K | {n_q3} Q3_K | {n_q4} Q4_0 | {n_copy} Copy "
|
pipeline.py
CHANGED
|
@@ -2,7 +2,6 @@
|
|
| 2 |
|
| 3 |
Pipeline stages (mirroring the C engine, with V2 fixes):
|
| 4 |
|
| 5 |
-
0. self-describing per-superblock segmentation (opt-in, ``cfg.segment``);
|
| 6 |
1. kurtosis-gated outlier clamp and batched GGML seeds;
|
| 7 |
2. vectorised WLS superblock solve;
|
| 8 |
3. factored candidate field + standalone factored floor;
|
|
@@ -73,8 +72,6 @@ class TensorStats:
|
|
| 73 |
factor_floor_used: int
|
| 74 |
candidate_floor_used: int
|
| 75 |
therm_improved: int = 0
|
| 76 |
-
segment_rounds: int = 0
|
| 77 |
-
segment_flips: int = 0
|
| 78 |
|
| 79 |
|
| 80 |
@dataclass(slots=True)
|
|
@@ -87,22 +84,10 @@ class QuantizedTensor:
|
|
| 87 |
factor_objectives: np.ndarray
|
| 88 |
config: HPCConfig
|
| 89 |
stats: TensorStats
|
| 90 |
-
segment_perm: np.ndarray | None = None
|
| 91 |
-
segment_labels: np.ndarray | None = None
|
| 92 |
|
| 93 |
def dequantize(self) -> np.ndarray:
|
| 94 |
return np.concatenate([b.dequantize() for b in self.blocks])
|
| 95 |
|
| 96 |
-
def dequantize_original(self) -> np.ndarray:
|
| 97 |
-
"""Consumer-side reconstruction: scatter dequantized slots back to
|
| 98 |
-
original positions using the stored label channel (exact)."""
|
| 99 |
-
if self.segment_perm is None:
|
| 100 |
-
return self.dequantize()
|
| 101 |
-
Xh = np.stack([b.dequantize() for b in self.blocks])
|
| 102 |
-
out = np.empty_like(Xh)
|
| 103 |
-
np.put_along_axis(out, self.segment_perm, Xh, axis=1)
|
| 104 |
-
return out.ravel()
|
| 105 |
-
|
| 106 |
|
| 107 |
def _phase2_wls(X, W, seeds, cfg: HPCConfig):
|
| 108 |
n = X.shape[0]
|
|
@@ -879,39 +864,6 @@ class Q2KQuantizer:
|
|
| 879 |
x = x.ravel()
|
| 880 |
n_blocks = x.size // QK_K
|
| 881 |
|
| 882 |
-
seg_perm = None
|
| 883 |
-
seg_labels = None
|
| 884 |
-
seg_rounds = 0
|
| 885 |
-
seg_flips = 0
|
| 886 |
-
|
| 887 |
-
if cfg.segment:
|
| 888 |
-
from .segmentation import apply_order, q2k_proxy_cfg, segment_stage
|
| 889 |
-
|
| 890 |
-
_emit(
|
| 891 |
-
"Phase 0: Band-Major Segmentation & Lookup Table",
|
| 892 |
-
0,
|
| 893 |
-
n_blocks,
|
| 894 |
-
f"Building {cfg.segment_table_size}-entry LUT & assigning {n_blocks:,} superblocks (k={cfg.segment_k})",
|
| 895 |
-
)
|
| 896 |
-
X_p = x.reshape(n_blocks, QK_K)
|
| 897 |
-
imp2d = (
|
| 898 |
-
None
|
| 899 |
-
if importance is None
|
| 900 |
-
else np.asarray(importance, dtype=np.float32).ravel().reshape(n_blocks, QK_K)
|
| 901 |
-
)
|
| 902 |
-
clamp_val0 = float(seed_clamp_value(x, cfg))
|
| 903 |
-
proxy = q2k_proxy_cfg(clamp_val0, cfg)
|
| 904 |
-
seg_perm, seg_labels, seg_rounds = segment_stage(
|
| 905 |
-
X_p, imp2d, cfg, proxy, max(2, int(cfg.segment_k))
|
| 906 |
-
)
|
| 907 |
-
X_p = apply_order(X_p, seg_perm).astype(np.float32)
|
| 908 |
-
x = np.ascontiguousarray(X_p.ravel())
|
| 909 |
-
if imp2d is not None:
|
| 910 |
-
importance = np.ascontiguousarray(
|
| 911 |
-
apply_order(imp2d, seg_perm).astype(np.float32).ravel()
|
| 912 |
-
)
|
| 913 |
-
X_p = None
|
| 914 |
-
|
| 915 |
if cfg.device != "cpu":
|
| 916 |
from .cuda_backend import cuda_is_available, quantize_cuda
|
| 917 |
|
|
@@ -920,7 +872,7 @@ class Q2KQuantizer:
|
|
| 920 |
):
|
| 921 |
dev_str = "cuda" if cfg.device == "auto" else cfg.device
|
| 922 |
res = quantize_cuda(
|
| 923 |
-
|
| 924 |
importance,
|
| 925 |
row_width,
|
| 926 |
cfg,
|
|
@@ -928,17 +880,6 @@ class Q2KQuantizer:
|
|
| 928 |
stop_event=stop_event,
|
| 929 |
device=dev_str,
|
| 930 |
)
|
| 931 |
-
if seg_perm is not None:
|
| 932 |
-
from .segmentation import band_labels
|
| 933 |
-
|
| 934 |
-
n_chk = min(n_blocks, 256)
|
| 935 |
-
Xh = np.stack([b.dequantize() for b in res.blocks[:n_chk]]).astype(np.float64)
|
| 936 |
-
labels_slot = np.take_along_axis(seg_labels[:n_chk], seg_perm[:n_chk], axis=1)
|
| 937 |
-
labels_rec = band_labels(Xh, max(2, int(cfg.segment_k)))
|
| 938 |
-
res.stats.segment_rounds = seg_rounds
|
| 939 |
-
res.stats.segment_flips = int(np.count_nonzero(labels_rec != labels_slot))
|
| 940 |
-
res.segment_perm = seg_perm
|
| 941 |
-
res.segment_labels = seg_labels
|
| 942 |
if cfg.verbose:
|
| 943 |
_report(res.stats)
|
| 944 |
return res
|
|
@@ -1258,17 +1199,6 @@ class Q2KQuantizer:
|
|
| 1258 |
else:
|
| 1259 |
weighted += float(np.dot(W[i].astype(np.float64), e * e))
|
| 1260 |
|
| 1261 |
-
if seg_perm is not None:
|
| 1262 |
-
# informational: how many labels a channelless decoder would
|
| 1263 |
-
# mis-derive from the stored slot values
|
| 1264 |
-
from .segmentation import band_labels
|
| 1265 |
-
|
| 1266 |
-
n_chk = min(n_blocks, 256)
|
| 1267 |
-
Xh = np.stack([b.dequantize() for b in blocks[:n_chk]]).astype(np.float64)
|
| 1268 |
-
labels_slot = np.take_along_axis(seg_labels[:n_chk], seg_perm[:n_chk], axis=1)
|
| 1269 |
-
labels_rec = band_labels(Xh, max(2, int(cfg.segment_k)))
|
| 1270 |
-
seg_flips = int(np.count_nonzero(labels_rec != labels_slot))
|
| 1271 |
-
|
| 1272 |
rmse = float(np.sqrt(total_sse / x.size))
|
| 1273 |
stats = TensorStats(
|
| 1274 |
n_blocks=n_blocks,
|
|
@@ -1281,8 +1211,6 @@ class Q2KQuantizer:
|
|
| 1281 |
factor_floor_used=factor_floor_used,
|
| 1282 |
candidate_floor_used=candidate_floor_used,
|
| 1283 |
therm_improved=therm_improved,
|
| 1284 |
-
segment_rounds=seg_rounds,
|
| 1285 |
-
segment_flips=seg_flips,
|
| 1286 |
)
|
| 1287 |
_emit(
|
| 1288 |
"Phase 5: Tensor Complete",
|
|
@@ -1309,8 +1237,6 @@ class Q2KQuantizer:
|
|
| 1309 |
factor_objectives=factor_objectives,
|
| 1310 |
config=cfg,
|
| 1311 |
stats=stats,
|
| 1312 |
-
segment_perm=seg_perm,
|
| 1313 |
-
segment_labels=seg_labels,
|
| 1314 |
)
|
| 1315 |
if cfg.verbose:
|
| 1316 |
_report(stats)
|
|
@@ -1332,8 +1258,6 @@ def _stack_blocks(blocks):
|
|
| 1332 |
|
| 1333 |
def _report(stats: TensorStats) -> None:
|
| 1334 |
extra = f" therm={stats.therm_improved}" if stats.therm_improved else ""
|
| 1335 |
-
if stats.segment_rounds:
|
| 1336 |
-
extra += f" seg(rounds={stats.segment_rounds}, flips={stats.segment_flips})"
|
| 1337 |
print(
|
| 1338 |
f"Q2_K V2: blocks={stats.n_blocks} rmse={stats.rmse:.6e} "
|
| 1339 |
f"rmse/sigma={stats.rmse_over_sigma:.5f} temp={stats.temperature:.3e} "
|
|
|
|
| 2 |
|
| 3 |
Pipeline stages (mirroring the C engine, with V2 fixes):
|
| 4 |
|
|
|
|
| 5 |
1. kurtosis-gated outlier clamp and batched GGML seeds;
|
| 6 |
2. vectorised WLS superblock solve;
|
| 7 |
3. factored candidate field + standalone factored floor;
|
|
|
|
| 72 |
factor_floor_used: int
|
| 73 |
candidate_floor_used: int
|
| 74 |
therm_improved: int = 0
|
|
|
|
|
|
|
| 75 |
|
| 76 |
|
| 77 |
@dataclass(slots=True)
|
|
|
|
| 84 |
factor_objectives: np.ndarray
|
| 85 |
config: HPCConfig
|
| 86 |
stats: TensorStats
|
|
|
|
|
|
|
| 87 |
|
| 88 |
def dequantize(self) -> np.ndarray:
|
| 89 |
return np.concatenate([b.dequantize() for b in self.blocks])
|
| 90 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
|
| 92 |
def _phase2_wls(X, W, seeds, cfg: HPCConfig):
|
| 93 |
n = X.shape[0]
|
|
|
|
| 864 |
x = x.ravel()
|
| 865 |
n_blocks = x.size // QK_K
|
| 866 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 867 |
if cfg.device != "cpu":
|
| 868 |
from .cuda_backend import cuda_is_available, quantize_cuda
|
| 869 |
|
|
|
|
| 872 |
):
|
| 873 |
dev_str = "cuda" if cfg.device == "auto" else cfg.device
|
| 874 |
res = quantize_cuda(
|
| 875 |
+
weights,
|
| 876 |
importance,
|
| 877 |
row_width,
|
| 878 |
cfg,
|
|
|
|
| 880 |
stop_event=stop_event,
|
| 881 |
device=dev_str,
|
| 882 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 883 |
if cfg.verbose:
|
| 884 |
_report(res.stats)
|
| 885 |
return res
|
|
|
|
| 1199 |
else:
|
| 1200 |
weighted += float(np.dot(W[i].astype(np.float64), e * e))
|
| 1201 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1202 |
rmse = float(np.sqrt(total_sse / x.size))
|
| 1203 |
stats = TensorStats(
|
| 1204 |
n_blocks=n_blocks,
|
|
|
|
| 1211 |
factor_floor_used=factor_floor_used,
|
| 1212 |
candidate_floor_used=candidate_floor_used,
|
| 1213 |
therm_improved=therm_improved,
|
|
|
|
|
|
|
| 1214 |
)
|
| 1215 |
_emit(
|
| 1216 |
"Phase 5: Tensor Complete",
|
|
|
|
| 1237 |
factor_objectives=factor_objectives,
|
| 1238 |
config=cfg,
|
| 1239 |
stats=stats,
|
|
|
|
|
|
|
| 1240 |
)
|
| 1241 |
if cfg.verbose:
|
| 1242 |
_report(stats)
|
|
|
|
| 1258 |
|
| 1259 |
def _report(stats: TensorStats) -> None:
|
| 1260 |
extra = f" therm={stats.therm_improved}" if stats.therm_improved else ""
|
|
|
|
|
|
|
| 1261 |
print(
|
| 1262 |
f"Q2_K V2: blocks={stats.n_blocks} rmse={stats.rmse:.6e} "
|
| 1263 |
f"rmse/sigma={stats.rmse_over_sigma:.5f} temp={stats.temperature:.3e} "
|
q3_k.py
CHANGED
|
@@ -983,17 +983,12 @@ def quantize_tensor_q3_k(
|
|
| 983 |
importance: np.ndarray | None = None,
|
| 984 |
cfg: HPCConfig | None = None,
|
| 985 |
chunk_blocks: int | None = None,
|
| 986 |
-
|
| 987 |
-
):
|
| 988 |
"""Quantize a tensor to GGML Q3_K using the full HPC V2 pipeline.
|
| 989 |
|
| 990 |
``chunk_blocks`` (256-weight super-blocks per chunk) defaults to
|
| 991 |
``Q3_K_CHUNK_BLOCKS_CUDA`` on the GPU path (same weights-per-chunk as the
|
| 992 |
Q4_0 reference) and ``Q3_K_CHUNK_BLOCKS_CPU`` on the CPU path.
|
| 993 |
-
|
| 994 |
-
With ``return_labels=True`` returns ``(payload, n_blocks, rmse, labels)``
|
| 995 |
-
where ``labels`` is the segmentation label channel (one band id per
|
| 996 |
-
original position, or None when segmentation is off).
|
| 997 |
"""
|
| 998 |
cfg = cfg or HPCConfig()
|
| 999 |
x = np.asarray(weights, dtype=np.float32).ravel()
|
|
@@ -1010,22 +1005,6 @@ def quantize_tensor_q3_k(
|
|
| 1010 |
else:
|
| 1011 |
W_raw = None
|
| 1012 |
|
| 1013 |
-
if cfg.segment:
|
| 1014 |
-
from .segmentation import apply_order, band_labels, q3k_proxy, segment_stage
|
| 1015 |
-
|
| 1016 |
-
seg_order, seg_labels, seg_rounds = segment_stage(
|
| 1017 |
-
X, W_raw, cfg, q3k_proxy, max(2, int(cfg.segment_k))
|
| 1018 |
-
)
|
| 1019 |
-
X = np.ascontiguousarray(apply_order(X.astype(np.float64), seg_order)).astype(np.float32)
|
| 1020 |
-
if W_raw is not None:
|
| 1021 |
-
W_raw = np.ascontiguousarray(
|
| 1022 |
-
apply_order(W_raw.astype(np.float64), seg_order)
|
| 1023 |
-
).astype(np.float32)
|
| 1024 |
-
else:
|
| 1025 |
-
seg_order = None
|
| 1026 |
-
seg_labels = None
|
| 1027 |
-
seg_rounds = 0
|
| 1028 |
-
|
| 1029 |
cuda_ok = cfg.device != "cpu" and cuda_is_available()
|
| 1030 |
use_cuda = cuda_ok and (
|
| 1031 |
cfg.device.startswith("cuda") or (cfg.device == "auto" and n_blocks >= 64)
|
|
@@ -1062,22 +1041,4 @@ def quantize_tensor_q3_k(
|
|
| 1062 |
total_sse += sse_b
|
| 1063 |
|
| 1064 |
rmse = float(np.sqrt(total_sse / x.size))
|
| 1065 |
-
|
| 1066 |
-
if cfg.segment:
|
| 1067 |
-
n_chk = min(n_blocks, 256)
|
| 1068 |
-
raw_chk = b"".join(chunks)[: n_chk * Q3_K_BLOCK_BYTES]
|
| 1069 |
-
xh = np.asarray(dequantize_q3_k_bytes(raw_chk, n_chk), dtype=np.float64).reshape(
|
| 1070 |
-
n_chk, QK3_K
|
| 1071 |
-
)
|
| 1072 |
-
labels_slot = np.take_along_axis(seg_labels[:n_chk], seg_order[:n_chk], axis=1)
|
| 1073 |
-
labels_rec = band_labels(xh, max(2, int(cfg.segment_k)))
|
| 1074 |
-
seg_flips = int(np.count_nonzero(labels_rec != labels_slot))
|
| 1075 |
-
_log.info(
|
| 1076 |
-
"Q3_K segmentation: rounds=%d channelless flips=%d rmse=%.6e",
|
| 1077 |
-
seg_rounds, seg_flips, rmse,
|
| 1078 |
-
)
|
| 1079 |
-
|
| 1080 |
-
payload = b"".join(chunks)
|
| 1081 |
-
if return_labels:
|
| 1082 |
-
return payload, n_blocks, rmse, seg_labels
|
| 1083 |
-
return payload, n_blocks, rmse
|
|
|
|
| 983 |
importance: np.ndarray | None = None,
|
| 984 |
cfg: HPCConfig | None = None,
|
| 985 |
chunk_blocks: int | None = None,
|
| 986 |
+
) -> tuple[bytes, int, float]:
|
|
|
|
| 987 |
"""Quantize a tensor to GGML Q3_K using the full HPC V2 pipeline.
|
| 988 |
|
| 989 |
``chunk_blocks`` (256-weight super-blocks per chunk) defaults to
|
| 990 |
``Q3_K_CHUNK_BLOCKS_CUDA`` on the GPU path (same weights-per-chunk as the
|
| 991 |
Q4_0 reference) and ``Q3_K_CHUNK_BLOCKS_CPU`` on the CPU path.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 992 |
"""
|
| 993 |
cfg = cfg or HPCConfig()
|
| 994 |
x = np.asarray(weights, dtype=np.float32).ravel()
|
|
|
|
| 1005 |
else:
|
| 1006 |
W_raw = None
|
| 1007 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1008 |
cuda_ok = cfg.device != "cpu" and cuda_is_available()
|
| 1009 |
use_cuda = cuda_ok and (
|
| 1010 |
cfg.device.startswith("cuda") or (cfg.device == "auto" and n_blocks >= 64)
|
|
|
|
| 1041 |
total_sse += sse_b
|
| 1042 |
|
| 1043 |
rmse = float(np.sqrt(total_sse / x.size))
|
| 1044 |
+
return b"".join(chunks), n_blocks, rmse
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
q4_0.py
CHANGED
|
@@ -28,8 +28,6 @@ per 18-byte block = 4.5 bpw):
|
|
| 28 |
from __future__ import annotations
|
| 29 |
|
| 30 |
from math import ceil
|
| 31 |
-
import logging
|
| 32 |
-
|
| 33 |
import numpy as np
|
| 34 |
|
| 35 |
try:
|
|
@@ -50,8 +48,6 @@ QK4_0 = 32
|
|
| 50 |
Q4_0_BLOCK_BYTES = 18
|
| 51 |
Q4_N_CAND = 24
|
| 52 |
Q4_N_STATES = 6
|
| 53 |
-
|
| 54 |
-
_log = logging.getLogger(__name__)
|
| 55 |
Q4_N_LEVELS = 16
|
| 56 |
|
| 57 |
|
|
@@ -587,16 +583,6 @@ def quantize_tensor_q4_0(
|
|
| 587 |
else:
|
| 588 |
W_raw = None
|
| 589 |
|
| 590 |
-
if cfg.segment:
|
| 591 |
-
# Q4_0's unit block (32 weights, one scale+min) has no per-band
|
| 592 |
-
# sub-scale dof to align, position-ascending k=1 layout is the
|
| 593 |
-
# identity permutation, and the permutation channel would pay 8
|
| 594 |
-
# bits per weight for nothing. Explicit no-op for now.
|
| 595 |
-
_log.info(
|
| 596 |
-
"Q4_0 segmentation disabled: unit blocks (d, min) have no band dof "
|
| 597 |
-
"to align (k=1 layout is the identity)"
|
| 598 |
-
)
|
| 599 |
-
|
| 600 |
use_cuda = cfg.device != "cpu" and cuda_is_available() and (
|
| 601 |
cfg.device.startswith("cuda") or (cfg.device == "auto" and n_blocks >= 64)
|
| 602 |
)
|
|
|
|
| 28 |
from __future__ import annotations
|
| 29 |
|
| 30 |
from math import ceil
|
|
|
|
|
|
|
| 31 |
import numpy as np
|
| 32 |
|
| 33 |
try:
|
|
|
|
| 48 |
Q4_0_BLOCK_BYTES = 18
|
| 49 |
Q4_N_CAND = 24
|
| 50 |
Q4_N_STATES = 6
|
|
|
|
|
|
|
| 51 |
Q4_N_LEVELS = 16
|
| 52 |
|
| 53 |
|
|
|
|
| 583 |
else:
|
| 584 |
W_raw = None
|
| 585 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 586 |
use_cuda = cfg.device != "cpu" and cuda_is_available() and (
|
| 587 |
cfg.device.startswith("cuda") or (cfg.device == "auto" and n_blocks >= 64)
|
| 588 |
)
|