QLoRA
QLoRA ajusta LLMs através do treino de adaptadores LoRA sobre um modelo base congelado, armazenado em NF4 de 4 bits, permitindo alojar um modelo de 65 mil milhões de parâmetros numa única GPU de 48 GB.
QLoRA (Adaptação de Baixo Posto Quantizada) é um método de ajuste fino que congela um modelo de linguagem grande (LLM) pré-treinado com precisão de 4 bits e treina pequenos adaptadores LoRA sobre ele, propagando o gradiente de volta pelos pesos quantizados até os adaptadores. Apresentado por Dettmers et al. no artigo sobre QLoRA de 2023, reduziu de mais de 780 GB para menos de 48 GB a memória da GPU necessária para ajustar um modelo de 65 bilhões de parâmetros — o suficiente para uma única GPU de estação de trabalho — mantendo o desempenho da tarefa do ajuste fino de 16 bits. Os modelos Guanaco do artigo, ajustados dessa forma, alcançaram 99,3% da pontuação do ChatGPT no benchmark Vicuna após 24 horas de treinamento em uma única GPU.
Como funciona a QLoRA#
O QLoRA combina um modelo-base congelado e comprimido com três técnicas para economizar memória:
- NormalFloat de 4 bits (NF4): Cada peso é armazenado como um código de 4 bits que aponta para um de 16 níveis posicionados nos quantis de uma distribuição normal, com uma escala de valor absoluto máximo por bloco de 64 pesos. Os pesos do modelo pré-treinado têm distribuição aproximadamente normal, então os níveis de quantis fornecem mais resolução perto de zero, onde se concentra a maioria dos pesos.
- Quantização dupla: As escalas por bloco também são quantizadas para 8 bits em blocos de 256, reduzindo sua sobrecarga de 0,5 para cerca de 0,127 bits por parâmetro, uma economia de aproximadamente 3 GB em um modelo de 65B.
- Otimizadores paginados: Os estados do otimizador ficam na memória unificada da NVIDIA e são movidos para a RAM da CPU durante picos de uso de memória, como em sequências longas com checkpointing de gradientes, para que o treinamento não falhe por falta de memória.
Na passagem direta, cada camada congelada desquantiza seus pesos NF4 para bfloat16 imediatamente antes da multiplicação de matrizes e adiciona a saída do caminho LoRA. A retropropagação calcula gradientes por meio dos pesos desquantizados, mas atualiza somente as duas matrizes LoRA de baixo posto. O artigo constatou que eram necessários adaptadores em cada camada linear do bloco Transformer para igualar o ajuste fino completo:
O trecho abaixo cria os níveis NF4 da mesma forma que a biblioteca bitsandbytes e os compara com 16 níveis igualmente espaçados em blocos de pesos com distribuição normal:
import torch
torch.manual_seed(0)
normal = torch.distributions.Normal(0.0, 1.0)
# NF4: 16 levels at quantiles of a normal distribution, with an exact zero (as built in bitsandbytes)
positive = normal.icdf(torch.linspace(0.9677083, 0.5, 9)[:-1])
negative = -normal.icdf(torch.linspace(0.9677083, 0.5, 8)[:-1])
nf4 = torch.cat([negative, torch.zeros(1), positive]).sort().values
nf4 = nf4 / nf4.max()
int4 = torch.linspace(-1, 1, 16) # evenly spaced 4-bit levels for comparison
weights = torch.randn(4096, 64) * 0.02 # pretrained weights are roughly normal, in blocks of 64
absmax = weights.abs().amax(dim=1, keepdim=True) # one scale per block
for name, levels in (("NF4", nf4), ("INT4", int4)):
codes = ((weights / absmax)[..., None] - levels).abs().argmin(dim=-1) # 4-bit index per weight
restored = levels[codes] * absmax
print(f"{name} mean squared error: {(restored - weights).pow(2).mean():.3e}")Ele imprime um erro quadrático médio de 3.395e-06 para NF4 e de 4.053e-06 para níveis igualmente espaçados: com os mesmos 16 níveis e as mesmas escalas por bloco, o espaçamento por quantis do NF4 reduz em cerca de 16% o erro de reconstrução de pesos com distribuição normal. Na prática, o Hugging Face Transformers carrega um modelo em NF4 por meio do bitsandbytes, usando um BitsAndBytesConfig que define load_in_4bit=True, bnb_4bit_quant_type="nf4", bnb_4bit_use_double_quant=True e bnb_4bit_compute_dtype=torch.bfloat16; a biblioteca PEFT anexa os adaptadores LoRA.
QLoRA e métodos relacionados#
- LoRA: Treina o mesmo tipo de adaptadores em um modelo-base mantido com precisão de 16 bits. Só os pesos de 16 bits de um modelo de 65B ocupam cerca de 130 GB, enquanto o NF4 os armazena usando aproximadamente um quarto desse espaço.
- Ajuste fino eficiente em parâmetros (PEFT): A família de métodos que treina um pequeno conjunto de parâmetros, incluindo LoRA, QLoRA, adaptadores e ajuste de prompts.
- Quantização do modelo após o treinamento: Comprime um modelo finalizado para inferência. Um modelo ajustado com QLoRA costuma ser mesclado em pesos de 16 bits e depois quantizado novamente para servir.
- Treinamento consciente da quantização (QAT): Simula o arredondamento de baixa precisão na passagem direta enquanto todos os pesos são treinados, para que o modelo implantado mantenha sua precisão em baixa precisão. O Ultralytics YOLO26 executa QAT INT8 quando treinado com
quantize=8, inserindo quantização falsa em suas camadas convolucionais e lineares por meio do NVIDIA ModelOpt, para que os pesos aprendidos sejam preservados na exportação INT8.
Compromissos#
O QLoRA troca velocidade por memória: desquantizar cada peso congelado a cada passagem direta e retropropagação torna a etapa de treinamento mais lenta do que com LoRA de 16 bits. Os adaptadores são pequenos o suficiente para serem armazenados e trocados por tarefa, mas, para mesclá-los ao modelo-base, é necessário primeiro desquantizá-lo para 16 bits. No modelo de 65B, os pesos de 4 bits e as escalas com quantização dupla ocupam cerca de 34 GB, deixando o restante da GPU de 48 GB para adaptadores, ativações e estados do otimizador paginado.










