A Quantização (ou Quantization) é uma das técnicas fundamentais de otimização no campo do Aprendizado de Máquina. Ela permite compactar Grandes Modelos de Linguagem (LLMs), reduzindo drasticamente o consumo de memória (VRAM/RAM) e acelerando o tempo de resposta, com uma perda mínima na capacidade de raciocínio.
Em termos simples, quantizar é reduzir a precisão numérica dos pesos da rede neural.
O que significa Reduzir a Precisão?
Durante o treinamento, as LLMs calculam e armazenam seus bilhões de parâmetros (pesos) usando números de ponto flutuante de alta precisão de 32 bits (FP32) ou 16 bits (FP16 / BF16).
- Ponto Flutuante de 16 bits (
FP16): Guarda números com casas decimais extremamente detalhadas (ex:0.0048293712). Cada peso ocupa 2 bytes de memória. - Inteiro de 4 bits (
INT4): Arredonda e mapeia essa gama contínua de valores decimais para um conjunto discreto e limitado de inteiros (ex: inteiros de -8 a 7). Cada peso passa a ocupar apenas 0,5 byte (4 bits).
A Matemática do Mapeamento
O processo de quantização converte um valor contínuo de ponto flutuante x∈[min,max]x \in [\text{min}, \text{max}] em um valor inteiro discreto q, utilizando dois parâmetros matemáticos: uma Escala (S) e um Ponto Zero (Z).
A fórmula de quantização mais comum (Quantização Uniforme) é:
E para desquantizar o valor durante a execução das operações matemáticas:
- S (Scale): Define o tamanho dos degraus entre os números.
- Z (Zero-Point): Ajusta o deslocamento para que o valor zero real da precisão original corresponda exatamente ao zero discreto do inteiro.
Exemplo de cálculo
Para entender a quantização na prática, vamos acompanhar o passo a passo matemático de como um pequeno grupo de pesos de alta precisão (FP32) é comprimido para um formato de baixa precisão de 4 bits (INT4) e depois reconstruído (FP16 aproximado).
Imagine que extraímos uma pequena fatia de uma matriz de pesos de uma camada de um modelo. O modelo original utiliza FP32 (ponto flutuante de 32 bits, ocupando 4 bytes por número).
Nossos 4 pesos originais (X) são:
Nosso objetivo: Comprimir esses valores para INT4 (inteiro de 4 bits sem sinal), cujos valores possíveis variam apenas no intervalo discreto de 0 a 15 (total de 24=162^4 = 16 níveis).
Passo 1: Calcular a Escala (S) e o Ponto Zero (Z)
Para mapear o intervalo contínuo dos nossos pesos reais [min,max][\text{min}, \text{max}] para o intervalo discreto [qmin,qmax]=[0,15][q_{\text{min}}, q_{\text{max}}] = [0, 15], primeiro identificamos os extremos dos dados originais:
- min=−0.85\text{min} = -0.85
- max=0.98\text{max} = 0.98
- qmin=0q_{\text{min}} = 0
- qmax=15q_{\text{max}} = 15
A. Cálculo da Escala (S)
A escala determina a distância representada por cada degrau do inteiro:
B. Cálculo do Ponto Zero (Z)
O ponto zero ajusta a escala para que o valor real correspondente a $0.0$ seja representado perfeitamente por um inteiro:
Passo 2: Quantização (X→qX \rightarrow q)
Agora aplicamos a fórmula de quantização uniformizada para cada um dos pesos originais:
- Para x1=−0.85x_1 = -0.85: q1=round(−0.850.122)+7=round(−6.967)+7=−7+7=𝟎q_1 = \text{round}\left( \frac{-0.85}{0.122} \right) + 7 = \text{round}(-6.967) + 7 = -7 + 7 = \mathbf{0}
- Para x2=0.12x_2 = 0.12: q2=round(0.120.122)+7=round(0.983)+7=1+7=𝟖q_2 = \text{round}\left( \frac{0.12}{0.122} \right) + 7 = \text{round}(0.983) + 7 = 1 + 7 = \mathbf{8}
- Para x3=0.45x_3 = 0.45: q3=round(0.450.122)+7=round(3.688)+7=4+7=𝟏𝟏q_3 = \text{round}\left( \frac{0.45}{0.122} \right) + 7 = \text{round}(3.688) + 7 = 4 + 7 = \mathbf{11}
- Para x4=0.98x_4 = 0.98: q4=round(0.980.122)+7=round(8.032)+7=8+7=𝟏𝟓q_4 = \text{round}\left( \frac{0.98}{0.122} \right) + 7 = \text{round}(8.032) + 7 = 8 + 7 = \mathbf{15}
Resultado Comprimido
Em vez de salvar os 4 números flutuantes pesados de 32 bits, o modelo salva apenas a sequência de inteiros de 4 bits:
Além do vetor q, o modelo precisa armazenar os metadados de bloco: S = 0.122 e Z = 7.
Ganho de memória: Cada peso q ocupa agora apenas 4 bits (0,5 byte) em vez de 32 bits (4 bytes). Redução de 8x no tamanho dos pesos.
Passo 3: Desquantização na Inferência (q→X′q \rightarrow X’)
Quando a LLM precisa realizar as multiplicações de matrizes durante a geração de um token, ela desquantiza temporariamente esses inteiros de volta para ponto flutuante usando a fórmula inversa:
- X1′=0.122⋅(0−7)=0.122⋅(−7)=−𝟎.𝟖𝟓𝟒X’_1 = 0.122 \cdot (0 – 7) = 0.122 \cdot (-7) = \mathbf{-0.854} (Original: -0.85)
- X2′=0.122⋅(8−7)=0.122⋅(1)=𝟎.𝟏𝟐𝟐X’_2 = 0.122 \cdot (8 – 7) = 0.122 \cdot (1) = \mathbf{0.122} (Original: 0.12)
- X3′=0.122⋅(11−7)=0.122⋅(4)=𝟎.𝟒𝟖𝟖X’_3 = 0.122 \cdot (11 – 7) = 0.122 \cdot (4) = \mathbf{0.488} (Original: 0.45)
- X4′=0.122⋅(15−7)=0.122⋅(8)=𝟎.𝟗𝟕𝟔X’_4 = 0.122 \cdot (15 – 7) = 0.122 \cdot (8) = \mathbf{0.976} (Original: 0.98)
Avaliação do Erro de Quantização
Analisando a diferença entre os pesos originais e os desquantizados:
| Valor Original (X) | Valor Reconstruído (X′) | Erro Absoluto (∣X−X′∣) |
| -0.85 | -0.854 | 0.004 |
| 0.12 | 0.122 | 0.002 |
| 0.45 | 0.488 | 0.038 |
| 0.98 | 0.976 | 0.004 |
A perda de precisão é na casa dos centésimos. Para bilhões de conexões em uma rede neural, esse pequeno desvio numérico é absorvido pela robustez do modelo, enquanto os ganhos em consumo de VRAM e velocidade de execução são significativos.
