Introduzione: due livelli di confusione
La maggior parte della confusione nel mondo dei modelli linguistici di grandi dimensioni deriva dal mescolare due concetti distinti ma complementari. Molti sviluppatori e ricercatori parlano indistintamente di GGUF, GPTQ, AWQ e EXL2 come se fossero categorie simili, quando in realtà operano su livelli completamente diversi dell'architettura di un modello. Comprendere questa distinzione è fondamentale per scegliere il formato corretto per le proprie esigenze.
Un contenitore definisce come i tensori vengono archiviati su disco e come vengono caricati in memoria. Un metodo di quantizzazione definisce invece come i pesi vengono compressi in un numero inferiore di bit. Questi due aspetti sono ortogonali: è possibile avere lo stesso metodo di quantizzazione archiviato in contenitori diversi, oppure lo stesso contenitore che ospita metodi di quantizzazione differenti.
I contenitori principali
- safetensors: formato moderno basato su intestazione JSON e buffer di tensori grezzi
- GGUF: formato binario specializzato per l'esecuzione con GGML e llama.cpp
- PyTorch pickle (.bin / .pt): formato legacy che utilizza il protocollo pickle di Python
I metodi di quantizzazione
- GPTQ: quantizzazione post-training one-shot basata su informazioni Hessiane approssimate
- AWQ: quantizzazione consapevole dell'attivazione che protegge i pesi salenti
- bitsandbytes NF4: normalizzazione a 4 bit floating-point
- llama.cpp K-quants: schemi di quantizzazione a blocchi con scale per llama.cpp
- llama.cpp I-quants: quantizzazione basata su matrice di importanza
Eccezione: EXL2 e EXL3
EXL2 e EXL3 rappresentano un caso speciale: combinano sia un metodo di quantizzazione che un layout di archiviazione strettamente legato a una specifica libreria di inferenza. Non sono quindi puri contenitori né puri metodi, ma una soluzione integrata.
Una regola pratica per la memoria
Prima di approfondire i singoli formati, è utile avere una formula semplice per stimare l'utilizzo di memoria:
Memoria dei pesi ≈ parametri × bit-per-peso ÷ 8
Questa è aritmetica pura, non un benchmark di vendor. Copre solo i pesi; la cache KV e l'overhead di runtime aggiungono ulteriore memoria in cima.
Ecco una tabella illustrativa:
| Modello | 16-bit | ~4.5 bit per peso |
|---|---|---|
| 8B | ~16 GB | ~4.5 GB |
| 70B | ~140 GB | ~39 GB |
Queste stime mostrano come la quantizzazione possa ridurre drasticamente i requisiti di memoria, rendendo possibile l'esecuzione di modelli grandi su hardware consumer.
Formato 1: Precisione completa con safetensors e PyTorch
PyTorch pickle e i rischi di sicurezza
I modelli non quantizzati vengono solitamente distribuiti come pesi a 16 bit in uno dei due formati: pytorch_model.bin o model.safetensors. I file più vecchi .bin e .pt utilizzano il protocollo pickle di Python per la serializzazione.
Tuttavia, il caricamento di un file pickle può eseguire codice arbitrario. Questo rappresenta un rischio di sicurezza significativo quando si caricano checkpoint non affidabili da fonti sconosciute. Un attaccante potrebbe incorporare codice malevolo in un file pickle che verrebbe eseguito nel momento in cui il modello viene caricato, compromettendo completamente il sistema dell'utente.
Safetensors: il nuovo standard
Safetensors, creato da Hugging Face, elimina completamente questo rischio. Un file safetensors consiste di una piccola intestazione JSON seguita da buffer di tensori grezzi. Non contiene nulla di eseguibile: è semplicemente dati serializzati in un formato lineare e ben definito.
Safetensors offre ulteriori vantaggi:
- I tensori possono essere memory-mappati e caricati uno alla volta senza leggere l'intero file
- Il formato è linguaggio-agnostico e facilmente parseable
- È ora ufficialmente un progetto della PyTorch Foundation
Nota importante sulla quantizzazione
Un punto cruciale spesso trascurato: la maggior parte dei modelli GPTQ, AWQ, EXL2, EXL3 e MLX sono anch'essi archiviati in file .safetensors. La quantizzazione risiede nel contenuto dei tensori stessi e in un file di configurazione, non in un nuovo contenitore. Questo significa che molti repository su Hugging Face contengono modelli quantizzati in formato safetensors, combinando i vantaggi di sicurezza di safetensors con i benefici di dimensione ridotta della quantizzazione.
Formato 2: GGUF per llama.cpp
Che cos'è GGUF?
GGUF è un formato binario specializzato per eseguire modelli con GGML e gli esecutori basati su GGML, come llama.cpp. È stato creato da Georgi Gerganov, che inoltre guida lo sviluppo di llama.cpp. Il formato è stato introdotto il 21 agosto 2023 come sostituto del vecchio formato GGML.
Perché ha rimpiazzato GGML
I vecchi formati GGML, GGMF e GGJT avevano un limite fondamentale: non potevano indicare l'architettura a cui apparteneva un modello. Ogni volta che veniva aggiunto un nuovo iperparametro, tutti i file esistenti diventavano incompatibili. GGUF ha risolto questo problema introducendo metadati basati su coppie chiave-valore tipizzate. Questo permette di aggiungere nuovi campi senza rompere la compatibilità con i file vecchi, garantendo compatibilità all'indietro.
Obiettivi di progettazione
La specifica GGUF definisce cinque obiettivi principali:
- Deployment in un singolo file
- Estensibilità per nuovi campi
- Compatibilità con memory mapping (mmap)
- Caricamento facile e efficiente
- Informazioni complete contenute nel file stesso
A differenza dei formati che contengono solo tensori, GGUF può trasportare il tokenizzatore, i token speciali e un template di chat Jinja insieme ai pesi. Questo lo rende un formato completamente autosufficiente per l'inferenza.
Interpretare i nomi delle quantizzazioni GGUF
Il suffisso in un nome come Q4_K_M.gguf indica lo schema di quantizzazione. Ecco una tabella completa delle quantizzazioni GGUF:
| Tipo | Come funziona | Bit per peso |
|---|---|---|
| Q4_0 / Q4_1 (legacy) | 4-bit round-to-nearest in blocchi di 32 pesi; Q4_1 aggiunge un minimo di blocco | 4.5 / 5.0* |
| Q8_0 (legacy label) | 8-bit round-to-nearest in blocchi di 32 pesi | 8.5* |
| Q2_K | 16 blocchi × 16 pesi per super-blocco, scale e minimi a 4-bit | 2.625 |
| Q3_K | 16 blocchi × 16 pesi, scale a 6-bit | 3.4375 |
| Q4_K | 8 blocchi × 32 pesi, scale e minimi a 6-bit | 4.5 |
| Q5_K | 8 blocchi × 32 pesi, scale e minimi a 6-bit | 5.5 |
| Q6_K | 16 blocchi × 16 pesi, scale a 8-bit | 6.5625 |
| IQ4_XS | Super-blocchi di 256 pesi, utilizza matrice di importanza | 4.25 |
| IQ3_XXS | Stessa famiglia I-quant | 3.06 |
| IQ2_XXS | Stessa famiglia I-quant | 2.06 |
| IQ1_S | Stessa famiglia I-quant | 1.56 |
*Derivati manualmente, non elencati nella tabella Hugging Face: 32 pesi più una scale a 16-bit (e un minimo a 16-bit per Q4_1).
Verifica della matematica Q4_K
Un super-blocco contiene 256 pesi. 256 × 4 bit = 1.024 bit. Aggiungere 8 blocchi × 12 bit di scale e minimi (96 bit). Aggiungere una super-scale a 16-bit e un super-minimo a 16-bit (32 bit). Totale: 1.152 ÷ 256 = 4.5 bit per peso. Questo dimostra come i nomi GGUF codifichino la loro struttura matematica nel nome stesso.
Il significato di _S, _M, _L
Questi suffissi non indicano nuovi tipi di quantizzazione, ma mix di quantizzazioni diverse. Per esempio, llama.cpp descrive Q4_K_M come utilizzante Q6_K per metà dei tensori attention.wv e feed_forward.w2, e Q4_K per il resto. È per questo motivo che un file Q4_K_M media a più di 4.5 bit per peso: alcuni tensori critici ottengono una qualità superiore per minimizzare la perdita complessiva.
Tipi più recenti
La tabella Hugging Face elenca anche TQ1_0 e TQ2_0 per pesi ternari, oltre a MXFP4, un tipo floating-point microscaling a 4-bit. Questi rappresentano sperimentazioni più recenti nel campo della quantizzazione ultra-bassa.
Una particolarità di etichettatura
Hugging Face classifica Q8_0 tra i tipi "legacy". Tuttavia, in pratica Q8_0 rimane la scelta standard quasi-lossless per GGUF quando si desidera una qualità molto elevata con una riduzione di dimensione rispetto ai 16-bit.
Qualità vs. dimensione: la tabella di riferimento
Hugging Face pubblica una tabella di riferimento per un modello di classe Llama-2-7B che mostra il trade-off tra qualità e compressione:
| Quantizzazione | Perplexity | Cambio vs FP16 | Dimensione |
|---|---|---|---|
| FP16 | 5.9565 | baseline | 13.0 GB |
| Q8_0 | 5.9584 | +0.03% | 7.0 GB |
| Q6_K | 5.9642 | +0.13% | 5.5 GB |
| Q5_K_M | 5.9796 | +0.39% | 4. ← Volver a las noticias |