code wiki / (root) / nx_quant_q4k.nx

nx_quant_q4k.nx

buildroot/runtime/nx_quant_q4k.nx

10622 B277 linesdepth 4pulls 4 transitivereach 1 importersview sourcekind librarytopic quant
docsdependenciesstructsconstsfunctions

about

nx_quant_q4k.nx -- hierarchical k-quants (ggml q4_K shape). Improvement over nx_quant_block.nx (q4_0 shape): q4_0: one scale per 32-value block. All 32 values share the same dynamic range; groups with wildly different magnitudes waste precision (small-magnitude groups get coarse steps). q4_K: super-block of 256 values = 8 groups of 32. TWO scales: a SUPER scale per super-block + a LOCAL scale per group. The hierarchy lets each group adapt its precision while still sharing the super-block magnitude estimate -- which empirically halves worst-case error vs q4_0 at near-identical storage. Concrete win for the user's "VRAM optimization realistic tracking": This is the realisation of the Q-002 row -- q4_K + AWQ calibration -- which the doc projected at 1-2% quality loss vs q4_0's 5-7%. Storage per 256 values: 1 super_d (i64) = 8 bytes 8 group_d_local (i64 each) = 64 bytes 128 packed nibbles (256 values) = 128 bytes Total = 200 bytes vs dense 256 * 8 = 2048 bytes -> 10.24x compression Reconstruction: value = nibble * group_d_local * super_d / Q10 Algorithm-led precision: 1. Find super_max = max(|values|) across the 256-value super-block 2. super_d = super_max / 127 (range of effective combined scale) 3. For each 32-value group: a. find group_max = max(|values|) in the group b. group_d_local = (group_max * Q10) / (7 * super_d) (so that nibble of 7 reconstructs to group_max) 4. For each value: nibble = round(value * Q10 / (group_d_local * super_d)) Hierarchy benefit: a group with group_max << super_max gets a SMALL

dependencies 4 imports · 1 importers

nx_syscalls.nx nx_tier.nx nx_tensor.nx nx_quant_block.nx nx_quant_q4k.nx nx_quant_q4k_test.nx

imports: nx_syscalls.nxnx_tier.nxnx_tensor.nxnx_quant_block.nx

imported by: nx_quant_q4k_test.nx

structs

87struct NxQuantQ4K

consts

59const NX_MAGIC_1024: i64 = 1024
61const NX_Q4K_Q10: nx_int = 1024
62const NX_Q4K_SUPER_VALUES: nx_int = 256 // values per super-block
63const NX_Q4K_GROUP_VALUES: nx_int = 32 // values per group
64const NX_Q4K_GROUPS: nx_int = 8 // groups per super-block
65const NX_Q4K_NIBBLE_MAX: nx_int = 7 // [-7..+7]
66const NX_Q4K_SUPER_RANGE: nx_int = 127 // super_d denominator
69const NX_Q4K_BYTES_PER_SUPER: nx_int = 200
73const NX_Q4K_OK: nx_int = 0
74const NX_Q4K_ERR_BAD_LEN: nx_int = 1 // n not multiple of 256
75const NX_Q4K_ERR_BAD_DTYPE: nx_int = 2
76const NX_Q4K_ERR_SHAPE_MISMATCH: nx_int = 3
77const NX_Q4K_N_VERDICTS: nx_int = 4
95const NX_Q4K_STRUCT_BYTES: nx_int = 40 // 5 fields * 8

functions

79func nx_q4k_verdict_is_valid(v: nx_int) -> nx_int
called by 1: main
97func nx_q4k_alloc(n_values: nx_int) -> *NxQuantQ4K
called by 2: nx_q4k_quantize_tensormain calls 1: sys_mmap
118func _q4k_pack_nibble(qb: *NxQuantQ4K, value_idx: nx_int, signed_nib: nx_int) -> nx_int
called by 1: nx_q4k_quantize
134func _q4k_unpack_nibble(qb: *NxQuantQ4K, value_idx: nx_int) -> nx_int
called by 1: nx_q4k_dequantize
148func _q4k_abs(x: nx_int) -> nx_int
called by 1: nx_q4k_quantize
170func nx_q4k_quantize(values: *i64, n: nx_int, qb: *NxQuantQ4K) -> nx_int
237func nx_q4k_dequantize(qb: *NxQuantQ4K, values_out: *i64, n: nx_int) -> nx_int
254func nx_q4k_compression_ratio_q10(qb: *NxQuantQ4K) -> nx_int
called by 1: main
263func nx_q4k_quantize_tensor(t: *NxTensor) -> *NxQuantQ4K
272func nx_q4k_dequantize_tensor(qb: *NxQuantQ4K, t: *NxTensor) -> nx_int