Google a publié aujourd’hui à 13 h UTC les variants QAT (Quantization-Aware Training) de toute la famille Gemma 4 — E2B, E4B, 12B, 26B-A4B, 31B. Toutes les tailles sous l’org google/, Apache 2.0, GGUF direct + mmproj.
Trois heures plus tard, Olares One tourne dessus en prod sur le 12B.
102.78 t/s vs 87.5 t/s baseline = +17.4% speed. 8.6 GB VRAM vs ~14 GB = −39%. Context 32K → 65K avec encore de la marge. Tool calling intact, vision intacte (modulo un piège mmproj que j’explique plus bas).
C’est quoi QAT, en une explication
Quantization-Aware Training c’est l’idée d’entraîner le modèle EN sachant qu’il va être quantizé. Pendant le fine-tuning final, on simule les arrondis Q4_0 dans le forward pass — donc les gradients qui remontent ajustent les poids pour être robustes à cette précision.
Le résultat : un Q4_0 entraîné en QAT garde la qualité d’un Q8_0 PTQ standard (Post-Training Quantization, ce qu’on fait habituellement après coup avec unsloth ou bartowski). En clair : même qualité, demi-taille fichier.
C’est pas nouveau comme technique — DeepSeek le faisait sur leur recipe BF16→FP8. Mais c’est la première fois que Google le ship en upstream public pour Gemma. Et la première fois qu’il y a un repo HuggingFace officiel avec les artefacts prêts à l’emploi.
Pourquoi ça compte sur consumer Blackwell 24 Go
Olares One c’est RTX 5090 Mobile, 24 Go GDDR7, sm_120 Blackwell. La frontière entre “ça rentre comfortably” et “il faut faire des compromis” est très étroite quand tu veux tout en même temps :
- Modèle 12B Q8_0 : 12.7 GB
- mmproj BF16 (vision) : 167 MB
- KV cache @ 32K q8_0/q8_0 : ~600 MB
- Drafter MTP Q8_0 (colefuoco assistant) : 465 MB
- Compute buffer ubatch 2048 : ~1.5 GB
Total : ~15 GB. Sur les 24 Go physiques, ça laissait 9 Go de marge mais HAMi vGPU sur Olares One cap à 20 Go par pod par défaut. Ça rentrait, mais le context restait coincé à 32K.
Avec QAT Q4 :
- Modèle 12B QAT UD-Q4_K_XL : 7.5 GB (−40%)
- Le reste identique : 2.7 GB additionnels
Total : 8.6 GB observés en prod. Sur le même cap HAMi 20 Go, ça libère 11 Go pour pousser le context à 65K avec encore 3 Go de marge.
Ce que j’ai shippé
Chart llamacppgemma412bone v1.0.2 → v1.0.3 sur ma source market https://orales-one-market.aamsellem.workers.dev.
Stack :
Image : aamsellem/llama-cpp-gemma4mtp:am17an-dd97604
(build perso depuis am17an PR #23398, support Gemma 4 MTP + gemma4uv projector)
Model : unsloth/gemma-4-12B-it-qat-GGUF
File : gemma-4-12B-it-qat-UD-Q4_K_XL.gguf (6.4 GB, imatrix + upcast layers sensibles)
Mmproj : google/gemma-4-12B-it-qat-q4_0-gguf
mmproj-gemma-4-12b-it-qat-q4_0.gguf (167 MB, vision encoder)
Drafter : colefuoco00/gemma-4-12B-it-assistant-GGUF Q8_0 (465 MB)
Context : 65536
KV cache : q8_0 / q8_0
Spec : --spec-type draft-mtp --spec-draft-n-max 2
Pourquoi unsloth UD plutôt que Google Q4_0 plat ? Unsloth fait de l’imatrix sur la base QAT (calibration set + upcast sélectif des layers les plus sensibles à 8-bit). Bench head-to-head plus bas dans cet article.
Le piège mmproj unsloth (1 commit perdu)
Première tentative en swappant juste TARGET_MODEL/TARGET_FILE en gardant MMPROJ_FILE=mmproj-BF16.gguf comme dans v1.0.2 :
mtmd_init_from_file: error: mismatch between text model
(n_embd = 3840) and mmproj (n_embd = 2048)
hint: you may be using wrong mmproj
Le mmproj-BF16.gguf que unsloth a uploadé dans son repo QAT 12B est en réalité un mmproj E4B-sized (n_embd=2048). Le 12B Gemma 4 a n_embd=3840. Donc l’embedding dimension du vision encoder ne matche pas celle du backbone text. Bug d’upload unsloth — ils ont probablement scripté la conversion et utilisé le wrong mmproj source.
Fix : pull le mmproj depuis le repo officiel Google à la place :
https://huggingface.co/google/gemma-4-12B-it-qat-q4_0-gguf/resolve/main/mmproj-gemma-4-12b-it-qat-q4_0.gguf
167 MB. Compatible avec les unsloth UD-Q4_K_XL weights puisque les deux dérivent de la même base Google QAT BF16. n_embd=3840 confirmé via logs. Vision chargée, single endpoint, image_url API ready.
Workaround chart-side : ajouter un MMPROJ_MODEL séparé du TARGET_MODEL dans le ConfigMap, et changer le download path mmproj pour utiliser ${MMPROJ_MODEL} au lieu de ${TARGET_MODEL}. Trois lignes.
Le bench
Olares One, RTX 5090M sm_120 Blackwell mobile, 24 Go physiques (cap HAMi 20 Go).
3 runs Space Invaders HTML, single user, vision-loaded, MTP active :
Run 1: 107.18 t/s | 2000 tokens
Run 2: 100.89 t/s | 2000 tokens
Run 3: 100.27 t/s | 1886 tokens
AVG : 102.78 t/s. MTP draft acceptance 72.5–75.0% (vs v1.0.2 84–88%, légèrement plus bas mais excellent). GPU usage : 8.6 GB.
vs baseline v1.0.2 (Q8_0 unsloth) : +17.4% speed, −39% VRAM, context bumpé 32K → 65K.
L’accept rate qui baisse de ~12 points c’est attendu — le drafter colefuoco a été calibré sur la version Q8_0 de base, et la distribution des logits d’un QAT-Q4 diverge légèrement (les arrondis Q4 ne sont pas identiques aux floats Q8). Mais le gain en speed compense largement la perte d’accept.
Head-to-head : Google Q4_0 plat vs Unsloth UD-Q4_K_XL
Vu qu’unsloth a publié 2 h après Google, j’ai voulu vérifier que choisir leur variant UD c’était pas naïf. Bench croisé sur le même chart, juste TARGET swappé.
| Variant | AVG t/s | MTP accept | GPU | File size |
|---|---|---|---|---|
| Google Q4_0 plat | 103.27 | 73–74% | 8.84 GB | 6.65 GB |
| Unsloth UD-Q4_K_XL | 102.78 | 72–75% | 8.6 GB | 6.4 GB |
Quasi-égalité sur tous les axes. Speed Google +0.5% (within noise σ ≈ 3), MTP identique, mais Google +0.24 GB VRAM et fichier +250 MB. Aucune raison de switcher : unsloth UD a l’avantage de l’imatrix (calibration sur calibration set + upcast layers sensibles) sans pénalité de speed mesurable.
Décision : reste sur unsloth UD-Q4_K_XL pour la prod.
Leaderboard 12B sur Olares One
| Stack | t/s | Context | Vision | Tool calling | VRAM |
|---|---|---|---|---|---|
| Gemma 4 12B QAT UD-Q4_K_XL (v1.0.3, aujourd’hui) | 102.78 | 65K | ✓ | ✓ | 8.6 GB |
| Gemma 4 12B Q8_0 (v1.0.2, baseline hier) | 87.5 | 32K | ✓ | ✓ | ~14 GB |
| Gemma 4 12B Q8_0 no-MTP (v1.0.0) | 47 | 32K | ✓ | ✓ | ~13 GB |
Le pas vers QAT c’est plus que +17% — c’est la première fois qu’un 12B vision + MTP + 65K ctx rentre confortablement sur 24 Go physique avec marge libre. La marge libre c’est ce qui ouvre la porte aux runs paralleles : tu peux maintenant lancer le 12B en background pendant qu’un autre app utilise ~10 Go de la même GPU.
Ce qui reste à débloquer
Drafter MTP officiel Google. Google a publié les MTP drafters QAT pour toutes les tailles (google/gemma-4-12B-it-qat-q4_0-unquantized-assistant), mais c’est du safetensors-only — la conversion GGUF dépend de llama.cpp PR #23398 (Gemma 4 MTP support, am17an, encore en WIP au moment où j’écris). Quand ça merge, on devrait passer du colefuoco drafter community au Google officiel, avec sans doute un bump d’accept rate.
Build upstream b8740+. L’image qu’on tourne est mon build perso depuis le branch am17an. Quand le PR merge dans master et que ggml-org cut une nouvelle Docker tag avec le projector gemma4uv, on peut drop l’image custom et revenir sur l’upstream officiel.
Generalisation aux autres tailles Gemma 4 QAT. L’E4B QAT existe déjà pour notre app llamacppgemma4audione (Gemma 4 E4B + audio). Vaut la peine de tester si le swap E4B Q8_0 → E4B QAT Q4 réplique le pattern +17% speed, −40% VRAM. Sur des modèles encore plus petits c’est moins critique mais ça reste du marge.
Coda
Quand DeepSeek a sorti V2 en FP8 native il y a deux ans, la communauté a dit “OK c’est intéressant mais Q8_0 PTQ post-coup c’est quasi-lossless donc on s’en fiche du QAT”. C’était partiellement vrai à l’époque. Aujourd’hui sur consumer Blackwell mobile 24 Go où chaque GB compte, l’écart Q4↔Q8 redevient critique.
Google ship maintenant le QAT officiel à toute la famille Gemma 4 le jour du release. Unsloth re-quantize en UD en moins de 2 h. Olares One tourne dessus en moins de 6 h. Le pipeline release → bench → ship a réduit à demi-journée.
Le scoring board des modèles qui rentrent sur 24 Go consumer change. Le 12B était cantonné aux apps “single-tenant” sur Olares One (impossible de le laisser tourner pendant qu’un autre LLM tourne). Avec QAT, il peut co-exister avec le 35B-A3B champion. C’est un changement qualitatif, pas juste quantitatif.
Sur Olares One : pull https://orales-one-market.aamsellem.workers.dev, upgrade Gemma 4 12B One en v1.0.3 depuis le market UI.