FAIE / fast_dequant.py
abuz8studios's picture
FAIE engine code + docs (no weights)
421f9b7 verified
Raw History Blame Contribute Delete
1.99 kB
"""
Vectorized GGUF dequantization.
FIXED 2026-07-26: the previous implementation assumed a SEQUENTIAL 2-bit packing
(element e <- byte e//4, bits 2*(e%4)); ggml's real K-quant layout is bit-planed
(element e <- byte (e//128)*32 + e%32, bits 2*((e%128)//32)), and Q3_K
additionally uses offset-32 scales in a different 6-bit packing plus hmask bit
order (byte e%32, bit e//32). Independent check vs gguf.quants.dequantize showed
cos 0.06 (Q2_K) / 0.003 (Q3_K) for the old code — deterministic garbage.
These functions now delegate to gguf.quants.dequantize (the same code the
llama.cpp project maintains next to the C reference), keeping the old
signatures. See quant_repack.py for the matching CUDA-kernel-side repack.
"""
import numpy as np
from gguf.constants import GGMLQuantizationType
from gguf.quants import dequantize
QK_K = 256
Q2_K_BLOCK_SIZE = 84
Q3_K_BLOCK_SIZE = 110
Q6_K_BLOCK_SIZE = 210
def _as_u8(raw_data):
if isinstance(raw_data, np.ndarray):
return raw_data.reshape(-1).view(np.uint8)
return np.frombuffer(raw_data, dtype=np.uint8)
def _dequant(raw_data, n_elements, block_bytes, qtype):
data = _as_u8(raw_data)
n_blocks = n_elements // QK_K
if data.size < n_blocks * block_bytes:
n_blocks = data.size // block_bytes
blocks = data[:n_blocks * block_bytes]
out = dequantize(blocks, qtype).astype(np.float32, copy=False).reshape(-1)
return out[:n_elements]
def dequant_q2k_fast(raw_data, n_elements):
"""Correct Q2_K dequantization (ggml layout)."""
return _dequant(raw_data, n_elements, Q2_K_BLOCK_SIZE, GGMLQuantizationType.Q2_K)
def dequant_q3k_fast(raw_data, n_elements):
"""Correct Q3_K dequantization (ggml layout)."""
return _dequant(raw_data, n_elements, Q3_K_BLOCK_SIZE, GGMLQuantizationType.Q3_K)
def dequant_q6k_fast(raw_data, n_elements):
"""Correct Q6_K dequantization (ggml layout)."""
return _dequant(raw_data, n_elements, Q6_K_BLOCK_SIZE, GGMLQuantizationType.Q6_K)