Marlin / GPTQ-Marlin#
Marlin (Mixed-Precision Auto-Regressive LINear) n'est pas une méthode de quantification — c'est un kernel GPU d'inférence qui rend la quantification GPTQ INT4 pratique et rapide en contexte batché. Il apporte un speedup jusqu'à 4× sur les GEMM mixed-precision et jusqu'à 2.8× end-to-end dans vLLM.
Le problème : GPTQ est précis, mais lent à servir#
La quantification GPTQ (voir la page dédiée) produit des modèles INT4 très compacts avec une perte de qualité minimale. Mais à l'inférence, chaque couche linéaire doit calculer :
Y = X_fp16 × W_int4
Où X est une matrice d'activations en FP16 et W est la matrice de poids compressée en INT4. Le GPU ne sait pas multiplier directement du FP16 par de l'INT4 — il faut déquantifier les poids INT4 vers le FP16 à la volée, puis faire la multiplication (GEMM). Ce déquantify-then-GEMM est extrêmement lent avec les kernels naïfs :
⚠️ LENT"] --> W16["W_fp16"] W16 --> GEMM["GEMM FP16"] X16["X_fp16"] --> GEMM GEMM --> Y["Y"]
Problème : la déquantification domine le temps de calcul → la quantification ne speed up RIEN (voire ralentit) en batched serving.
Résultat : sans kernel optimisé, GPTQ INT4 ne speed up l'inférence que pour des batch sizes très petits (1–4). Dès qu'on sert plusieurs requêtes en parallèle (cloud serving, batch 16+), la déquantification devient le bottleneck et INT4 est plus lent que FP16 natif.
C'est ce problème que Marlin résout.
Niveau néophyte : l'analogie#
Imaginez une bibliothèque où les livres sont stockés dans une langue ultra-compressée (abréviations partout). Pour lire un livre, le bibliothécaire doit d'abord le « décompresser » entièrement avant de vous le donner. Si vous êtes seul, ça va. Mais si 32 personnes demandent des livres en même temps, le bibliothécaire est débordé et tout le monde attend.
Marlin, c'est 10 bibliothécaires spécialisés qui travaillent en parallèle : pendant que l'un décompresse la page 2, un autre lit la page 1, un autre prépare la page 3. Personne ne attend — le livre compressé se lit aussi vite qu'un livre normal.
Niveau technique : le kernel Marlin#
Architecture générale#
Marlin est un kernel CUDA single-kernel qui fusionne la déquantification et le GEMM en une seule passe, avec un pipeline soigneusement conçu pour cacher la latence mémoire derrière le calcul.
(global mem)"] --> LOAD["LOAD tiles
(async prefetch)"] LOAD --> DEQ["DÉQUANT
INT4→FP16
(registers)"] DEQ --> GEMM["GEMM
FP16 × FP16
(Tensor Cores)"] GEMM --> OUT["Y (output)"] NEXT["NEXT tile
(en attente)"] -.->|"prefetch overlap"| LOAD
KEY : le prefetch du prochain tile chevauche le GEMM du tile courant → la latence mémoire est CACHÉE.
Les 4 innovations clés#
1. Accès mémoire asynchrone (async memcpy)#
OVERLAP : le LOAD de Tile 1 commence PENDANT le GEMM de Tile 0. Pendant que le Tensor Core calcule le GEMM du tile courant, la mémoire globale charge déjà le tile suivant. La latence de déquantification est ainsi totalement masquée par le calcul.
Le kernel utilise des prefetch asynchrones : pendant que le Tensor Core calcule le GEMM du tile courant, la mémoire globale charge déjà le tile suivant. La latence de déquantification est ainsi totalement masquée par le calcul.
2. Tiled layout et repacking#
Les poids GPTQ INT4 sont stockés dans un format « group-quantized » (un scale + zero-point par groupe de 128). Ce format n'est pas adapté aux accès mémoire coalesced du GPU.
Marlin effectue un repacking offline des poids dans un layout tiled optimisé :
g1: [w w w w] s1 z1
g2: [w w w w] s2 z2
...
gN: [w w w w] sN zN
Séquentiel par groupe
(mauvais coalescing)"] end subgraph AFTER["APRÈS (layout Marlin)"] A1["Tile(0,0): [w w w w] [s s]
Tile(0,1): [w w w w] [s s]
Tile(1,0): [w w w w] [s s]
Tuiles 2D coalesced
(accès mémoire optimal)"] end BEFORE ==>|"repacking offline
(1 fois au chargement)"| AFTER
Ce repacking se fait une seule fois au chargement du modèle — zéro coût à l'inférence.
3. Task scheduling multi-warp#
Marlin divise le travail entre warps (groupes de 32 threads) avec une stratégie sophistiquée :
Pas de stall : chaque warp a toujours du travail prêt.
4. Support de la sparsité 2:4 NVIDIA#
Marlin peut être combiné avec la structured sparsity 2:4 des GPU NVIDIA Ampere+ (2 éléments non-zéros sur 4), doublant virtuellement le débit effectif :
W_int4_sparse (2:4)→ Déquant + Skip zeros → GEMM sparse. Moitié des poids = zéro → 2× de calcul utile par cycle.
Pourquoi Marlin est plus rapide que GPTQ natif#
| Caractéristique | GPTQ natif | Marlin |
|---|---|---|
| Déquantification | Séquentielle (bottleneck) | Pipelinée (async, cachée par GEMM) |
| Layout mémoire | Group-quant (non-coalesced) | Tiled 2D (repacked, coalesced optimal) |
| Fusion kernel | 2 kernels (dequant+GEMM) | 1 kernel fusionné (dequant∥GEMM) |
| Scheduling | Simple | Multi-warp + prefetch |
| Sparsité 2:4 | Non supporté | Supporté nativement |
| Batch 1 (single user) | ~1× (correct) | ~1× (semblable) |
| Batch 16-32 | <1× (plus lent que FP16) | ~4× (speedup max !) |
| Batch 64-128 | N/A | Accélération notable |
Le point clé : Marlin brille surtout en batched serving (cloud), là où GPTQ natif échoue complètement.
Caractéristiques#
| Propriété | Valeur |
|---|---|
| Type | Kernel d'inférence (pas une méthode de quantification) |
| Quantification supportée | GPTQ INT4 weights × FP16 activations |
| Précision | INT4 poids, FP16 activations (mixed-precision) |
| GPU requis | NVIDIA Ampere+ (A100, A10, L40S, H100, RTX 30xx/40xx) |
| Speedup GEMM | Jusqu'à 4× (batch 16–32) |
| Speedup end-to-end (vLLM) | Jusqu'à 2.8× |
| Sparsité 2:4 | Supportée nativement |
| Statut | Intégré dans vLLM, TensorRT-LLM, et plus |
Benchmarks de vitesse#
GEMM seul (matmul INT4×FP16)#
Marlin atteint le speedup théorique maximal (4×) pour batch 16-32, puis décroît doucement. GPTQ naïf ne speed up JAMAIS le GEMM.
End-to-end dans vLLM (génération complète)#
| Modèle | Batch | vLLM FP16 (tok/s) | vLLM + GPTQ-Marlin (tok/s) | Speedup |
|---|---|---|---|---|
| LLaMA-7B | 32 | ~2 000 | ~5 000 | 2.5× |
| LLaMA-13B | 32 | ~1 200 | ~3 200 | 2.7× |
| LLaMA-70B | 16 | ~250 | ~700 | 2.8× |
Exemple pratique#
Utilisation dans vLLM (le plus simple)#
vLLM détecte automatiquement les modèles GPTQ et utilise Marlin si le GPU le supporte :
# Installer vLLM
pip install vllm
# Servir un modèle GPTQ quantifié — Marlin est activé automatiquement
python -m vllm.entrypoints.openai.api_server \
--model TheBloke/Llama-2-13B-GPTQ \
--quantization gptq_marlin \
--dtype float16 \
--port 8000
Note :
--quantization gptq_marlinforce l'utilisation du kernel Marlin. Sans cette option, vLLM peut fallback sur un kernel GPTQ standard selon la configuration.
Vérifier que Marlin est utilisé#
from vllm import LLM, SamplingParams
llm = LLM(
model="TheBloke/Llama-2-13B-GPTQ",
quantization="gptq_marlin",
dtype="float16",
)
# Le log de vLLM affiche :
# "Using MarlinLinearKernel for ..." si Marlin est actif
Conversion d'un modèle GPTQ existant vers le format Marlin#
from vllm.model_executor.layers.quantization.gptq import GPTQConfig
# Le repacking (INT4 → Marlin tiled layout) est automatique
# au chargement du modèle dans vLLM. Aucune étape manuelle.
Benchmark comparatif#
# Avec vLLM benchmark tool
python -m vllm.benchmark.benchmark_serving \
--model TheBloke/Llama-2-13B-GPTQ \
--quantization gptq_marlin \
--num-prompts 100 \
--request-rate 10
# Comparer avec :
python -m vllm.benchmark.benchmark_serving \
--model meta-llama/Llama-2-13b-hf \
--num-prompts 100 \
--request-rate 10
Limitations#
- Pas une méthode de quantification — Marlin accélère l'inférence de modèles déjà quantifiés en GPTQ INT4 (ou AWQ avec adaptation).
- Configuration fixe — optimisé pour INT4 weights × FP16 activations. Pas de support natif pour INT8 ou d'autres configurations.
- Complexité CUDA avancée — le kernel est du CUDA hautement optimisé, difficile à modifier ou porter vers d'autres architectures (AMD/ROCm).
- Décroissance pour batch > 64 — le speedup diminue aux très grands batch sizes car le GEMM devient compute-bound (et non plus memory-bound).
- GPU Ampere+ requis — ne fonctionne pas sur les GPU plus anciens (V100, Pascal).
Références#
- Papier arXiv : MARLIN: Mixed-Precision Auto-Regressive Parallel Inference on Large Language Models (Frantar et al., PPoPP 2025)
- Code source : github.com/IST-DASLab/marlin
- Intégration vLLM : docs.vllm.ai — Quantization
- Voir aussi : GPTQ · AWQ · Index quantification