Skip to content

Latest commit

 

History

History
347 lines (245 loc) · 32.6 KB

File metadata and controls

347 lines (245 loc) · 32.6 KB

quant.cpp

quant.cpp

Beyond RAG: 문서 전체를 노트북에 통째로 로드하세요.

Chunking은 작은 컨텍스트 윈도우를 위한 임시방편이었습니다. 우리는 그것을 불필요하게 만들었습니다.
6.4× KV 압축으로 16GB Mac에서 전체 문서 이해가 가능합니다.
C 파일 하나(16K줄), 외부 의존성 0.

PyPI Python Release License Tests Guide


빠른 시작

Ollama 스타일 CLI (v0.12.0+):

pip install quantcpp

quantcpp pull qwen3                     # Qwen3-4B Q4_K_M 다운로드 (~2.5 GB)
quantcpp run qwen3                      # 대화형 채팅
quantcpp serve qwen3 -p 8080            # OpenAI 호환 HTTP 서버 (SSE 스트리밍)
quantcpp client "안녕"                   # 스트리밍 클라이언트 → :8080 서버
quantcpp list                           # 캐시된 모델 목록

추천 기본 모델: Qwen3-4B (4B params, MMLU 73, M3에서 4.5 tok/s). 최고 품질 AND 최고 속도 — Q4 NEON fused dot 경로로 Phi-3.5-mini보다 2.4배 빠릅니다. 다른 별칭: phi3.5, smollm2, llama3.2:1b. run/serve 첫 실행 시 자동 다운로드.

serve는 OpenAI 호환 POST /v1/chat/completions 엔드포인트를 8080 포트에 제공합니다 — 클라이언트가 "stream": true를 보내면 SSE 토큰 단위 스트리밍, 생략하면 단일 JSON 응답. 내장 quantcpp client는 두 모드 모두 지원 (기본: 스트리밍, --no-stream: 단일 응답).

한 줄 질문:

quantcpp run qwen3 "중력이란 무엇인가요?"

Python API (3줄):

from quantcpp import Model
m = Model.from_pretrained("Qwen3-4B")
print(m.ask("중력이란 무엇인가요?"))

API 키 없음. GPU 없음. 설정 없음. 모델은 ~/.cache/quantcpp/에 캐시됩니다. 지원되는 architecture와 모델 선택 가이드는 docs/supported_models.md를 참고하세요. 브라우저에서 바로 체험 → · 작동 원리 가이드 →


핵심 발견: Document-QA 7/7 vs Chunk-RAG 0/7

Llama 3.2 3B Q8_0로 측정한 직접 비교 결과:

방법 정확도 할루시네이션
Chunk-RAG (잘못된 청크 검색) 0/7 7개 모두
전체 문서 (FP32 KV) 7/7 없음
전체 문서 (6.4x 압축 KV) 7/7 없음 — 품질 손실 0

Chunk-RAG가 잘못된 섹션을 검색하면, 모델은 "모른다"고 하지 않고 그럴듯한 거짓을 생성합니다:

  • "CTO는 누구인가?" → "John Smith" (실제: Maria Santos)
  • "매출은?" → "$1,000,000" (실제: 8억 4700만)
  • "R&D 비율은?" → "순이익의 15%" (실제: 매출의 14%)

6.4x KV 압축으로 전체 문서를 한 번에 로드하면, 모델은 multi-hop 추론까지 정확히 답합니다 (예: "성장 지역에 영향을 주는 위험은?" → 환율 변동, Section 3 + Section 5 정보 연결 필요).

핵심: KV 압축은 단순한 메모리 절감이 아니라 근본적으로 다른 RAG 접근을 가능하게 합니다. RAG는 "어떤 문서를 볼지" 결정하고, long-context는 "그 문서를 얼마나 깊이 이해할지" 결정합니다. 전체 결과: bench/results/document_level_rag_breakthrough.md

v2 후속 — Working Memory Cliff (2026-04-11): v1 결과를 더 큰 grid로 확장 측정했습니다 (1B/3B 모델, ctx 256-2048, 204 NIAH trials + FP32-weights 통제 실험). 두 모델 모두 명목 128K context window의 1% 미만에서 sharp cliff가 존재합니다 (1B Q8 cliff 512-1024, 3B Q4 cliff 1024-1280을 step function으로). 6.4× KV 압축은 20개 cell 중 18개에서 fp32 baseline과 bit-for-bit 일치 — cliff는 model property이지 KV/weight quantization artifact가 아닙니다. 정직한 재해석: Beyond RAG는 유효 working memory 안에 들어가는 문서에 대해서만 동작하며, 그 크기는 명목 context window의 100분의 1에서 1000분의 1입니다. 전체 tech report: docs/paper/working-memory-cliff.md. HuggingFace blog post draft: docs/paper/hf-blog-draft.md.

v3.21 ★★★ Qwen3.6-35B 117-토큰 cliff BREAK — MoE softmax temperature, qwen35moe에서 기본 자동 적용 (2026-04-22): 한 knob — TQ_MOE_ROUTE_TEMP=2.0 — 으로 40+ 라운드 미해결이던 Qwen3.6-35B-A3B의 "It could do math! It could do math!" 117-토큰 반복 루프 제거. qwen35moe arch 자동 감지 + 기본값 자동 적용 (기존 auto-serial 모드와 동일 패턴), 사용자가 env 없이도 기본 적용. Llama/Phi/Gemma/Qwen3 non-hybrid에는 영향 없음. drift-trigger 프롬프트 -n 200 T=0 temperature 스위프: 기본 T=1.0 → 117 루프; T=1.5 → 더 일찍 87-토큰 cliff; T=1.8 → 여전; T=2.0 → 200 토큰 Alex+슬픈-나무 이야기 완주, rep-loop 없음; T=2.5 → 200 토큰 완주; T=3.0 → 과도 분산 114 재발. Sweet spot T=2.0 ~ 2.5. 인과: peaky MoE 라우팅이 DeltaNet 지속 상태와 positive feedback loop 형성. softmax 분산하면 루프 형성 불가. 26 라운드 arc: R16-R19 per-layer DeltaNet state reset은 null, R24에서 Qwen3.5-4B (DeltaNet + dense FFN, MoE 없음) 같은 프롬프트 → drift 전혀 없음 → MoE 단독 원인 확정, R25 MoE router probe에서 L4 0.80+ collapse 발견, R26 temperature ablation으로 cliff 차단. 회귀 23/23 PASS (T=2.0 포함), "Paris" factual probe 정상. 150+ 토큰 tail 여전히 character-level degrade — hard cliff 제거, essay-length은 추가 작업 필요. Opt-in, 기본 미변경. 권장: TQ_MOE_ROUTE_TEMP=2.0 ./build/quant Qwen3.6-35B-Q5_K_M.gguf -p "..." -n 200 --rep-penalty 1.3. 전체 리포트: bench/results/2026-04-22_moe_temp_cliff_break.md. v0.28.0.

v3.20 ★★ BPE encode/decode UTF-8 수정 — 국제 문자 silent 품질 재앙 해결 (2026-04-21): encode_byte_to_bpe_char / decode_bpe_token 에 있던 대칭 버그 두 개가 Llama-3 / Qwen3 계열 모든 모델에서 비ASCII 문자 (액센트, CJK, 키릴, byte-fallback 이모지)를 포함한 모든 프롬프트/출력을 조용히 깨뜨리고 있었습니다. 인코딩: GPT-2 direct-byte 코드포인트에 대해 ≥ 0x80 의 raw byte를 그대로 emit (독립형 바이트는 invalid UTF-8)하여 str_lookup이 매칭에 실패 → 문자가 byte-fallback을 통해 잘못된 저-ID 토큰으로 변환. 디코딩: U+0080-U+00FF 코드포인트를 UTF-8 인코딩 (c3 83)으로 출력, 실제 바이트 (0xC3)가 아님 → 출력 이중 인코딩 ("café" → "café"). 토큰 레벨 HF 참조 일치 검증: café/naïve/日本語/привет 모두 HF AutoTokenizer 와 byte-byte 일치. 새 tools/refparity/ 프레임워크의 A/B 출력 diff로 발견. quant.h single-header 에도 sync. scripts/test_tokenizer.sh 회귀 fixture 추가. 영향 범위: GPT-2 byte-level BPE (Llama-3.x, Qwen2.5/3.x/3.5/3.6); Gemma/Phi-3 SentencePiece 경로 영향 없음. 회귀 15/15 + 토크나이저 8/8 PASS. v0.27.0.

Qwen3.6-35B 16 GB Mac 실용 레시피: 장문 coherence 기준 현재 최선 구성은 Qwen3.6-35B-A3B-UD-Q5_K_M.gguf + --rep-penalty 1.3. "Once upon a time in a faraway land" (-n 200, T=0) 실측: 기본 설정은 117 토큰에서 반복 루프, Q5_K_M + rep-penalty는 200 토큰 전체 예산을 생성 후 말미에서만 완만하게 degrade. 35B DeltaNet drift 는 여전히 열린 아키텍처 조사 과제이나, 사용자가 지금 쓸 수 있는 최선.

v3.19 ★ DeltaNet L2-norm 공식이 ggml과 일치 — Qwen3.6 coherence +36% (2026-04-21): R26의 "eps 수정"은 올바른 진단이지만 잘못된 공식이었습니다. 우리는 1/sqrt(ss + eps)를 사용했지만 llama.cpp ggml_l2_norm1/max(sqrt(ss), eps)을 사용 — near-zero 입력에서 3 orders of magnitude 차이 (1e3 vs 1e6). 30 DeltaNet 레이어 × position 에서 K/Q under-scaling이 누적 → decode-length degradation. 수정: ggml과 정확히 일치. Qwen3.6-35B IQ4_XS auto-serial 실측 "Write a 300-word essay": 117 → 160 토큰 (+36%), coherent content 45 → 110 토큰. refs/llama.cpp/ggml/src/ggml-cpu/ops.cpp::ggml_compute_forward_l2_norm_f32 를 우리 l2_normalize와 직접 diff로 발견. 15/15 regression PASS. v0.26.0.

v3.18 Qwen3.6 auto-serial quality mode — 결정성 + 긴 coherence (2026-04-20): 발견: Qwen3.6-35B 멀티쓰레드 matmul은 T=0에서 비결정적 (동일 프롬프트 두 번 실행 = 다른 출력). 병렬 FP reduction 순서 변동이 30 MoE 레이어 × position feedback에서 누적 → top-1 argmax flip. 수정: qwen35moe+DeltaNet 하이브리드 자동 감지 후 -j 1 강제. 이전: 실행마다 결과 다름, 60-70 토큰 후 degrade. 이후: 결정적, coherent 범위 ~95 토큰으로 확장. 비용: 디코드 ~2-3× 느림 (3 t/s vs 8 t/s). Opt-out: TQ_NO_AUTO_SERIAL=1. 솔직한 한계: 1000+자 생성 완전 수정은 아직 아님 — 40 레이어 × 8-expert weighted sum × IQ4_XS 양자화 오차 누적이 결국 반복 루프로 귀결. 오늘 세션 요약: 7 릴리스로 7개 Qwen3.6 버그 클래스 해결. 비결정성 제거만으로도 실용 향상 충분함. v0.25.0.

v3.17 MoE SwiGLU exact expf — Qwen3.6 coherence 마진 (2026-04-20): MoE swiglu_fused가 Schraudolph 근사 (~2% 오차) 대신 exact expf 기본 사용. R27-29에서 DeltaNet에는 적용했지만 MoE는 fast_exp 유지 중이었음. 30 MoE 레이어 × 500+ 토큰에서 오차 누적. 수정 후 400-word Qwen3.6 프롬프트가 더 길고 다양한 continuation 생성. 속도 비용: 측정 불가 (SwiGLU 병목 아님; 280w에서 28-29s TTFT 동일). Opt-out: TQ_MOE_FAST_EXP=1. 500+ 단어 degradation 여전 (다원 버그 중 한 원인 해결). 15/15 regression PASS. v0.24.0.

v3.16 ★★ 긴 프롬프트 silent-truncation 수정 (2026-04-20): 4096 chars (~700 영어 단어) 이상 프롬프트가 tq_generate.c의 4096-token caller 버퍼에 의해 조용히 잘려나가고 있었습니다. BPE가 문자 단위로 먼저 토큰화되기 때문에 4096 cap이 merge 전에 적용되어 char 4096 이후 텍스트가 사라졌습니다. 수정: 32768로 확장 + dynamic sizeof. OpenMythos reference-diff 진단: HF Qwen3-0.6B가 561-word 문서를 698 토큰으로, 우리 엔진은 684로 토큰화 — 우리 마지막 토큰 decoded = ". The abacus" (텍스트 시작 부분!), truncation 증명. 수정 후 Qwen3.5-4B (dense hybrid) 561-word 문서 coherent: "the future of AI is not just about what we can do with it - it's about how we think about what matters most to us." ✓. Qwen3.6-35B MoE hybrid는 여전히 561w에서 repetition loop — 버그가 MoE feedback accumulation at long positions로 격리됨 (DeltaNet + 토크나이저는 Qwen3.5-4B 성공으로 정상 입증). 15/15 regression PASS. v0.23.0: docs/RELEASE_NOTES.md.

v3.15 Qwen3.6 chunked batched prefill (+30% TTFT, 2026-04-20): Batched MoE dispatch를 8개 토큰 청크로 분할 (TQ_MOE_BATCH_CHUNK 조정 가능) — 소형-N 안전 영역을 유지하며 batched 속도 이득 대부분 회복. State (KV cache, DeltaNet ssm)가 이미 driver call 간 영속이므로 의미론적으로 올바름. Qwen3.6-35B IQ4_XS 실측: 44-word prose TTFT 12.6s → 7.0s (+44%), 280-word 38.0s → 29.4s (+29%), 동일한 정확한 요약. ~300 단어 문서까지 검증. 500+ 단어에서는 별개 accumulation 버그 (batched, per-token 모두 실패 — MoE scatter 버그와 다른 KV/DeltaNet-state 이슈). 15/15 regression PASS. v0.22.0: docs/RELEASE_NOTES.md.

v3.14 ★★★ Qwen3.6-35B 실질 사용 가능 — 16 GB Mac 문서 Q&A (2026-04-20): 마지막 Qwen3.6 버그 종료. tq_moe_forward_batch N≥40에서 (tq_forward_batch_moe_hybrid 내 batched MoE 커널) 격리. tq_forward per-token 경로는 동일 입력에서 완벽 출력. 수정: default를 opt-in (TQ_USE_MOE_BATCH=1)로 뒤집음. Qwen3.6-35B 44-word 자연문 + "Summarize in one sentence." — 이전 ! \ ` inteligت sWith …garbage — **이후**"Artificial intelligence, particularly through deep learning and large language models, has transformed how we create and interact with content…" ✓. 광범위 검증 5/8 PASS (나머지 "fail"도 모두 coherent 출력, 단지 테스트 키워드 부재). Trade-off: TTFT 12.6s per-token vs 4-7s batched — 정확성 우선. 세션 아크 전체: v0.19.0 BPE → v0.20.0 QK-norm + NEOX → v0.21.0 MoE opt-in. **6 Pillar 1 + 1.5 라운드에 R26-R50의 30+ empirical 라운드가 못 잡은 문제 모두 종료**. OpenMythos 영감 HF reference diff 방법론이 결정적. v0.21.0: [docs/RELEASE_NOTES.md`](docs/RELEASE_NOTES.md).

v3.13 ★★ NEOX RoPE + QK-norm — Qwen3 장문 coherence 복구 (2026-04-20): v3.12 BPE 수정 위에 2개 transformer-level 근본 원인 추가 해결. (1) tq_transformer.c:1204 — 순수 Qwen3 (0.6B~32B)는 q_norm/k_norm 필수. R40가 GGUF arch="qwen" 전체에 QK-norm 비활성화한 것은 Qwen3.5/3.6 DeltaNet HYBRID에만 옳음. QK-norm 없으면 layer 2에서 residual stream 폭발 (norm 5400 vs HF 10). (2) tq_ops.ctq_rope_neox 신규 — llama.cpp가 LLM_ARCH_QWEN3*LLAMA_ROPE_TYPE_NEOX/IMROPE (half-split pairs)로 매핑하지만 우리 엔진의 tq_ropetq_forward_batch는 LLaMA 스타일 interleaved pairs 사용. R34가 partial-rotary만 고침; 순수 Qwen3 full rotary + batched prefill은 여전히 틀림. 이제 arch 감지 후 올바른 RoPE 디스패치. Qwen3-0.6B 50-word 합성 입력: 이전 alyticsанcieaâ��à¹�… UTF-8 쓰레기, 이후 " Let me try to understand this" coherent. Qwen3.5-4B 자연문: "Artificial intelligence is a field of computer science…". Qwen3.6-35B 8-프롬프트 매트릭스: UTF-8 garbage 0건. 방법론 승리: HF reference diff (tools/pillar1/), refs/OpenMythos의 "ground truth와 먼저 비교" 원칙이 결정적. 6 라운드에 R26-R50의 30+ 경험적 라운드가 못 잡은 3개 근본 원인을 모두 종료. Regression 15/15 + tokenizer 4/4. v0.20.0: docs/RELEASE_NOTES.md.

v3.12 ★ BPE 근본 원인 수정 — Qwen3 family 완전 coherent (2026-04-20): src/engine/tq_tokenizer.c:1442에 한 줄 추가 (if (tokens[top.pos] < 0) continue;) 로 30+ 라운드의 "Qwen3 drift" 모든 증상의 진짜 원인 제거. 버그: BPE heap merge에서 다른 merge의 RIGHT neighbor로 죽은 position이 gen[] bump 없이 tokens[P]=-1만 되어, 오래된 heap entry가 죽은 slot을 부활시키며 linked list 오염 → 토큰 문자 중복/손실. HF reference 비교로 확인: 우리 엔진이 "Hello"[32713="Hel", 654="ll"] = "Helll" (문자 5개: H,e,l,l,l — 'o' 대신 'l')로 인코딩; HF는 [9707="Hello"] 정상. 다운스트림 결과: Qwen3.6-35B 40+ 단어 프롬프트가 완벽한 Python 코드 + 완전한 서사문 생성 (이전 garbage); Phi-3.5 "What is 2+2?"가 "The sum of 2 and 2 is equal to four." 정답 (이전 "tti" 환각). 방법론: Python HF reference diff가 3 라운드 만에 발견. Regression 15/15 + 새 토크나이저 테스트 4/4. 전체 before/after 증명: bench/results/2026-04-20_bpe_fix_proof.md. quant.h 단일 헤더는 naive O(n²) BPE 사용으로 영향 없음.

v3.11 TTFT/decode 분리 + 데일리 드라이버 픽 (2026-04-20): CLI 출력이 TTFT | decode로 분리되어, 짧은 쿼리에서 cold-start에 지배당하는 "overall tok/s" 대신 prefill latency와 sustained decode를 개별적으로 보여줍니다. 16 GB M1 Pro CPU-only warm 실측: Phi-3.5 Q4_K_M TTFT 2.3s / decode 14.5 t/s (짧은 대화), Llama-3.2-3B Q8→Q4 TTFT 0.97s / decode 29.0 t/s (one-shot 코드/수학), Qwen3.6-35B IQ4_XS TTFT 1.83s / decode 10.5 t/s (35B MoE 품질 장문). Decode는 모델 성질, TTFT는 warmup 성질 — 같은 명령 두 번 실행하면 두 번째부터 warm 수치. 3-모델 매트릭스 + 용도별 추천: bench/results/2026-04-20_ttft_daily_driver.md.

v3.10 Qwen3.x 모든 형식 승리 (2026-04-20): 두 구조적 수정이 Qwen3.5/3.6의 장문 드리프트를 완전히 제거. (1) NEOX-style partial RoPE — Qwen3.5/3.6은 LLAMA_ROPE_TYPE_IMROPE (NEOX half-split (q[i], q[i+rope_pairs])). (2) Arch-conditional QK-norm — Gemma 4 필수, Qwen family 비활성화. Qwen3.6-UD-IQ4_XS (--chat, T=0): "Once upon a time" n=60 → 60-token 완전 스토리, def fibonacci(n):정확한 Python, haiku/list/팩트 모두 작동. 15/15 regression PASS. v0.17.0: docs/RELEASE_NOTES.md.

v3.9 Qwen3.6 Q5_K_M on 16 GB Mac — 최초 엔진 (2026-04-19): tq_model.c auto-policy MADV + q5k_int_dot_worker NEON vshlq_u8 qh 추출로 26.5 GB Q5_K_M GGUF16 GB M1 Pro에서 로드 + 추론됩니다. RSS 9.65 GB (non-expert WILLNEED = 2.50 GB, routed experts OS 관리 = 22.13 GB, MoE K=8/N=256 희소성 덕분). Decode: warm 7.9 t/s (대화 실용권). llama.cpp는 같은 하드웨어에서 동일 파일 OOM. NEON SHL 기반 5번째 비트 추출 (AND+CEQ+AND → SHL+AND)로 Q5_K cold decode +40%. 전체 Qwen3.6 5-tier 매트릭스: bench/results/2026-04-19_qwen36_quant_matrix_16gb.md. v0.16.0 릴리스 노트: docs/RELEASE_NOTES.md.

v3.8 Mission A 완료 — MoE batched prefill 기본 ON (2026-04-19): 3단계 Step-3 라운드로 token-grouped MoE batched dispatch 완성. tq_moe_forward_batch (3-phase: batch-route → inverse index → expert-wise batched gather/matmul/scatter), tq_forward_batch_moe_hybrid (per-token DeltaNet + self-attn, batched MoE FFN), cross-expert parallel, batched shared expert, tq_tp_run_dynamic FCFS atomic queue. 측정 결과 (Qwen3.6-UD-Q3_K_S, 450-word prompt, warm, j=8): 103s → 73s wall time (-29%), 4.4 → 6.1 t/s prefill (+39%), CPU work -41%. TQ_MOE_BATCH_DYNAMIC=1 opt-in 시 추가 +17%. 기본 ON, TQ_NO_MOE_BATCH=1로 opt-out. 전체 리포트: docs/RELEASE_NOTES.md v0.15.0.

v3.7 IQ4_XS가 16GB Mac에서 동작 (2026-04-18 밤): 반직관적 결과 — 16.51 GB 파일16 GB Mac에서 로드됨. mmap + TQ_NO_MLOCK=1이 hot expert subset만 RAM에 유지하기 때문. Qwen3.6-35B-A3B-UD-IQ4_XS: RSS 5.44 GB (warm), 디코드 12.5 t/s peak, 실행 후 free RAM 10.2 GB. Q3_K_S 대비 품질 향상 구체적: 고유명사 + 긴 서사 유지 ("village of Oakhaven", "apprentice to blacksmith", "Master Thorne") — greedy ~60 토큰 coherent (Q3_K_S ~40 대비). 속도 손실은 13% (14.3 → 12.5 t/s). 4-tier ladder 전체: bench/results/2026-04-18_iq4_xs_tier.md. 16GB Mac에서 Qwen3.6 최고 품질 확인된 variant = IQ4_XS.

v3.6 Q3_K_S tier 측정 (2026-04-18 밤): Q3_K int8 커널(11e3c32) 완성 후 Unsloth UD-Q3_K_S (3.5 bpw, 14.3 GB) 본격 측정. 16GB M1 Pro CPU-only: 14.3 t/s warm peak, RSS 5.24 GB — 테스트한 모든 Qwen3.6 variant 중 가장 작은 working set (IQ2_XXS 6.54 GB 보다도 적음, bpw는 70% 높은데도). 원인: TQ_NO_MLOCK=1이 cold expert를 OS에 맡기는데, Q3_K_S의 균일 256-elem 블록이 IQ3_XXS의 IQ3/IQ4/Q4_K/Q6_K 혼합보다 페이지 locality가 좋음. 품질 향상 명확: "William Shakespeare wrote Hamlet" 정답 (IQ3_XXS는 여기서 실패), "Jack loved to play with his guitar" vs IQ2의 "village of the mountains". llama.cpp CPU 5.11 t/s → 2.8× 빠름. 16GB Mac에서 Qwen3.6 권장 variant는 이제 Q3_K_S. 전체 리포트: bench/results/2026-04-18_q3_k_s_tier.md.

v3.5 RoPE + SwiGLU NEON 정리 (2026-04-18 저녁): 같은 프로파일에서 나온 구조적 수정 2개. (1) Partial-RoPE용 TLS sin/cos 캐시 — Qwen 3.x 전체가 쓰는 경로. 이전엔 layer×head×pair마다 powf + cosf + sinf 재계산. sin/cos는 (pos, base, rope_dim)에만 의존하고, 한 forward pass 안에서는 layer/head 간 동일. 그 triple로 키한 thread-local 표 — 첫 layer만 계산, 나머지 ~179 조합은 배열 읽기. Qwen3.6 토큰당 transcendental 호출 ~180× 감소. (2) fast_exp_neon — SwiGLU 내부에서 Schraudolph 비트 트릭 exp를 NEON 직접 (lane당 FMA 1 + vcvtq_s32_f32 1)로. 이전엔 vst1q_f32 → scalar 4회 → vector 재조립. SwiGLU 8-lane 타일 경로 길이 절반. Qwen3.6 MoE 토큰당 약 12만 회 호출. 커밋 b4d7807, d4c0fc6.

v3.4 Q3 품질 돌파 (2026-04-18 후반): 스칼라 fused_dot 3개 더 교체 — Q3_K, IQ3_XXS, IQ4_XS (IQ4_XS는 vqtbl1q_s8 TBL-16 사용, kvalues_iq4nl 16-entry codebook에 완벽 매칭). 타깃: Qwen3.6-35B-A3B를 IQ2_XXS (2.05 bpw, 30-40 토큰서 drift)에서 **UD-IQ3_XXS (3.06 bpw, 12.3 GB)**로 승격 — 같은 16GB Mac, CPU-only. 결과: 14.6 t/s warm peak, RSS 6.82 GB (IQ2 대비 +0.28 GB뿐 — page cache가 routed expert 스트리밍, hot-set 크기 거의 동일). Coherent 디코딩이 ~2배 길게 유지 (IQ2: "small village of the mountains" → drift; IQ3: "small village called 'Happiness'" + Jack 스토리 이어감). llama.cpp의 같은 Q3 모델 CPU 대비 2.8× 빠름 (5.23 t/s). 16GB Mac에서 35B MoE 품질-속도 둘 다 잡은 상태. 전체 리포트: bench/results/2026-04-18_q3_breakthrough.md.

v3.3 MoE + Q4_K_M 성능 돌파 (2026-04-18): 프로파일 기반(sample) 핫 경로 분석으로 세 가지 커널 문제를 동시에 수정했습니다. (1) Q6_K NEON int8 fast pathfused_dot_q6_k가 순수 스칼라였습니다. Q4_K_M은 attention.wo/ffn_down에 Q6_K를 쓰기 때문에 모든 Q4_K_M 모델의 숨은 병목이었음. Qwen3.5-4B Q4_K_M 5.0 → 14.1 t/s, Phi-3.5-mini Q4_K_M 6.2 → 14.1 t/s. (2) MoE router NEON 벡터화 — 라우터 logit 계산 (토큰당 30 layers × 256 experts × 2048 dim = 15.7M scalar FMA)을 4-accumulator NEON FMA로, scratch 버퍼는 thread-local로 (malloc 제거). (3) TQ_NO_MLOCK=1 환경변수 — 16GB Mac에서 mlock(10 GB)는 오히려 OS LRU를 방해. 끄면 RSS 12→6.5 GB 절감 + 속도도 더 빨라짐 (256 experts 중 hot set이 작아서 OS page cache가 더 똑똑하게 관리). Qwen3.6-35B-A3B-UD-IQ2_XXS: 3.08 → 16.1 t/s (5.2×), llama.cpp CPU 대비 3.2× 빠름. 전체 측정: bench/results/2026-04-18_moe_and_q4_k_m_breakthrough.md.

16GB Mac에서 35B MoE 실행 권장 명령:

TQ_NO_METAL=1 TQ_NO_MLOCK=1 ./build/quant \
  models/Qwen3.6-35B-A3B-UD-IQ2_XXS.gguf \
  --chat -p "질문" -n 60 -T 0.7 -j 8

왜 quant.cpp인가?

AI 모델이 대화를 기억하려면 KV 캐시라는 메모리가 필요합니다. 대화가 길어질수록 이 메모리가 빠르게 커져서, 모델 자체보다 더 많은 메모리를 차지합니다.

일반 엔진:  모델(4GB) + KV 캐시(8GB) = 12GB 필요 → 8GB Mac에서 OOM
quant.cpp:  모델(4GB) + KV 캐시(2.3GB) = 6.3GB → 8GB Mac에서 OK ✅

quant.cpp는 이 KV 캐시를 3배 압축합니다. 같은 컴퓨터에서 3배 더 긴 대화가 가능합니다.

놀라운 점: 압축해도 품질이 떨어지지 않고, 오히려 13% 더 빨라집니다.


핵심 성과

Llama 3.2 3B 모델, 3970 토큰 평가:

설정 품질 (PPL) 메모리 (32K) 속도
압축 없음 (FP32) 19.41 7.17 GB 기준
압축 + progressive 19.39 (-0.1%) 2.33 GB +13%
압축 (일반) 20.02 (+3.1%) 2.30 GB +13%

progressive=True 한 줄로, 메모리 3배 절감 + 속도 13% 향상 + 품질 동등을 달성합니다.

m = Model("model.gguf", progressive=True)

어디에 쓸 수 있나요?

용도 코드
챗봇 만들기 m.ask("안녕하세요!")
긴 문서 질문 m = Model("model.gguf", context_length=32768)
대화 저장/복원 m.save_context("대화.kv")m.load_context("대화.kv")
끝없는 대화 자동 — context 초과 시 오래된 대화를 압축, 삭제하지 않음
C 앱에 AI 추가 #include "quant.h"cc app.c -lm
브라우저에서 실행 WASM 데모 (193 KB)

더 많은 기능

내 모델 사용:

m = Model("path/to/any-model.gguf")  # 모든 GGUF 파일 지원
for tok in m.generate("옛날 옛적에"):
    print(tok, end="", flush=True)

대화 저장 & 복원:

m.ask("이 긴 문서를 읽어줘: ...")
m.save_context("document.kv")      # 압축 상태로 디스크에 저장

m2 = Model("model.gguf")
m2.load_context("document.kv")     # 즉시 복원 — 다시 읽을 필요 없음
m2.ask("37페이지에 뭐라고 써있었어?")

설치 방법:

방법 명령어 설명
Python pip install quantcpp 사전 빌드 wheel (Linux, macOS)
C (단일 헤더) #include "quant.h" 654 KB 파일 하나, 의존성 0
브라우저 데모 링크 193 KB WASM
소스 빌드 cmake -B build && cmake --build build 72K LOC, 테스트 35개

기술적 배경

왜 "최근 128 토큰만 FP32"로 충분한가?

Transformer의 attention 메커니즘은 최근 토큰에 자연스럽게 집중합니다 (causal masking + positional encoding). 측정 결과, attention 가중치의 ~70%가 최근 128 토큰에 집중됩니다.

양자화 오류는 attention_weight × MSE로 전파됩니다. 가중치가 높은 영역(최근 128 토큰)만 FP32로 유지하면, 전체 가중 오류가 최소화됩니다.

이것은 context 길이와 무관합니다 — 128K context에서도 128 토큰(0.1%)의 FP32이면 충분합니다.

벤치마크 전체 데이터

Llama 3.2 3B — KV 압축 비교 (957-token PPL eval, M-series CPU)

KV 설정 블록 크기 압축비 PPL Δ vs FP32 tok/s vs FP32 속도
FP32 13.56 18.43 baseline
turbo_kv_4b 72 7.1× 14.08 +3.8% 18.17 -1.4% (패리티)
turbo_kv_5b 88 5.8× 13.65 +0.7% 16.80 -8.8%
turbo_kv_3b 56 9.1× 15.36 +13.3% 16.57 -10.1%
uniform_4b 68 7.5× 14.60 +7.7% 13.27 -26.8%

Progressive KV (3970-token eval, 정직한 조건)

설정 PPL vs FP32 k FP32 비율
FP32 19.41 100%
4-bit + k128 19.39 -0.1% 3.2%
4-bit flat 20.02 +3.1% 0%
2-bit + k512 26.53 +36.7% 12.9%

Context 확장 (Llama 3.2 3B + turbo_kv_4b, 32K context)

  • FP32 KV: 10.4 GB (8GB Mac에서 OOM)
  • turbo_kv_4b: 5.5 GB (8GB Mac에서 OK)
  • 속도: 7.8 tok/s (+13% vs FP32)
"llama.cpp로도 임베딩 되는데, 왜 quant.cpp?"

맞습니다. llama.cpp는 훌륭하고 임베딩도 가능합니다. 차이는 통합 방식입니다:

llama.cpp = 컴파일된 라이브러리 (250K+ LOC). libllama를 링크하면 GGML 텐서 그래프, Metal/CUDA 백엔드, 샘플러, 토크나이저가 따라옵니다. 빌드 시스템이 이를 감당할 수 있다면 훌륭합니다 — 하지만 빌드 단계가 필요한 _라이브러리_입니다.

quant.cpp = 파일 하나 (16K LOC). #include "quant.h", cc app.c -lm으로 컴파일. CMake 없음, 링커 플래그는 libc뿐. 하나의 번역 단위.

# quant.cpp — C 프로젝트에 AI 추가: 2줄
cc -O2 my_app.c -lm -lpthread -o my_app    # 끝

# llama.cpp — 먼저 라이브러리를 빌드해야 합니다
cmake -B build && cmake --build build
cc my_app.c -Ibuild/include -Lbuild -lllama -lm -lstdc++ -o my_app
시나리오 quant.cpp llama.cpp
WASM 브라우저 192 KB 바이너리 GGML 텐서 그래프가 너무 큼
마이크로컨트롤러 / RTOS #include만 가능 (FS/링커 없음) 빌드 시스템 필요
게임 엔진 (Unity/Unreal/Godot) .h 파일 하나 드롭 250K LOC 빌드 통합
교육 / 연구 하루만에 전체 코드 읽기 가능 훌륭하지만 코드가 방대
GPU 속도 기본 Metal/CUDA 최적화
모델 지원 7개 아키텍처 100+

llama.cpp — 워크스테이션에서 최고 속도가 필요할 때. vLLM — 배치 서빙이 필요할 때. quant.cpp — AI를 앱/게임/브라우저/디바이스 안에 넣어야 할 때, 통합 단순성이 GPU 처리량보다 중요할 때.

아키텍처 상세
include/turboquant/   — 공개 C API
src/core/             — 양자화 알고리즘 (polar, qjl, turbo, uniform)
src/cache/            — 페이지드 캐시 + 점진적 압축
src/backend/cpu/      — CPU 커널 (NEON, AVX2)
src/engine/           — GGUF 로더, Transformer, 토크나이저
tests/                — Google Test (35개 테스트)
wasm/                 — 브라우저 데모 (193 KB)
bindings/python/      — PyPI 패키지

지원 모델: Llama 3.x, SmolLM2, Gemma 3/4 (MoE), Qwen 3.5, Phi-3, Mistral, DeltaNet


프로젝트 히스토리 & 신뢰성

정직한 정정 기록 (10건, 100% 자체 발견)

우리는 잘못된 주장을 외부 신고 전에 스스로 발견하고 공개적으로 정정합니다.

전체 정정 기록 보기
# 시기 내용
1 v0.6.3 "lossless 7×" 주장 → 재측정 후 정정
2 v0.6.x "beats fp32" → FP32 baseline이 scalar(비최적화)였음
3 v0.7.x "with Metal default" → CMake 기본은 Metal=OFF
4 v0.7.x Tim Dettmers HIGGS 댓글 해석 오류
5 v0.8.0 Python kv_compress=1 default abort
6 v0.8.0 Cross-heap libc.free abort
7 v0.8.1 65KB/call ask() 메모리 누수
8 v0.9.0 작동하는 기능을 잘못된 분석으로 비활성화
9 v0.10 957-token eval에서 k512=53% FP32로 측정 (과대 주장)
10 v0.10 2-bit Pareto 주장 철회 (long context에서 PPL +36.7%)

연구 기반

벤치마크 아티팩트

모든 주장은 재현 가능한 벤치마크 데이터로 뒷받침됩니다:

라이선스

Apache 2.0 — LICENSE


PyPI · WASM Demo · Changelog · Issues