notizia

Migliaia di parole di argomenti tecnici! Una guida alla quantificazione da leggere per gli ingegneri LLM, le illustrazioni visive rivelano come comprimere modelli di grandi dimensioni

2024-07-31

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina


Nuovo rapporto sulla saggezza

Redattore: Dipartimento editoriale

[Introduzione alla Nuova Saggezza] Di fronte alla scala dei parametri in graduale espansione di LLM, sviluppatori e ricercatori senza H100 hanno escogitato molti modi per compensare e la tecnologia di "quantificazione" è uno di questi. Questa guida visiva utilizza varie illustrazioni per riassumere in modo completo i concetti di base e i metodi di "quantificazione".

I modelli linguistici di grandi dimensioni (LLM) sono spesso troppo grandi per essere eseguiti su hardware di livello consumer. Questi modelli possono avere più di miliardi di parametri e spesso richiedono GPU con memoria di grandi dimensioni per accelerare il processo di inferenza.

Pertanto, sempre più ricerche hanno iniziato a concentrarsi su come ridurre il modello, ad esempio migliorando i metodi di formazione o utilizzando adattatori. Una delle tecniche principali in questo campo è chiamata quantizzazione.

L'ingegnere ML Maarten Grootendorst ha scritto un post sul blog che introduce specificamente la tecnologia di quantificazione nel contesto della modellazione del linguaggio ed esplora i concetti correlati uno per uno attraverso metodi visivi per aiutarci a costruire una comprensione intuitiva della tecnologia.


In questo post del blog, Maarten esplora vari metodi, casi d'uso e i principi alla base della quantificazione.

Il sommario e il contenuto dell'articolo sono mostrati nella figura seguente. Introduce principalmente i due metodi di quantizzazione post-allenamento (PTQ) e allenamento consapevole della quantizzazione (QAT). Si consiglia ai lettori con una base di intelligenza artificiale di saltare direttamente alla parte di quantizzazione simmetrica:


Prima parte: il "problema" del LLM

I "modelli linguistici di grandi dimensioni" sono grandi in termini di numero di parametri del modello, raggiungendo solitamente miliardi di scala (principalmente pesi).

Non solo i costi di archiviazione di questi parametri sono piuttosto elevati, ma anche la quantità di calcoli nella fase di inferenza è elevata.

Durante l'inferenza, il valore di attivazione è il prodotto dell'input e del peso, quindi maggiore è il numero di pesi, maggiore è il valore di attivazione.


Vogliamo quindi rappresentare miliardi di valori nel modo più efficiente possibile, riducendo così al minimo lo spazio necessario per memorizzare i parametri.

Iniziamo dall'inizio ed esploriamo come vengono rappresentati i valori prima di ottimizzare.

Come rappresentare valori numerici

I valori numerici vengono solitamente memorizzati come numeri in virgola mobile (o semplicemente float): un numero positivo o negativo con un punto decimale.

Questi valori sono rappresentati da cifre binarie su ciascun bit.

Lo standard IEEE-754 descrive il modo in cui le cifre su ciascuna cifra rappresentano un valore specifico. Nello specifico, esistono tre mappature: segno, esponente o decimale (mantissa).


Queste tre parti possono essere combinate per calcolare il valore rappresentato in base a un insieme di valori di bit:


Più cifre vengono utilizzate, più preciso è il valore numerico. Ad esempio, il modulo FP32 può essere accurato con più cifre dopo il punto decimale rispetto a FP16:


limite di memoria

Più cifre sono disponibili, non solo più preciso è il valore, ma anche più ampio è il campo di valori rappresentabili.


Dato un numero di bit e una rappresentazione, l'intervallo di valori che possono essere rappresentati è chiamato intervallo dinamico, mentre la distanza tra due valori adiacenti è chiamata precisione.


Una caratteristica interessante di questa rappresentazione è che possiamo calcolare la quantità di memoria necessaria al dispositivo per memorizzare un determinato valore.

Poiché ogni byte in memoria contiene 8 bit, possiamo creare una formula di base per la maggior parte delle forme di numeri in virgola mobile:


Nelle applicazioni reali, ci sono molti più fattori che influenzano la quantità di grafica/memoria richiesta durante l'inferenza, come la dimensione del contesto e l'architettura del modello.

Immaginiamo ora di avere un modello con 70 miliardi di parametri. La maggior parte dei modelli stessi sono rappresentati utilizzando numeri in virgola mobile a 32 bit (spesso chiamati precisione completa), che richiedono 280 GB di memoria per caricare il modello.


Ma se tutti i parametri possono essere espressi come numeri in virgola mobile a 16 bit, la dimensione della memoria richiesta può essere ridotta direttamente di una volta.

Pertanto, è molto interessante ridurre al minimo il numero di rappresentazioni dei parametri del modello (non solo per l'inferenza ma anche per l'addestramento).

Tuttavia, questo approccio non è privo di costi. La precisione del modello in genere diminuisce al diminuire del numero di bit di rappresentazione, con conseguente diminuzione della precisione.

Vogliamo ridurre il numero di cifre utilizzate per rappresentare un valore mantenendo la precisione... è qui che le tecniche di quantizzazione tornano utili.

Parte 2: Introduzione alla quantificazione

Ora sappiamo che lo scopo della quantizzazione è ridurre la precisione dei parametri del modello da larghezze di bit più elevate (come i numeri in virgola mobile a 32 bit) a larghezze di bit inferiori (come gli interi a 8 bit).


Quando si riduce il numero di bit che rappresentano i parametri originali, di solito si verifica una perdita di precisione (granularità).

Per rendere questo effetto più intuitivo, possiamo usare i colori delle foto come analogia. Ad esempio, seleziona un'immagine qualsiasi (a sinistra), ma utilizza solo 8 colori (a destra):


Tieni presente che il biscotto ingrandito appare più "granuloso" dell'originale.

Allo stesso modo, l'obiettivo principale della quantizzazione è ridurre il numero di bit (colori) richiesti per rappresentare i parametri originali mantenendo la massima precisione possibile.

Tipi di dati comuni

Innanzitutto, esaminiamo i tipi di dati comuni e l'impatto del loro utilizzo invece della rappresentazione a 32 bit (detta precisione completa o FP32).

FP16

Il primo è un esempio di passaggio da 32 bit a 16 bit (chiamato mezza precisione o FP16) in virgola mobile:


L’intervallo di valori possibili per il FP16 è molto più piccolo di quello per il FP32.

BF16

Per ottenere un intervallo numerico simile all'FP32 originale, bfloat 16 è stato introdotto come tipo "FP32 troncato":


BF16 utilizza lo stesso numero di bit di FP16, ma aggiunge un bit esponenziale, quindi può ottenere un range di valori più ampio ed è spesso utilizzato nel campo del deep learning.

INT8

Riducendo ulteriormente il numero di bit, la rappresentazione diventa più vicina a un numero intero piuttosto che a un numero in virgola mobile. Ad esempio, passando da FP32 a INT8 che ha solo 8 bit, solo 1/4 del numero di bit originale:


Ogni volta che il numero di bit viene ridotto, viene eseguita una mappatura per "comprimere" la rappresentazione originale FP32 in meno bit.

Ma nel funzionamento reale, non è necessario mappare l'intero intervallo FP32 [-3.4e38, 3.4e38] in INT8. Dobbiamo solo trovare un modo per mappare l'intervallo di dati dei parametri del modello effettivo in INT8.

I metodi comuni di compressione/mappatura includono la quantizzazione simmetrica e la quantizzazione asimmetrica, entrambe mappature lineari.

Quello di cui parleremo dopo è il metodo di quantizzazione da FP32 a INT8.

Quantizzazione simmetrica

Nella quantizzazione simmetrica, l'intervallo del valore in virgola mobile originale viene mappato su un intervallo simmetrico centrato sullo zero nello spazio di quantizzazione, con zero come punto medio dell'intervallo prima e dopo la quantizzazione.

Ciò significa che lo zero originale nello spazio in virgola mobile è esattamente zero dopo essere stato mappato nello spazio quantizzato.


Un tipico esempio di quantizzazione simmetrica è la quantizzazione massima assoluta (absmax).

Dato un elenco di valori, prendiamo il valore assoluto più alto (α) come intervallo per eseguire la mappatura lineare.


[-127, 127] rappresenta l'intervallo ristretto, mentre l'intervallo non limitato è [-128, 127], a seconda del metodo di quantizzazione

Poiché si tratta di una mappa lineare centrata sullo zero, la formula è semplice.

Per prima cosa calcola il/i fattore/i di scala utilizzando la seguente formula:

- b è il numero di byte su cui vogliamo quantizzare (8)

- α è il valore assoluto più alto

Usiamo quindi s per quantizzare l'input x:


Come mostrato nella figura sopra, il valore assoluto massimo α è 10,8 Quando si mappa FP32 su INT8, si ottiene la seguente formula:


Se si desidera ripristinare i valori FP32 originali, è anche possibile utilizzare il fattore o i fattori di scala precedentemente calcolati per la quantizzazione inversa.


Prima quantizzare e poi dequantizzare per ripristinare il valore originale. L'intero processo è il seguente:


Puoi vedere che alcuni valori, come 3.08 e 3.02, sono entrambi 36 quando quantizzati su INT8. Pertanto, quando dequantizzati tornano a FP32, perdono un po’ di precisione e non sono più distinguibili.

Questa differenza tra il valore originale e il valore quantizzato inverso è chiamata errore di quantizzazione. In generale, minore è il numero di bit del risultato della quantizzazione, maggiore è l'errore.


quantizzazione asimmetrica

A differenza della quantizzazione simmetrica, la quantizzazione asimmetrica non è una simmetria centrata sullo zero. Invece, mappa i valori minimo (β) e massimo (α) dell'intervallo in virgola mobile rispettivamente sui valori minimo e massimo dell'intervallo quantizzato.

Il metodo che esploriamo qui è chiamato quantizzazione del punto zero.


Nota come si è spostata la posizione dello 0. Ecco perché si chiama quantizzazione asimmetrica. Nell'intervallo [-7.59, 10.8], i valori massimo e minimo si trovano a distanze diverse da 0.

A causa dell'offset della posizione del punto zero, dobbiamo calcolare il punto zero nell'intervallo INT8 per eseguire la mappatura lineare. Come prima, dobbiamo anche calcolare il fattore di scala (s), ma utilizzando la differenza nell'intervallo INT8 [-128, 127].


Questo è un po' complicato poiché il punto zero (z) deve essere calcolato nell'intervallo INT8 per spostare i pesi.

Come prima, compiliamo la formula:


Per dequantizzare il valore quantizzato da INT8 a FP32, dobbiamo utilizzare il fattore di scala (s) e il punto zero (z) precedentemente calcolati.

Altrimenti, la dequantizzazione è semplice:


Quando affianchiamo la quantizzazione simmetrica e asimmetrica, possiamo vedere rapidamente la differenza tra i due metodi:


Nell'immagine sopra, possiamo vedere la caratteristica del centro zero della quantizzazione simmetrica e l'offset della quantizzazione asimmetrica.

Mappatura e ritaglio dell'intervallo (ritaglio)

Nell'esempio precedente, abbiamo esplorato come mappare un intervallo di valori in un dato vettore in una rappresentazione a bit basso. Anche se questo può mappare l'intero intervallo di valori vettoriali, presenta un grosso inconveniente, vale a dire i valori anomali.

Immagina di avere un vettore contenente i seguenti valori:


Un valore molto più grande di tutti gli altri può essere considerato un valore anomalo. Se mappiamo l'intera gamma di vettori, tutti i piccoli valori verranno mappati sulla stessa rappresentazione di ordine inferiore e perderanno la loro caratteristica distintiva:


Questo è il metodo absmax utilizzato prima.La stessa cosa accade con la quantizzazione asimmetrica senza clip

Invece, possiamo scegliere di ritagliare determinati valori. Il ritaglio si riferisce all'impostazione di un intervallo dinamico diverso dei valori originali in modo che tutti i valori anomali siano impostati sullo stesso valore.

Nell'esempio seguente, impostiamo manualmente l'intervallo dinamico su [-5, 5] e tutti i valori al di fuori di questo intervallo verranno mappati su -127 o 127, indipendentemente dal loro valore effettivo:


Il vantaggio principale di questo approccio è che l’errore di quantizzazione per i non valori anomali è significativamente ridotto. Tuttavia, ciò comporterà un aumento dell’errore di quantizzazione per i valori anomali.

Calibrazione

Nell'esempio sopra, impostiamo casualmente l'intervallo dinamico su [-5, 5], ma la decisione dovrebbe essere presa attraverso un processo di "calibrazione" per trovare un intervallo appropriato che comprenda quanti più valori possibili riducendo al minimo l'errore di quantizzazione.

L'esecuzione specifica delle fasi di calibrazione è diversa per i diversi tipi di parametri.

Pesi (e pregiudizi)

Possiamo pensare ai pesi e ai bias di un modello linguistico di grandi dimensioni (LLM) come valori statici perché sono noti prima di eseguire il modello. Ad esempio, il file da ~20 GB di Llama 3 è costituito principalmente da pesi e pregiudizi.

Poiché il numero di variabili di bias (milioni) è significativamente inferiore ai pesi (miliardi), i bias solitamente mantengono una precisione maggiore (come INT16), mentre il lavoro principale sulla quantizzazione si concentra sui pesi.

Per i pesi statici noti, le tecniche di calibrazione per selezionare l'intervallo includono:

- Seleziona manualmente i percentili dell'intervallo di input

- Ottimizzare l'errore quadratico medio (MSE) tra pesi originali e pesi quantizzati

- Minimizzare l'entropia tra il valore originale e il valore quantizzato (divergenza KL)


La scelta di un percentile, ad esempio, si traduce in un comportamento di ritaglio simile a quello visto in precedenza.

valore di attivazione

Gli input che vengono costantemente aggiornati in un ampio modello linguistico sono spesso chiamati attivazioni.


Sono chiamati valori di attivazione perché di solito passano attraverso alcune funzioni di attivazione, come sigmoide o relu

A differenza dei pesi, le attivazioni cambiano con i dati di input durante l'inferenza e sono quindi difficili da quantificare con precisione.

Poiché questi valori vengono aggiornati dopo ogni livello nascosto, i loro valori specifici non sono noti durante la fase di inferenza finché i dati di input non passano attraverso il modello.


In generale, esistono due metodi per la calibrazione dei pesi e delle attivazioni, applicati in diverse fasi del modello:

- Quantizzazione post-allenamento (PTQ)

- Come suggerisce il nome, si tratta di una quantificazione dopo l'allenamento

- Formazione sulla quantizzazione consapevole (QAT)

- Quantizzazione durante l'allenamento/ottimizzazione

Parte 3: quantificazione post-allenamento (PTQ)

La quantizzazione post-training (PTQ) è una delle tecniche di quantizzazione più popolari. Quantifica i parametri del modello (inclusi pesi e valori di attivazione) una volta completato l'addestramento del modello.

La quantificazione dei pesi può utilizzare la quantizzazione simmetrica o la quantizzazione asimmetrica.

Tuttavia, la quantificazione dei valori di attivazione richiede una fase di inferenza per ottenere la loro distribuzione sottostante, poiché non ne conosciamo in anticipo l’intervallo.

Esistono due forme di quantizzazione dei valori di attivazione:

- quantizzazione dinamica

- quantizzazione statica

quantizzazione dinamica

Dopo che i dati passano attraverso lo strato nascosto, i suoi valori di attivazione vengono raccolti e vengono confrontati il ​​valore massimo (α) e il valore minimo (β) di ciascun strato:


La distribuzione di queste attivazioni viene quindi utilizzata per calcolare i valori del punto zero (z) e del fattore di scala (s) richiesti per l'uscita quantizzata:


Questo processo si ripete ogni volta che i dati passano attraverso un nuovo livello di rete. Pertanto, ogni strato ha i propri valori z e s indipendenti, utilizzando quindi uno schema di quantizzazione diverso.

quantizzazione statica

A differenza della quantizzazione dinamica, la quantizzazione statica non calcola il punto zero (z) e il fattore di scala (s) durante l'inferenza, ma calcola questi valori prima dell'inferenza.

Per trovare questi valori, utilizziamo un set di dati di calibrazione e lo inseriamo nel modello per raccogliere queste distribuzioni sottostanti dei valori di attivazione.


Una volta raccolte queste distribuzioni, è possibile calcolare i valori s e z richiesti per la quantificazione durante l'inferenza.

Al momento dell'inferenza effettiva, i valori s e z non vengono ricalcolati ma utilizzati globalmente in tutte le attivazioni per quantizzarli.

Nel complesso, la quantizzazione dinamica, che calcola i valori s e z per ogni strato nascosto, tende ad essere più accurata. Tuttavia, ciò potrebbe aumentare il tempo di calcolo poiché questi valori devono essere calcolati ad ogni momento di inferenza.

Al contrario, la quantizzazione statica, sebbene non accurata come la quantizzazione dinamica, è più veloce perché conosce già in anticipo i valori s e z utilizzati per la quantizzazione.

Campo quantitativo a 4 bit

La quantizzazione inferiore a 8 bit è sempre stata una sfida perché l'errore di quantizzazione aumenta con ogni bit perso. Fortunatamente, esistono diversi modi intelligenti per ridurre il numero di bit a 6, 4 o anche a 2 bit (anche se generalmente non è consigliabile ridurre il numero di bit al di sotto di 4 bit).

Esploreremo due metodi comuni su HuggingFace:

- GPTQ (il modello completo funziona su GPU)

- GGUF (possibilmente scarica i livelli sulla CPU)

GPTQ

Si può dire che GPTQ sia uno dei metodi di quantizzazione a 4 bit più famosi nelle applicazioni pratiche.

Utilizza la quantizzazione asimmetrica e la elabora strato per strato, elaborando ogni strato in modo indipendente prima di passare allo strato successivo:


In questo processo di quantizzazione strato per strato, converte prima i pesi degli strati in matrici dell'Assia inverse. La matrice Hessiana inversa è la derivata seconda della funzione di perdita del modello e rappresenta la sensibilità dell'output del modello ad ogni variazione di peso.

In poche parole, mostra essenzialmente l'importanza (importanza inversa) dei pesi in ogni strato.

Pesi di valore più piccoli nella matrice dell'Assia sono più importanti perché piccoli cambiamenti in questi pesi possono portare a cambiamenti significativi nelle prestazioni del modello.


Nella matrice dell'Assia inversa, i valori più bassi rappresentano pesi più "importanti".

Successivamente, quantizziamo e dequantizziamo la prima riga della matrice dei pesi:


Questo processo ci consente di calcolare l'errore di quantizzazione (q), che possiamo ponderare utilizzando il valore dell'Hessiano inverso precedentemente calcolato (h_1).

In sostanza, stiamo creando un errore quantizzato ponderato in base all'importanza dei pesi:


Successivamente, ridistribuiamo questo errore di quantizzazione ponderato agli altri pesi della riga. Ciò aiuta a mantenere la funzionalità complessiva e l'output della rete.

Ad esempio, se lo facciamo per il secondo peso (cioè x_2=0,3), moltiplichiamo l'errore di quantizzazione (q) per l'Hessiano inverso del secondo peso (h_2) e aggiungiamo ad esso:


Successivamente, continua la stessa operazione per il terzo peso in una determinata riga:


Questo processo di ridistribuzione dell'errore di quantizzazione ponderato q viene ripetuto finché tutti i valori non sono stati quantizzati.

Questo metodo funziona perché i pesi sono generalmente correlati tra loro. Pertanto, quando un peso presenta un errore di quantizzazione, il relativo peso verrà aggiornato di conseguenza attraverso l'Hessiana inversa.

GGUF

Sebbene GPTQ sia un buon metodo di quantizzazione per eseguire l'intero Large Language Model (LLM) sulla GPU, se non ci sono condizioni hardware corrispondenti, qualsiasi livello LLM può anche essere scaricato sulla CPU tramite GGUF.

Equivale a far funzionare il modello contemporaneamente su CPU e GPU per compensare la mancanza di memoria video (VRAM).

Il metodo di quantizzazione GGUF viene aggiornato frequentemente e dipende dal numero specifico di bit di quantizzazione, ma il principio di base è il seguente.

Innanzitutto i pesi di un dato strato vengono suddivisi in “super-blocchi”, ciascuno dei quali contiene un insieme di “sottoblocchi”. Da questi "sottoblocchi" calcoliamo il/i fattore/i di scala e il valore alfa:


Per quantizzare un dato "sottoblocco", è possibile utilizzare la quantizzazione absmax menzionata prima, moltiplicando il peso dato per il fattore di scala (s_sub):


Il fattore di scala s_sub viene calcolato utilizzando l'informazione nel "sottoblocco", ma quantizzato utilizzando l'informazione s_super nel "superblocco":


In sintesi, questa quantizzazione blocco per blocco utilizza il fattore di scala del "super blocco" (s_super) per quantizzare il fattore di scala del "sottoblocco" (s_sub).

Il livello di quantizzazione di ciascun fattore di scala può essere diverso e i fattori di scala "super-blocco" hanno generalmente una precisione maggiore rispetto ai fattori di scala "sottoblocco".

Per illustrare ciò, esploriamo diversi livelli di quantizzazione (2 bit, 4 bit e 6 bit):


A seconda del tipo di quantizzazione è necessario anche un ulteriore valore minimo (m) per la regolazione del punto zero, questi vengono quantizzati così come il fattore di scala (s)

Parte 4: Formazione sulla consapevolezza quantitativa (QAT)

La terza parte descrive come quantizzare il modello dopo l'addestramento. Lo svantaggio di questo metodo è che non tiene conto dell’effettivo processo di formazione.

È qui che il Quantitative Awareness Training (QAT) torna utile. A differenza della quantificazione post-allenamento (PTQ), l'obiettivo del QAT è apprendere il processo di quantizzazione durante l'allenamento.


Il QAT tende ad essere più accurato del PTQ perché la quantizzazione viene già presa in considerazione durante il processo di addestramento. Ecco come funziona:

Durante il processo di allenamento viene introdotta la cosiddetta quantizzazione "falsa". Ad esempio, quantizzare prima i pesi in INT4, quindi dequantizzarli nuovamente in FP32:


Questo processo consente al modello di tenere conto dell'errore di quantizzazione nel calcolo delle perdite e nell'aggiornamento dei pesi durante la fase di addestramento.

Come mostrato nella figura seguente, QAT tenta di esplorare il valore di perdita nel caso di minimi "ampi" per ridurre gli errori di quantizzazione, poiché i minimi "stretti" spesso portano a errori di quantizzazione maggiori.


Supponendo che la quantizzazione non venga considerata durante la backpropagation, il processo di discesa del gradiente selezionerà il peso con il valore di perdita più piccolo. Tuttavia, se è in un minimo "stretto", ciò introdurrà errori di quantizzazione maggiori.

Al contrario, se consideriamo la quantizzazione, nei minimi "larghi" verrà scelto un peso di aggiornamento diverso, con un errore di quantizzazione molto più piccolo.


Pertanto, sebbene il metodo PTQ abbia un valore di perdita basso ad alta precisione (ad esempio FP32), QAT ha anche un valore di perdita basso a bassa precisione (ad esempio INT4), che è ciò che stiamo perseguendo.

Era a 1 bit: BitNet

Abbiamo visto prima che ridurre la precisione di quantizzazione a 4 bit è già piuttosto piccolo, ma cosa succederebbe se la riducessimo ulteriormente?

È qui che entra in gioco BitNet, che rappresenta i pesi di un modello come un singolo bit, -1 o 1, e lo fa iniettando il processo di quantizzazione direttamente nell'architettura Transformer.

L'architettura Transformer è la base della maggior parte degli LLM e consiste in calcoli che coinvolgono strati lineari:


Questi strati lineari sono generalmente rappresentati con una precisione più elevata, come FP16, e sono dove si trova la maggior parte dei pesi.

BitNet sostituisce questi livelli lineari con livelli BitLinear:


I livelli BitLinear funzionano allo stesso modo dei normali livelli lineari, moltiplicando i pesi per i valori di attivazione per calcolare l'output.

Ma la differenza è che il livello BitLinear utilizza solo 1 bit per rappresentare il peso del modello e utilizza INT8 per rappresentare il valore di attivazione:


I livelli BitLinear, come l'addestramento basato sulla quantizzazione (QAT), eseguono una sorta di quantizzazione "falsa" durante l'addestramento per analizzare l'effetto di quantizzazione di pesi e attivazioni:


Comprendiamo BitLinear passo dopo passo.

quantificazione del peso

Durante l'addestramento, i pesi vengono memorizzati come INT8 e quindi quantizzati a 1 bit utilizzando una strategia di base chiamata funzione segno.

In sostanza, sposta la distribuzione dei pesi in modo che sia centrata su 0, quindi assegna tutti i valori inferiori a 0 a -1 e tutti i valori superiori a 0 a 1:


Inoltre, tiene traccia di un valore β (valore medio assoluto), che utilizzeremo più avanti nel processo di quantizzazione inversa.

Quantizzazione dell'attivazione

Per quantificare le attivazioni, BitLinear abilita il metodo del valore massimo assoluto (absmax) per convertire le attivazioni da FP16 a INT8 poiché richiedono la moltiplicazione della matrice (×) con maggiore precisione.


Inoltre, tiene traccia di un valore α (valore assoluto massimo), che utilizzeremo più avanti nel processo di dequantizzazione.

quantizzazione inversa

Teniamo traccia di α (il valore assoluto massimo delle attivazioni) e β (il valore assoluto medio dei pesi), che ci aiuteranno a dequantizzare le attivazioni riportandole al FP16.

Le attivazioni dell'output vengono riscalate utilizzando {α, γ} per dequantizzarle alla precisione originale:


Questo processo è relativamente semplice e consente di rappresentare il modello con solo due valori, -1 o 1.

Con questo approccio, gli autori hanno osservato che man mano che le dimensioni del modello crescono, il divario prestazionale tra l’addestramento a 1 bit e l’addestramento FP16 diventa sempre più piccolo.

Tuttavia, questo vale solo per i modelli più grandi (parametri >30B), il divario tra i modelli più piccoli è ancora ampio.

Tutti gli LLM sono 1,58 bit

Per migliorare i problemi di scalabilità menzionati in precedenza, è stato introdotto BitNet 1.58b.

In questo nuovo approccio ogni peso del modello non solo può essere -1 o 1, ma può anche assumere 0, rendendo ogni variabile un ternario.

È interessante notare che la semplice aggiunta di 0 è un'operazione semplice che migliora notevolmente BitNet e accelera il processo di calcolo.

0 potenza

Perché aggiungere 0 rappresenta un miglioramento significativo?

Questo ha a che fare con la moltiplicazione di matrici!

Innanzitutto, esploriamo il funzionamento di base della moltiplicazione di matrici.

Quando calcoliamo l'output, moltiplichiamo la matrice dei pesi per il vettore di input. Ecco una visualizzazione della moltiplicazione della prima riga del primo strato della matrice dei pesi:


Questa moltiplicazione prevede due azioni, moltiplicando un singolo peso con l'input e quindi sommandoli tutti.

Al contrario, BitNet 1.58b riesce a evitare l'atto della moltiplicazione, poiché i pesi a tre valori essenzialmente dicono quanto segue:

- 1: voglio aggiungere questo valore

- 0: non voglio questo valore

- -1: voglio sottrarre questo valore

Quindi se i tuoi pesi sono quantizzati a 1,58 bit, devi solo eseguire l'addizione:


Ciò non solo accelera notevolmente i calcoli, ma consente anche il filtraggio delle funzionalità.

Impostare un determinato peso su 0 equivale a ignorare l'input, anziché aggiungere o sottrarre il valore di input come 1 bit.

Quantificare

Per eseguire la quantizzazione del peso, BitNet 1.58b utilizza la quantizzazione del valore assoluto medio (absmean), una variante della quantizzazione del valore assoluto massimo (absmax) che abbiamo visto prima.

Comprime semplicemente la distribuzione dei pesi e utilizza la media assoluta (α) per quantificare i valori. Quindi arrotondarli a -1, 0 o 1:


Rispetto a BitNet, la quantizzazione dell'attivazione è la stessa tranne che per un aspetto: invece di ridimensionare le attivazioni all'intervallo [0, 2ᵇ⁻¹], utilizziamo il metodo del valore assoluto massimo per scalare a [-2ᵇ⁻¹, 2ᵇ⁻¹] .

Per riassumere, la quantizzazione a 1,58 bit coinvolge principalmente due tecniche:

- Aggiungi 0 per creare una rappresentazione a tre valori [-1, 0, 1]

- Quantificazione media assoluta dei pesi

Il documento di BitNet giunge a questa conclusione: "13B BitNet b1.58 è più efficiente di 3B FP16 LLM in termini di latenza, utilizzo della memoria e consumo energetico."


Indirizzo del documento: https://arxiv.org/abs/2402.17764

Con solo 1,58 bit computazionalmente efficienti, otteniamo un modello leggero.

Riferimenti:

https://newsletter.maartengrootendorst.com/p/a-visual-guide-to-quantization