CompressedGemma commited on
Commit
cc839cc
·
verified ·
1 Parent(s): dc86eef

Upload q4_0.py

Browse files
Files changed (1) hide show
  1. q4_0.py +33 -4
q4_0.py CHANGED
@@ -27,6 +27,7 @@ per 18-byte block = 4.5 bpw):
27
 
28
  from __future__ import annotations
29
 
 
30
  from math import ceil
31
  import numpy as np
32
 
@@ -38,7 +39,7 @@ except ImportError: # pragma: no cover
38
  from .anneal import thermal_refine_q4_0, thermal_spectral_lams
39
  from .config import HPCConfig
40
  from .cuda_backend import cuda_is_available
41
- from .factored import CAND_TO_QUHIT, MULTS_D
42
  from .fp16 import from_fp16_bits, nearest_int, to_fp16_bits
43
  from .sieve import sieve_measure_chain, subblock_chain_edges
44
  from .spectral import pin_dc_codes_uniform, pin_dc_codes_uniform_cuda
@@ -50,6 +51,16 @@ Q4_N_CAND = 24
50
  Q4_N_STATES = 6
51
  Q4_N_LEVELS = 16
52
 
 
 
 
 
 
 
 
 
 
 
53
 
54
  def dequantize_q4_0_bytes(raw: bytes | np.ndarray, n_blocks: int) -> np.ndarray:
55
  blocks = np.frombuffer(raw, dtype=np.uint8).reshape(n_blocks, Q4_0_BLOCK_BYTES)
@@ -354,6 +365,9 @@ def _quantize_q4_0_hpc_cuda(
354
 
355
  # 3. 6-State Sieve + 6-State Viterbi DP:
356
  best_cand_np = _q4_sieve_and_viterbi(cand_err_t.cpu().numpy(), cfg)
 
 
 
357
  best_cand_t = torch.from_numpy(best_cand_np).to(dev)
358
  rows = torch.arange(B, device=dev)
359
  d_sel = cand_d[rows, best_cand_t]
@@ -374,6 +388,7 @@ def _quantize_q4_0_hpc_cuda(
374
  e_u = X[:, None, :] - all_d[:, :, None] * (q_u.to(torch.float32) - 8.0)
375
  sse_u = torch.sum(W[:, None, :] * e_u * e_u, dim=2)
376
  pick_u = torch.argmin(sse_u, dim=1)
 
377
  best_d16 = all_b[rows, pick_u]
378
  best_d = all_d[rows, pick_u]
379
  best_q = q_u[rows, pick_u].to(torch.int64)
@@ -565,9 +580,14 @@ def quantize_tensor_q4_0(
565
  weights: np.ndarray,
566
  importance: np.ndarray | None = None,
567
  cfg: HPCConfig | None = None,
568
- chunk_blocks: int = 131072,
569
  ) -> tuple[bytes, int, float]:
570
- """Quantize a tensor to GGML Q4_0 using the full HPC V2 pipeline."""
 
 
 
 
 
571
  cfg = cfg or HPCConfig()
572
  x = np.asarray(weights, dtype=np.float32).ravel()
573
  if x.size == 0 or x.size % QK4_0 != 0:
@@ -583,10 +603,19 @@ def quantize_tensor_q4_0(
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
  )
589
  dev = torch.device("cuda" if cfg.device == "auto" else cfg.device) if use_cuda else None
 
 
 
 
 
 
 
 
590
 
591
  chunks: list[bytes] = []
592
  total_sse = 0.0
 
27
 
28
  from __future__ import annotations
29
 
30
+ import logging
31
  from math import ceil
32
  import numpy as np
33
 
 
39
  from .anneal import thermal_refine_q4_0, thermal_spectral_lams
40
  from .config import HPCConfig
41
  from .cuda_backend import cuda_is_available
42
+ from .factored import MULTS_D
43
  from .fp16 import from_fp16_bits, nearest_int, to_fp16_bits
44
  from .sieve import sieve_measure_chain, subblock_chain_edges
45
  from .spectral import pin_dc_codes_uniform, pin_dc_codes_uniform_cuda
 
51
  Q4_N_STATES = 6
52
  Q4_N_LEVELS = 16
53
 
54
+ _log = logging.getLogger(__name__)
55
+
56
+ # Chunk sizes (in 32-weight blocks). The CUDA default keeps the historical
57
+ # reference chunk (131072 blocks * 32 weights = 4,194,304 weights per chunk);
58
+ # the CPU default is scaled back so the vectorized numpy temporaries
59
+ # ((B, 24, 32) candidate-error fields) stay cache-resident instead of
60
+ # allocating multi-hundred-MB arrays per chunk.
61
+ Q4_0_CHUNK_BLOCKS_CUDA = 131072
62
+ Q4_0_CHUNK_BLOCKS_CPU = 8192
63
+
64
 
65
  def dequantize_q4_0_bytes(raw: bytes | np.ndarray, n_blocks: int) -> np.ndarray:
66
  blocks = np.frombuffer(raw, dtype=np.uint8).reshape(n_blocks, Q4_0_BLOCK_BYTES)
 
365
 
366
  # 3. 6-State Sieve + 6-State Viterbi DP:
367
  best_cand_np = _q4_sieve_and_viterbi(cand_err_t.cpu().numpy(), cfg)
368
+ del cand_err_t, e_c, q_c, qi_c, sh_c, sse_c
369
+ if cfg.use_spectral and (lam_dc > 0.0 or lam_vw > 0.0):
370
+ del v_c, dc_c
371
  best_cand_t = torch.from_numpy(best_cand_np).to(dev)
372
  rows = torch.arange(B, device=dev)
373
  d_sel = cand_d[rows, best_cand_t]
 
388
  e_u = X[:, None, :] - all_d[:, :, None] * (q_u.to(torch.float32) - 8.0)
389
  sse_u = torch.sum(W[:, None, :] * e_u * e_u, dim=2)
390
  pick_u = torch.argmin(sse_u, dim=1)
391
+ del e_u, q_u, qi_u, sh_u, sse_u
392
  best_d16 = all_b[rows, pick_u]
393
  best_d = all_d[rows, pick_u]
394
  best_q = q_u[rows, pick_u].to(torch.int64)
 
580
  weights: np.ndarray,
581
  importance: np.ndarray | None = None,
582
  cfg: HPCConfig | None = None,
583
+ chunk_blocks: int | None = None,
584
  ) -> tuple[bytes, int, float]:
585
+ """Quantize a tensor to GGML Q4_0 using the full HPC V2 pipeline.
586
+
587
+ ``chunk_blocks`` (32-weight blocks per chunk) defaults to
588
+ ``Q4_0_CHUNK_BLOCKS_CUDA`` on the GPU path and the cache-resident
589
+ ``Q4_0_CHUNK_BLOCKS_CPU`` on the CPU path.
590
+ """
591
  cfg = cfg or HPCConfig()
592
  x = np.asarray(weights, dtype=np.float32).ravel()
593
  if x.size == 0 or x.size % QK4_0 != 0:
 
603
  else:
604
  W_raw = None
605
 
606
+ cuda_ok = cfg.device != "cpu" and cuda_is_available()
607
+ use_cuda = cuda_ok and (
608
  cfg.device.startswith("cuda") or (cfg.device == "auto" and n_blocks >= 64)
609
  )
610
  dev = torch.device("cuda" if cfg.device == "auto" else cfg.device) if use_cuda else None
611
+ if chunk_blocks is None:
612
+ chunk_blocks = Q4_0_CHUNK_BLOCKS_CUDA if use_cuda else Q4_0_CHUNK_BLOCKS_CPU
613
+ chunk_blocks = max(1, int(chunk_blocks))
614
+ _log.info(
615
+ "Q4_0 routing: cfg.device=%r cuda_is_available=%s n_blocks=%d -> %s (chunk_blocks=%d)",
616
+ cfg.device, cuda_ok if cfg.device != "cpu" else "n/a", n_blocks,
617
+ f"CUDA[{dev}]" if use_cuda else "CPU", chunk_blocks,
618
+ )
619
 
620
  chunks: list[bytes] = []
621
  total_sse = 0.0