Half-Precision
A precisão de 16 bits (FP16) armazena números em 16 bits em vez dos 32 bits do FP32, reduzindo a memória para metade e acelerando os cálculos na GPU. Limitações, escalonamento da perda e inferência em FP16.
A precisão meia, também chamada FP16, float16 ou IEEE 754 binary16, é um formato de ponto flutuante de 16 bits com 1 bit de sinal, 5 bits de expoente e 10 bits de fração. Em comparação com a precisão simples padrão de 32 bits (FP32), ela reduz pela metade a memória e a largura de banda necessárias para cada número, e GPUs com Tensor Cores executam operações matriciais FP16 muitas vezes mais rápido que FP32. A desvantagem é o intervalo limitado, com valor máximo de 65,504, e cerca de três dígitos decimais significativos. As redes neurais toleram bem esse arredondamento, o que torna FP16 a precisão padrão para inferência em GPU e, combinada com FP32 na precisão mista, uma forma comum de acelerar o treinamento.
Comparação entre FP16 e FP32#
FP32 usa 8 bits para o expoente e 23 para a fração, abrangendo aproximadamente de 10⁻³⁸ a 10³⁸, com cerca de sete dígitos significativos. Os 5 bits de expoente do FP16 limitam os valores normais ao intervalo entre 6.1 × 10⁻⁵ e 65,504, com valores subnormais menores até cerca de 6 × 10⁻⁸, mas com precisão reduzida. Qualquer valor maior transborda para infinito, e qualquer valor menor é arredondado para zero. A conversão de um modelo mostra tanto os benefícios quanto os limites:
import torch
import torchvision
# ResNet-18 stores its weights in FP32 by default
model = torchvision.models.resnet18()
fp32_mb = sum(p.numel() * p.element_size() for p in model.parameters()) / 1e6
# Casting to FP16 stores every weight in 2 bytes instead of 4
model.half()
fp16_mb = sum(p.numel() * p.element_size() for p in model.parameters()) / 1e6
print(f"Weights: {fp32_mb:.1f} MB in FP32, {fp16_mb:.1f} MB in FP16")
# FP16 overflows above 65,504 and rounds to about 3 significant digits
x = torch.tensor([65504.0, 70000.0, 0.1])
print("FP16 values:", x.half().tolist())Os pesos diminuem de 46.8 MB para 23.4 MB. Na segunda linha, 65,504 permanece como o maior valor FP16, 70,000 vira inf, e 0.1 é armazenado como 0.0999755859375, o valor mais próximo que FP16 consegue representar.
Precisão meia no treinamento#
Treinar inteiramente em FP16 reduz a precisão ou causa divergência em muitos modelos, pois gradientes pequenos sofrem underflow e viram zero, e atualizações de pesos minúsculas em relação aos próprios pesos são eliminadas pelo arredondamento. O treinamento com precisão mista resolve os dois problemas: mantém uma cópia mestre FP32 dos pesos para as atualizações e executa as passagens direta e inversa em FP16; além disso, multiplica a perda por um fator de escala para manter os gradientes dentro do intervalo FP16 antes de convertê-los de volta para FP32. As bibliotecas ajustam esse fator automaticamente, como faz GradScaler do PyTorch:
As ativações FP16 também reduzem pela metade a memória usada por um lote durante o treinamento, permitindo que a mesma GPU comporte lotes maiores ou entradas de maior resolução. Em hardware compatível, bfloat16 (BF16) costuma ser a opção preferida para treinamento, porque seu expoente do mesmo tamanho que o do FP32 elimina a necessidade de escalonamento da perda.
Precisão meia na inferência#
A inferência não precisa de gradientes, e as ativações da maioria dos modelos de visão permanecem dentro do intervalo FP16, então converter um modelo pronto para FP16 geralmente mantém a precisão muito próxima à do FP32, sem os dados de calibração exigidos pela quantização de modelos INT8. Mecanismos de GPU como TensorRT criam mecanismos FP16 que executam em Tensor Cores, e GPUs embarcadas como NVIDIA Jetson dependem desse formato para inferência em tempo real. CPUs se beneficiam menos, pois muitas não oferecem operações FP16 rápidas. Por padrão, o Ultralytics YOLO treina em GPUs com precisão mista FP16 (amp=True) e usa quantize=16 para predição e exportação em FP16, por exemplo com YOLO26:
from ultralytics import YOLO
# Carrega o menor modelo de deteção YOLO26
model = YOLO("yolo26n.pt")
# Faça predições em FP16 em uma GPU; em uma CPU, os modelos PyTorch executam em FP32
results = model.predict("https://ultralytics.com/images/bus.jpg", quantize=16)
# Exporte um modelo ONNX que armazene os pesos em FP16
path = model.export(format="onnx", quantize=16)O arquivo exportado armazena cada peso em 2 bytes em vez de 4, e o mesmo argumento quantize=16 gera modelos FP16 para TensorRT, OpenVINO, CoreML e outros formatos de exportação.
Precisão meia e formatos relacionados#
- BFloat16 (BF16): O outro formato de ponto flutuante de 16 bits, com 8 bits de expoente e 7 de fração, que troca precisão pelo intervalo do FP32 e é preferido no treinamento de modelos grandes.
- FP8: Formatos de ponto flutuante de 8 bits em GPUs NVIDIA recentes que reduzem a memória pela metade mais uma vez, usados principalmente para treinar e disponibilizar grandes modelos de linguagem.
- Quantização INT8: Converte valores em inteiros de 8 bits com escalas por tensor ou por canal. É mais rápida e compacta que FP16, mas precisa de dados de calibração ou treinamento com reconhecimento de quantização para manter a precisão.
Onde a precisão meia é usada#
- IA de borda: Detectores em módulos Jetson e outras GPUs embarcadas executam em FP16 para atingir taxas de quadros de câmera consumindo apenas alguns watts ou dezenas de watts.
- Inferência na nuvem: Servir modelos em FP16 reduz pela metade a memória por réplica do modelo, permitindo que uma GPU comporte mais réplicas ou lotes maiores.
- Grandes modelos de linguagem: Um modelo com 7 bilhões de parâmetros precisa de 28 GB para seus pesos em FP32 e 14 GB em FP16; assim, em FP16, ele cabe em uma GPU de consumo de 24 GB, com espaço sobrando para o cache KV.










