Upload 14 files
Browse files- gguf.py +37 -1
- pipeline.py +127 -3
gguf.py
CHANGED
|
@@ -377,6 +377,7 @@ def write_quantized_gguf(
|
|
| 377 |
limit: int = 0,
|
| 378 |
verbose: bool = True,
|
| 379 |
progress_callback=None,
|
|
|
|
| 380 |
stop_event=None,
|
| 381 |
) -> dict[str, float]:
|
| 382 |
"""Quantize a source GGUF with the V2 engine and emit a valid GGUF.
|
|
@@ -469,13 +470,36 @@ def write_quantized_gguf(
|
|
| 469 |
if target > fout.tell():
|
| 470 |
fout.write(b"\x00" * (target - fout.tell()))
|
| 471 |
if plan[idx]:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 472 |
x, row = reader.read_tensor(ti.name)
|
| 473 |
imp = None
|
| 474 |
if imat is not None:
|
| 475 |
raw_imp = lookup_imatrix(imat, ti.name)
|
| 476 |
if raw_imp is not None:
|
| 477 |
imp = expand_importance(raw_imp, x.size, row)
|
| 478 |
-
res = quantizer.quantize(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 479 |
payload = blocks_to_bytes(res.scales, res.qs, res.dm)
|
| 480 |
if len(payload) != out_size:
|
| 481 |
raise RuntimeError(f"{ti.name}: Q2_K payload size mismatch")
|
|
@@ -498,6 +522,18 @@ def write_quantized_gguf(
|
|
| 498 |
imp is not None,
|
| 499 |
)
|
| 500 |
else:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 501 |
reader.copy_tensor_raw_to(ti.name, fout)
|
| 502 |
if verbose and idx % 25 == 0:
|
| 503 |
print(f" copy {ti.name}")
|
|
|
|
| 377 |
limit: int = 0,
|
| 378 |
verbose: bool = True,
|
| 379 |
progress_callback=None,
|
| 380 |
+
stage_callback=None,
|
| 381 |
stop_event=None,
|
| 382 |
) -> dict[str, float]:
|
| 383 |
"""Quantize a source GGUF with the V2 engine and emit a valid GGUF.
|
|
|
|
| 470 |
if target > fout.tell():
|
| 471 |
fout.write(b"\x00" * (target - fout.tell()))
|
| 472 |
if plan[idx]:
|
| 473 |
+
has_imat = imat is not None and lookup_imatrix(imat, ti.name) is not None
|
| 474 |
+
if stage_callback is not None:
|
| 475 |
+
stage_callback(
|
| 476 |
+
idx + 1,
|
| 477 |
+
len(out_infos),
|
| 478 |
+
ti,
|
| 479 |
+
{
|
| 480 |
+
"phase": f"Reading & Dequantizing Source ({ti.type_name})",
|
| 481 |
+
"done": 0,
|
| 482 |
+
"total": ti.n_elements // QK_K,
|
| 483 |
+
"detail": f"dims={ti.dims} elements={ti.n_elements:,} ({ti.n_bytes / 1048576:.2f} MB) imatrix={'yes' if has_imat else 'no'}",
|
| 484 |
+
},
|
| 485 |
+
)
|
| 486 |
x, row = reader.read_tensor(ti.name)
|
| 487 |
imp = None
|
| 488 |
if imat is not None:
|
| 489 |
raw_imp = lookup_imatrix(imat, ti.name)
|
| 490 |
if raw_imp is not None:
|
| 491 |
imp = expand_importance(raw_imp, x.size, row)
|
| 492 |
+
res = quantizer.quantize(
|
| 493 |
+
x,
|
| 494 |
+
importance=imp,
|
| 495 |
+
row_width=row,
|
| 496 |
+
status_callback=(
|
| 497 |
+
(lambda ev, _i=idx + 1, _ti=ti: stage_callback(_i, len(out_infos), _ti, ev))
|
| 498 |
+
if stage_callback is not None
|
| 499 |
+
else None
|
| 500 |
+
),
|
| 501 |
+
stop_event=stop_event,
|
| 502 |
+
)
|
| 503 |
payload = blocks_to_bytes(res.scales, res.qs, res.dm)
|
| 504 |
if len(payload) != out_size:
|
| 505 |
raise RuntimeError(f"{ti.name}: Q2_K payload size mismatch")
|
|
|
|
| 522 |
imp is not None,
|
| 523 |
)
|
| 524 |
else:
|
| 525 |
+
if stage_callback is not None:
|
| 526 |
+
stage_callback(
|
| 527 |
+
idx + 1,
|
| 528 |
+
len(out_infos),
|
| 529 |
+
ti,
|
| 530 |
+
{
|
| 531 |
+
"phase": f"Passthrough Copy ({ti.type_name})",
|
| 532 |
+
"done": 1,
|
| 533 |
+
"total": 1,
|
| 534 |
+
"detail": f"dims={ti.dims} ({ti.n_bytes / 1048576:.2f} MB)",
|
| 535 |
+
},
|
| 536 |
+
)
|
| 537 |
reader.copy_tensor_raw_to(ti.name, fout)
|
| 538 |
if verbose and idx % 25 == 0:
|
| 539 |
print(f" copy {ti.name}")
|
pipeline.py
CHANGED
|
@@ -17,6 +17,7 @@ from __future__ import annotations
|
|
| 17 |
|
| 18 |
from dataclasses import dataclass
|
| 19 |
from math import ceil
|
|
|
|
| 20 |
|
| 21 |
import numpy as np
|
| 22 |
|
|
@@ -413,7 +414,25 @@ class Q2KQuantizer:
|
|
| 413 |
weights: np.ndarray,
|
| 414 |
importance: np.ndarray | None = None,
|
| 415 |
row_width: int | None = None,
|
|
|
|
|
|
|
| 416 |
) -> QuantizedTensor:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 417 |
cfg = self.config
|
| 418 |
x = np.asarray(weights, dtype=np.float32)
|
| 419 |
if x.size == 0:
|
|
@@ -436,13 +455,34 @@ class Q2KQuantizer:
|
|
| 436 |
else:
|
| 437 |
W = None
|
| 438 |
|
|
|
|
|
|
|
| 439 |
clamp_val = seed_clamp_value(x, cfg)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 440 |
seeds = build_seeds(X, W, cfg, clamp_val)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 441 |
base_d, base_m = _phase2_wls(X, W, seeds, clamp_val)
|
| 442 |
|
| 443 |
candidate_errors = np.full((n_blocks, TOTAL_CANDIDATES), np.inf, dtype=np.float32)
|
| 444 |
standalone: list[FactorResult] = []
|
|
|
|
|
|
|
|
|
|
| 445 |
for i in range(n_blocks):
|
|
|
|
| 446 |
wi = None if W is None else W[i]
|
| 447 |
candidate_errors[i] = factor_candidates(
|
| 448 |
X[i],
|
|
@@ -453,13 +493,48 @@ class Q2KQuantizer:
|
|
| 453 |
base_m[i],
|
| 454 |
cfg,
|
| 455 |
)
|
| 456 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 457 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 458 |
best, temperature, _ = _phase3_select(candidate_errors, cfg)
|
| 459 |
carry = _compute_dc_carry(X, seeds, best, base_d, base_m, cfg, row_width)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 460 |
|
| 461 |
at_slot: list[FactorResult] = []
|
| 462 |
for i in range(n_blocks):
|
|
|
|
| 463 |
wi = None if W is None else W[i]
|
| 464 |
d16, m16 = candidate_pair(base_d[i], base_m[i], best[i])
|
| 465 |
at_slot.append(
|
|
@@ -482,7 +557,11 @@ class Q2KQuantizer:
|
|
| 482 |
blocks: list[Q2KBlock] = []
|
| 483 |
factor_floor_used = 0
|
| 484 |
candidate_floor_used = 0
|
|
|
|
|
|
|
|
|
|
| 485 |
for i in range(n_blocks):
|
|
|
|
| 486 |
wi = None if W is None else W[i]
|
| 487 |
d, m, ls, lm, codes, obj, sse = _assemble_block(
|
| 488 |
X[i], wi, seeds, base_d[i], base_m[i], best[i], carry[i], cfg
|
|
@@ -517,9 +596,42 @@ class Q2KQuantizer:
|
|
| 517 |
obj, sse = fobj, fsse
|
| 518 |
factor_floor_used += 1
|
| 519 |
|
| 520 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 521 |
|
| 522 |
if cfg.apply_dc_carry and (cfg.dc_lambda > 0.0 or cfg.dc_decay > 0.0):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 523 |
blocks = _apply_dc_nudge(X, W, blocks, cfg, row_width)
|
| 524 |
|
| 525 |
total_sse = 0.0
|
|
@@ -532,7 +644,6 @@ class Q2KQuantizer:
|
|
| 532 |
else:
|
| 533 |
weighted += float(np.dot(W[i].astype(np.float64), e * e))
|
| 534 |
|
| 535 |
-
sigma = float(np.sqrt(np.mean(x.astype(np.float64) ** 2)))
|
| 536 |
rmse = float(np.sqrt(total_sse / x.size))
|
| 537 |
stats = TensorStats(
|
| 538 |
n_blocks=n_blocks,
|
|
@@ -545,6 +656,19 @@ class Q2KQuantizer:
|
|
| 545 |
factor_floor_used=factor_floor_used,
|
| 546 |
candidate_floor_used=candidate_floor_used,
|
| 547 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 548 |
scales, qs, dm = _stack_blocks(blocks)
|
| 549 |
factor_objectives = np.array([r.objective for r in standalone], dtype=np.float64)
|
| 550 |
result = QuantizedTensor(
|
|
|
|
| 17 |
|
| 18 |
from dataclasses import dataclass
|
| 19 |
from math import ceil
|
| 20 |
+
import time
|
| 21 |
|
| 22 |
import numpy as np
|
| 23 |
|
|
|
|
| 414 |
weights: np.ndarray,
|
| 415 |
importance: np.ndarray | None = None,
|
| 416 |
row_width: int | None = None,
|
| 417 |
+
status_callback=None,
|
| 418 |
+
stop_event=None,
|
| 419 |
) -> QuantizedTensor:
|
| 420 |
+
def _emit(phase: str, done: int, total: int, detail: str, **extra) -> None:
|
| 421 |
+
if status_callback is not None:
|
| 422 |
+
status_callback(
|
| 423 |
+
{
|
| 424 |
+
"phase": phase,
|
| 425 |
+
"done": done,
|
| 426 |
+
"total": total,
|
| 427 |
+
"detail": detail,
|
| 428 |
+
**extra,
|
| 429 |
+
}
|
| 430 |
+
)
|
| 431 |
+
|
| 432 |
+
def _check_stop() -> None:
|
| 433 |
+
if stop_event is not None and stop_event.is_set():
|
| 434 |
+
raise InterruptedError("Quantization cancelled by user")
|
| 435 |
+
|
| 436 |
cfg = self.config
|
| 437 |
x = np.asarray(weights, dtype=np.float32)
|
| 438 |
if x.size == 0:
|
|
|
|
| 455 |
else:
|
| 456 |
W = None
|
| 457 |
|
| 458 |
+
sigma = float(np.sqrt(np.mean(x.astype(np.float64) ** 2)))
|
| 459 |
+
_check_stop()
|
| 460 |
clamp_val = seed_clamp_value(x, cfg)
|
| 461 |
+
_emit(
|
| 462 |
+
"Phase 1: Kurtosis Clamp & Batched GGML Seeds",
|
| 463 |
+
0,
|
| 464 |
+
n_blocks,
|
| 465 |
+
f"blocks={n_blocks} sigma={sigma:.5f} clamp={clamp_val:.5f} imatrix={'yes' if W is not None else 'no'}",
|
| 466 |
+
sigma=sigma,
|
| 467 |
+
)
|
| 468 |
seeds = build_seeds(X, W, cfg, clamp_val)
|
| 469 |
+
_check_stop()
|
| 470 |
+
_emit(
|
| 471 |
+
"Phase 2a: Vectorized Superblock WLS",
|
| 472 |
+
0,
|
| 473 |
+
n_blocks,
|
| 474 |
+
f"Solving 5-iteration WLS across {n_blocks} superblocks",
|
| 475 |
+
sigma=sigma,
|
| 476 |
+
)
|
| 477 |
base_d, base_m = _phase2_wls(X, W, seeds, clamp_val)
|
| 478 |
|
| 479 |
candidate_errors = np.full((n_blocks, TOTAL_CANDIDATES), np.inf, dtype=np.float32)
|
| 480 |
standalone: list[FactorResult] = []
|
| 481 |
+
t_cand = time.time()
|
| 482 |
+
last_emit = 0.0
|
| 483 |
+
step_report = max(1, min(32, n_blocks // 20 or 1))
|
| 484 |
for i in range(n_blocks):
|
| 485 |
+
_check_stop()
|
| 486 |
wi = None if W is None else W[i]
|
| 487 |
candidate_errors[i] = factor_candidates(
|
| 488 |
X[i],
|
|
|
|
| 493 |
base_m[i],
|
| 494 |
cfg,
|
| 495 |
)
|
| 496 |
+
fac_res = factor_only_solve(X[i], wi, cfg)
|
| 497 |
+
standalone.append(fac_res)
|
| 498 |
+
now = time.time()
|
| 499 |
+
if (i + 1) % step_report == 0 or (i + 1) == n_blocks or (now - last_emit) >= 0.25:
|
| 500 |
+
last_emit = now
|
| 501 |
+
elapsed = max(now - t_cand, 1.0e-6)
|
| 502 |
+
rate = (i + 1) / elapsed
|
| 503 |
+
eta = (n_blocks - (i + 1)) / max(rate, 1.0e-9)
|
| 504 |
+
_emit(
|
| 505 |
+
"Phase 2b: Analog-Guided Factored Candidate Field",
|
| 506 |
+
i + 1,
|
| 507 |
+
n_blocks,
|
| 508 |
+
f"blk {i+1}/{n_blocks} ({rate:.1f} blk/s, ETA {eta:.1f}s) "
|
| 509 |
+
f"d={float(fac_res.d):.5f} dmin={float(fac_res.dmin):.5f} "
|
| 510 |
+
f"obj={fac_res.objective:.5e} starts={fac_res.starts}",
|
| 511 |
+
rate=rate,
|
| 512 |
+
eta=eta,
|
| 513 |
+
sigma=sigma,
|
| 514 |
+
)
|
| 515 |
|
| 516 |
+
_check_stop()
|
| 517 |
+
_emit(
|
| 518 |
+
"Phase 3: 6-State Sieve & 36-State Viterbi DP",
|
| 519 |
+
0,
|
| 520 |
+
n_blocks,
|
| 521 |
+
f"Running Sieve + 36-state Viterbi sequence optimization ({cfg.optimizer.upper()})",
|
| 522 |
+
sigma=sigma,
|
| 523 |
+
)
|
| 524 |
best, temperature, _ = _phase3_select(candidate_errors, cfg)
|
| 525 |
carry = _compute_dc_carry(X, seeds, best, base_d, base_m, cfg, row_width)
|
| 526 |
+
_emit(
|
| 527 |
+
"Phase 3.9: Viterbi Path & Rolling DC Carry",
|
| 528 |
+
n_blocks,
|
| 529 |
+
n_blocks,
|
| 530 |
+
f"Boltzmann temp={temperature:.4e}, max |DC carry|={float(np.max(np.abs(carry))):.4e}",
|
| 531 |
+
temperature=temperature,
|
| 532 |
+
sigma=sigma,
|
| 533 |
+
)
|
| 534 |
|
| 535 |
at_slot: list[FactorResult] = []
|
| 536 |
for i in range(n_blocks):
|
| 537 |
+
_check_stop()
|
| 538 |
wi = None if W is None else W[i]
|
| 539 |
d16, m16 = candidate_pair(base_d[i], base_m[i], best[i])
|
| 540 |
at_slot.append(
|
|
|
|
| 557 |
blocks: list[Q2KBlock] = []
|
| 558 |
factor_floor_used = 0
|
| 559 |
candidate_floor_used = 0
|
| 560 |
+
running_sse = 0.0
|
| 561 |
+
t_asm = time.time()
|
| 562 |
+
last_emit = 0.0
|
| 563 |
for i in range(n_blocks):
|
| 564 |
+
_check_stop()
|
| 565 |
wi = None if W is None else W[i]
|
| 566 |
d, m, ls, lm, codes, obj, sse = _assemble_block(
|
| 567 |
X[i], wi, seeds, base_d[i], base_m[i], best[i], carry[i], cfg
|
|
|
|
| 596 |
obj, sse = fobj, fsse
|
| 597 |
factor_floor_used += 1
|
| 598 |
|
| 599 |
+
blk_obj = make_block(d, m, ls, lm, codes)
|
| 600 |
+
blocks.append(blk_obj)
|
| 601 |
+
running_sse += blk_obj.error(X[i])
|
| 602 |
+
now = time.time()
|
| 603 |
+
if (i + 1) % step_report == 0 or (i + 1) == n_blocks or (now - last_emit) >= 0.25:
|
| 604 |
+
last_emit = now
|
| 605 |
+
elapsed = max(now - t_asm, 1.0e-6)
|
| 606 |
+
rate = (i + 1) / elapsed
|
| 607 |
+
eta = (n_blocks - (i + 1)) / max(rate, 1.0e-9)
|
| 608 |
+
cur_rmse = float(np.sqrt(running_sse / ((i + 1) * QK_K)))
|
| 609 |
+
_emit(
|
| 610 |
+
"Phase 4: Sub-block Sieve + ULP + Hadamard Assembly",
|
| 611 |
+
i + 1,
|
| 612 |
+
n_blocks,
|
| 613 |
+
f"blk {i+1}/{n_blocks} ({rate:.1f} blk/s, ETA {eta:.1f}s) "
|
| 614 |
+
f"rmse={cur_rmse:.6e} rmse/sigma={cur_rmse/max(sigma, 1e-15):.4f} "
|
| 615 |
+
f"floors(cand={candidate_floor_used}, fac={factor_floor_used})",
|
| 616 |
+
rmse=cur_rmse,
|
| 617 |
+
sigma=sigma,
|
| 618 |
+
temperature=temperature,
|
| 619 |
+
cand_floors=candidate_floor_used,
|
| 620 |
+
fac_floors=factor_floor_used,
|
| 621 |
+
rate=rate,
|
| 622 |
+
eta=eta,
|
| 623 |
+
)
|
| 624 |
|
| 625 |
if cfg.apply_dc_carry and (cfg.dc_lambda > 0.0 or cfg.dc_decay > 0.0):
|
| 626 |
+
_check_stop()
|
| 627 |
+
_emit(
|
| 628 |
+
"Phase 4.8: Sequential Row-Aware DC Residual Nudge",
|
| 629 |
+
n_blocks,
|
| 630 |
+
n_blocks,
|
| 631 |
+
f"Cancelling cumulative row DC residuals (row_width={row_width or QK_K})",
|
| 632 |
+
sigma=sigma,
|
| 633 |
+
temperature=temperature,
|
| 634 |
+
)
|
| 635 |
blocks = _apply_dc_nudge(X, W, blocks, cfg, row_width)
|
| 636 |
|
| 637 |
total_sse = 0.0
|
|
|
|
| 644 |
else:
|
| 645 |
weighted += float(np.dot(W[i].astype(np.float64), e * e))
|
| 646 |
|
|
|
|
| 647 |
rmse = float(np.sqrt(total_sse / x.size))
|
| 648 |
stats = TensorStats(
|
| 649 |
n_blocks=n_blocks,
|
|
|
|
| 656 |
factor_floor_used=factor_floor_used,
|
| 657 |
candidate_floor_used=candidate_floor_used,
|
| 658 |
)
|
| 659 |
+
_emit(
|
| 660 |
+
"Phase 5: Tensor Complete",
|
| 661 |
+
n_blocks,
|
| 662 |
+
n_blocks,
|
| 663 |
+
f"Done: blocks={n_blocks} rmse={rmse:.6e} rmse/sigma={stats.rmse_over_sigma:.5f} "
|
| 664 |
+
f"wSSE={weighted:.5e} temp={temperature:.3e} "
|
| 665 |
+
f"floors(cand={candidate_floor_used}, fac={factor_floor_used})",
|
| 666 |
+
rmse=rmse,
|
| 667 |
+
sigma=sigma,
|
| 668 |
+
temperature=temperature,
|
| 669 |
+
cand_floors=candidate_floor_used,
|
| 670 |
+
fac_floors=factor_floor_used,
|
| 671 |
+
)
|
| 672 |
scales, qs, dm = _stack_blocks(blocks)
|
| 673 |
factor_objectives = np.array([r.objective for r in standalone], dtype=np.float64)
|
| 674 |
result = QuantizedTensor(
|