Tipi di quantizzazione in StableHLO
La quantizzazione è una tecnica per ottimizzare i modelli di machine learning convertendo i numeri in virgola mobile (come quelli utilizzati nei modelli originali) in numeri interi a precisione inferiore. In questo modo si riduce l'utilizzo della memoria e si velocizzano i calcoli, rendendo i modelli più efficienti per il deployment su dispositivi con risorse limitate.
La quantizzazione StableHLO segue la specifica di quantizzazione LiteRT, utilizzando uno schema di quantizzazione uniforme con supporto per la quantizzazione per tensore e per asse. Eredita la sua espressione di tipo dal dialetto Quant di MLIR, fornendo un modo standardizzato per rappresentare i tipi di dati quantizzati.
La quantizzazione uniforme mappa i valori in virgola mobile in numeri interi utilizzando una dimensione del passo uniforme, ottenendo valori quantizzati uniformemente distanziati. Ciò si ottiene tramite una relazione affine utilizzando due parametri di quantizzazione chiave.
La quantizzazione uniforme semplifica la rappresentazione dei numeri in virgola mobile mappandoli a numeri interi equidistanti. Questa mappatura viene ottenuta tramite una trasformazione affine che utilizza due parametri chiave: scala e punto zero. La scala determina la dimensione del passo tra valori quantizzati consecutivi. Una scala più piccola indica che i valori quantizzati sono più vicini tra loro. Il punto zero definisce il valore intero che rappresenta zero nello spazio originale in virgola mobile.
La relazione tra il valore originale in virgola mobile (real_value) e
il valore intero quantizzato (quantized_value) nella quantizzazione uniforme è:
real_value = scale * (quantized_value - zero_point)
Quantizzazione per tensore
Nella quantizzazione per tensore, vengono utilizzati una singola scala e un singolo punto zero per tutti i valori all'interno del tensore. Un tipo quantizzato per tensore è espresso in StableHLO come:
quant.uniform scale:zero_point> Esempio: !quant.uniform<i8:f32, 0.01:50>
Rappresenta un numero intero a 8 bit (i8) utilizzato per memorizzare un numero in virgola mobile a 32 bit (f32) utilizzando una scala di 0.01 e un punto zero di 50.
Quantizzazione per asse
La quantizzazione per asse offre un approccio più granulare rispetto alla quantizzazione per tensore. Anziché utilizzare una singola scala e un singolo punto zero per l'intero tensore, la quantizzazione per asse assegna scale e punti zero separati alle sezioni lungo una dimensione specifica quantized_dimension del tensore. Ciò è
particolarmente utile quando i valori variano in modo significativo in diverse dimensioni,
consentendo una migliore conservazione delle informazioni e dell'accuratezza.
Considera un tensore t con dimensioni [4, 3, 2]. Scegliamo di quantizzare
questo tensore lungo la seconda dimensione (quantized_dimension = 1). Ciò significa
che avremo tre sezioni (poiché la seconda dimensione ha una dimensione di 3), ognuna con
la propria scala e il proprio punto zero:
t[:, 0, :]: This slice gets scale[0] and zero_point[0].
t[:, 1, :]: This slice gets scale[1] and zero_point[1].
t[:, 2, :]: This slice gets scale[2] and zero_point[2].
In StableHLO, il tipo quantizzato per asse è espresso come:
quant.uniform {scale0:zero_point0, scale1:zero_point1, ...}> dove la lunghezza di scale:zero_point corrisponde al numero di sezioni lungo
quantized_dimension del tensore contenitore.
Esempio: tensor<4x3x2x!quant.uniform<i8:f32:1, {0.2:20, 0.1:10, 0.3:30}>>
Passaggi di quantizzazione in StableHLO
StableHLO fornisce diversi passaggi del compilatore che consentono trasformazioni e ottimizzazioni diverse relative alla quantizzazione, offrendoti flessibilità nella gestione dei modelli quantizzati. Questi pass sono:
stablehlo-legalize-qdq-to-quantized-op
Questa passata unisce un pattern comune nei modelli quantizzati, un'operazione di dequantizzazione seguita da un'operazione in virgola mobile e infine un'operazione di quantizzazione, in una singola operazione quantizzata. Dettagli
stablehlo-legalize-quantized-op-to-qdq
Questo passaggio fa il contrario del precedente. Decompone un'operazione quantizzata nella sequenza equivalente di operazioni di dequantizzazione, in virgola mobile e di quantizzazione. Dettagli
stablehlo-legalize-quant-to-math
Questa passata converte le operazioni StableHLO sui tipi quantizzati in operazioni equivalenti sui tipi interi. Implementa essenzialmente l'aritmetica della quantizzazione utilizzando operazioni matematiche standard. Questa decomposizione è utile per i sistemi che non supportano la quantizzazione in modo nativo, ma possono comunque utilizzare l'aritmetica della quantizzazione per esprimere la semantica dei modelli quantizzati. Dettagli
stablehlo-quant-legalize-to-tosa-rescale
StableHLO offre la possibilità di legalizzare le operazioni quantizzate nelle loro
rappresentazioni corrispondenti nel dialetto
TOSA. Questa legalizzazione
facilita la compatibilità e l'interoperabilità tra StableHLO e TOSA. Questa
passaggio converte in modo strategico le operazioni quantizzate StableHLO in una combinazione di
operazioni StableHLO e TOSA, con il dialetto TOSA utilizzato principalmente per l'operazione
rescale. L'operazione tosa.rescale svolge un ruolo fondamentale nell'adeguamento
della scala e del punto zero dei valori quantizzati, consentendo una rappresentazione accurata
dei dati quantizzati all'interno del framework TOSA.
Dettagli
tosa-rescale-legalize-to-stablehlo
Questa pass riscrive le operazioni di ridimensionamento TOSA in operazioni matematiche primitive StableHLO. Uno dei principali casi d'uso di questo pass è consentire all'interprete StableHLO di valutare i programmi contenenti operazioni di ridimensionamento TOSA. Dettagli
Valutazione dei programmi quantizzati
L'interprete di riferimento StableHLO può eseguire in modo efficiente programmi contenenti operazioni quantizzate. Per raggiungere questo obiettivo, prima riduce il programma a una rappresentazione equivalente utilizzando solo operazioni con numeri interi. Questo processo di abbassamento prevede una serie di passaggi del compilatore che trasformano il programma prima dell'interpretazione.
In sostanza, l'interprete utilizza il passaggio stablehlo-legalize-quant-to-math
per convertire le operazioni quantizzate nelle corrispondenti implementazioni
di aritmetica intera. Questa passata introduce operazioni di trasmissione CHLO per la gestione
di moltiplicazione/divisione di scala e addizione di punto zero. Per garantire la compatibilità
con l'interprete StableHLO, queste operazioni CHLO vengono poi legalizzate in
operazioni StableHLO. Vengono introdotte operazioni correlate alle forme che
vengono successivamente canonizzate e ottimizzate utilizzando una serie di passaggi di canonizzazione.
La sequenza completa di passaggi coinvolti in questa procedura di abbassamento è la seguente:
stablehlo-legalize-quant-to-math
chlo-legalize-to-stablehlo
canonicalize
shape-legalize-to-stablehlo
stablehlo-canonicalize-dynamism
Scenari di test quantizzati
StableHLO fornisce una suite completa di scenari di test quantizzati per convalidare la correttezza e il comportamento delle operazioni quantizzate. Questi scenari di test fungono da test unitari e coprono varie operazioni StableHLO in scenari quantizzati.
Un tipico esempio di scenario di test quantizzato è il seguente:
func.func @main() -> tensor<11xf32> {
%operand_0 = stablehlo.constant dense<...> : tensor<11xf32>
%operand_1 = stablehlo.constant dense<...> : tensor<11xf32>
%golden = stablehlo.constant dense<...> : tensor<11xf32>
%0 = stablehlo.uniform_quantize %operand_0 : (tensor<11xf32>) -> tensor<11x!quant.uniform<i8:f32, 0.3>>
%1 = stablehlo.uniform_quantize %operand_1 : (tensor<11xf32>) -> tensor<11x!quant.uniform<i8:f32, 0.3>>
%2 = stablehlo.add %1, %0 : tensor<11x!quant.uniform<i8:f32, 0.3>>
%result = stablehlo.uniform_dequantize %2 : (tensor<11x!quant.uniform<i8:f32, 0.3>>) -> tensor<11xf32>
%4 = stablehlo.custom_call @check.eq(%golden, %result) : (tensor<11xf32>, tensor<11xf32>) -> tensor<i1>
return %3 : tensor<11xf32>
}
e include:
- Dati di input: valori di input rappresentativi per l'operazione.
- Output di riferimento:l'output previsto dell'operazione quando viene applicata ai dati di input, in conformità con l'interprete di riferimento StableHLO e l'evaluatore HLO.
Questi scenari di test sono utili per:
- Convalida della quantizzazione StableHLO:verifica che il comportamento di quantizzazione delle operazioni StableHLO sia in linea con i risultati previsti.
- Cross-validation:confronta il comportamento della quantizzazione StableHLO con altre implementazioni o framework.
- Debug e sviluppo: aiuto nello sviluppo e nel debug di nuove funzionalità o ottimizzazioni di quantizzazione.