Repository navigation
feat(gguf): full CPU coverage for all ggml tensor types + optimized native inference - #3434
Merged
Merged
Conversation
- Fold every ggml quant type into the alias/config/lifecycle: Q4_1, Q5_0, Q5_1, Q8_1, Q2_K*, Q3_K*, Q8_K, all IQ*, plus quality variants (q2_k_s/m, q3_k_s/m/l) and explicit mxfp4/nvfp4 formats. - Quantize dispatch: gguf lib -> internal impls (new Q8_1/Q8_K) -> ggml_quantize_chunk for the remaining K/IQ types (guarded by an explicit allowlist; upstream has no quantizer for Q8_1/Q8_K and aborts). - Dequantize dispatch: internal impls -> ggml dequantize_row_* -> gguf lib; verified bit-identical across all three for every format. - GGUFCppKernel: new CPU inference path through native ggml SIMD mul_mat with per-(rows,dtype,qtype) autotuning against the torch fused/dequant paths (ggml wins 3-100x on AVX2). Q8_1/Q8_K excluded: upstream mul_mat has no F32 vec_dot for them and segfaults. - llama-cpp-python unexported enum values (Q8_1=9, TQ1_0=34, TQ2_0=35) mapped by id fallback. - pyproject: new 'gguf' extra pinning gguf>=0.19.0 and llama-cpp-python>=0.3.36 (latest stable releases). - tests/test_gguf_all_formats.py: 224 cases covering roundtrip quantize/dequantize, oracle equivalence vs gguf lib + ggml, torch and cpp kernel forwards, config round-trips, and quantized-storage checks. - README: document full format coverage and the optimized CPU path.
Contributor
|
I'll fix CI failures and address comments from users with write access that start with 'Devin'.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Extends GGUF CPU quantization, dequantization, loading and inference to all 37 supported aliases. Adds a
ggufoptional extra with stable minimum versionsgguf>=0.19.0andllama-cpp-python>=0.3.36; retainsbitsandbytes>=0.50.2.What Changed
quantization/config.py):_GGUF_BITS_ALIAS_INFOnow covers all 37 aliases —q4_1,q5_0,q5_1,q8_1,q2_k/q3_k/q4_k/q5_k/q6_k/q8_k(+_s/_m/_lquality variants), alliq*,tq1_0/tq2_0,mxfp4,nvfp4,q1_0,q2_0,q1_0_g128.bits=3now defaults toq3_k. Variant grammar extended (xxs/xs/s/m/nl,mxfp/nvfpversions) so public format tokens likeq_k_sormxfp4round-trip correctly.qlinear/gguf.py,qlinear/gguf_cpp.py):gguflib → internal impls (newQ8_1/Q8_K) →ggml_quantize_chunkfor remaining K/IQ types. The ggml path is guarded by an explicit allowlist because upstream has no quantizer forQ8_1/Q8_Kandassert(false)aborts the process on them.Q8_1,Q8_K,I8/I16/I32/I64/F64) → ggmldequantize_row_*→gguflib. Independent dequantization comparisons usertol=atol=1e-6; this is a floating-point tolerance, not a bit-identity claim.GGUFCppKernel): nativeggml_mul_maton the packed weight (ggml's own SIMD vec_dot kernels; on this 8-core AVX2 Xeon it is 3-25x faster than the torch fused path and 10-100x faster than dense dequant+matmul), autotuned per(rows, dtype, qtype)against the torch fused/dequant paths withGPTQMODEL_GGUF_CPP_NATIVE_MATMULoverride.Q8_1/Q8_Kare excluded — upstream exposes no F32-sourcevec_dotfor them and segfaults; they run the torch path. Weights stay quantized between calls (no persistent dense cache).llama-cpp-pythondoes not exportGGML_TYPE_Q8_1/TQ1_0/TQ2_0constants; enum ids are supplied by a documented fallback table.GGUFTorchLinear,GGUFCppKernel,GGUFCudaKernelSUPPORTS_BITSextended to[1,2,3,4,5,6,8].Tests
tests/test_gguf_all_formats.py— 700 collected cases over all 37 aliases. Covers FP32/FP16/BF16 native, dense and fused CPU paths; independent packed-weight and A8 activation oracles; repeated-forward persistent-state inspection; complete config serialization; Q8 boundary bytes; invalid buffers; empty/padded inputs; forced fallback; cache clearing; and concurrent native calls.type_size(e.g.Q8_K=292 B/256,IQ1_M=56 B/256,NVFP4=36 B/64).The 24 skips are 12 intentionally unsupported native Q8_1/Q8_K cases and 12 unavailable bitsandbytes CPU packed-extension cases; Q8_1/Q8_K fallback tests pass. Tests ran on Linux x86_64 CPU with Torch 2.14.1+cpu. No standalone static type-checker is configured in this repo; syntax compilation was run, not a claim of full static type coverage.
Full-model
test_gguf_qlinear_llama.pyrequires/monster/data/model/Llama-3.2-1B-Instruct, absent here. CUDA, AVX512/AMX and full-model generation were not validated on this AVX2 host. An earlier broader check found the unrelated transformersDummyCache.get_max_lengthcompatibility failure.Kernel Accuracy Requirements
ggufpackage and Torch byte decoders for Q1_0/Q2_0/Q8_1/Q8_K, plus native dequantizers where exported.2 * block_size - 3(61–509), including padding and multiple packed blocks. FP32 arithmetic is independently reconstructed before the specified output cast. Native/fused FP16/BF16 comparisons use the same final output rounding; dense Torch uses weights cast to the activation dtype.rtol=atol=2e-3.Maximum absolute error against the applicable packed-weight oracle with exactly Q8-representable activations:
Native ggml additionally quantizes activations to Q8 for its SIMD dot kernels. The random-input tests compare that arithmetic to an independent Torch A8 oracle at
rtol=atol=2e-3, separately from activation quantization loss. Max absolute arithmetic error is 0.0001683 / 0.0008669 / 0.0003659 for FP32 / FP16 / BF16 inputs, measured before the output cast. On the FP32 random-input fixture, native-vs-weight-only Torch max absolute drift is 0.026065; it is not just accumulation noise and does not satisfy a strict 0.002 weight-only equivalence guarantee. UseGPTQMODEL_GGUF_CPP_NATIVE_MATMUL=0when weight-only semantics are required.Repeated forwards retain only the packed
qweightbuffer:out_features * padded_blocks * type_sizebytes (544–9,344 bytes in the oracle matrix), with no additional Python-owned dense/expanded tensor state. Dense fallback reconstruction is temporary FP32 scratch (up to 32,768 bytes for these shapes), plus its output cast; fused reconstruction uses bounded block chunks. Native CPU graph buffers, including their packed-weight copy, are freed after each call.Review Requirements
Notes
GGUFCudaKernelcoverage for the new formats (CUDA path unchanged in this PR), oneDNNbf16x3is still wired into the fused torch path for AVX512 boxes.Q8_1/Q8_Kare inference-side only even upstream (KV-cache/aux types); we still ship internal quantizers so files can be produced, but matmul stays on the torch path.Link to Devin session: https://app.devin.ai/sessions/bca72424bc9b493e8f91ef329ab9ff9b
Open in Devin Desktop: https://app.devin.ai/desktop/session/bca72424bc9b493e8f91ef329ab9ff9b?variant=devin
Requested by: @Qubitium