Transformers documentation
Contribuir
Contribuir
O Transformers suporta muitos métodos de quantização, como QLoRA, GPTQ, LLM.int8 e AWQ. No entanto, ainda existem muitas outras abordagens de quantização que não foram integradas. Para facilitar a adição e o uso desses métodos de quantização com o Transformers, utilize a classe HfQuantizer. O HfQuantizer foi projetado para ser uma classe auxiliar interna para adicionar um método de quantização, em vez de algo aplicado a cada módulo do PyTorch.
Este guia mostrará como integrar um novo método de quantização com HfQuantizer.
Requisitos
Antes de integrar um novo método de quantização ao Transformers, verifique se o método atende aos seguintes requisitos. Somente métodos de quantização que podem ser executados com módulos do PyTorch são suportados.
O método de quantização está disponível por meio de um pacote Python que pode ser instalado via pip (também é aceitável se você puder instalar o pacote apenas a partir do código-fonte). Idealmente, kernels pré-compilados estão incluídos no pacote pip.
O método pode ser executado em hardware comumente utilizado (CPU, GPU, etc.).
O método é encapsulado em um nn.Module (
~bitsandbytes.nn.Linear8bitLt,~bitsandbytes.nn.Linear4bit), e a camada linear quantizada deve ter a seguinte definição.class Linear4bit(nn.Module): def __init__(self, ...): ... def forward(self, x): return my_4bit_kernel(x, self.weight, self.bias)Dessa forma, os modelos do Transformers são facilmente quantizados substituindo as instâncias de nn.Linear por uma classe de destino.
O método de quantização deve ser serializável. Você pode salvar os pesos quantizados localmente ou enviá-los para o Hub.
Verifique se o pacote que contém os kernels/primitivas de quantização está estável (sem mudanças frequentes que quebrem a compatibilidade).
Alguns métodos de quantização podem exigir a “pré-quantização” do modelo por meio de calibração de dados (AWQ). Nesse caso, preferimos suportar apenas inferência no Transformers e deixar que a biblioteca de terceiros mantida pela comunidade de ML trate a quantização do modelo em si.
Criar a nova classe HFQuantizer
O melhor ponto de partida seria dar uma olhada em outro método de quantização, como Finegrained Fp8. Você precisará atualizar ou criar, no total, três arquivos: o arquivo de configuração, o arquivo de integração e o arquivo do quantizador.
Crie uma nova classe de configuração de quantização dentro de src/transformers/utils/quantization_config.py. Adicione a nova configuração de quantização ao _import_structure no arquivo src/transformers/__init__.py do Transformers.
Crie um novo arquivo dentro de src/transformers/quantizers/ chamado
quantizer_your_method.pye faça-o herdar de [`~quantizers.HfQuantizer`]. Certifique-se de adicionar o novo quantizer e a configuração de quantização no auto-mapping de quantização em src/transformers/quantizers/auto.py.Defina os seguintes atributos de classe e métodos de propriedade para o seu método de quantização:
requires_calibration: Indica se o método de quantização requer um processo de calibração de dados. Se definido comoTrue, você só pode suportar inferência (com pesos quantizados) e não inferência e quantização.is_serializable: Um método de propriedade para determinar se o método é serializável ou não.is_trainable: Um método de propriedade para determinar se é possível fazer fine-tuning de modelos por cima do método de quantização (com ou sem abordagens PEFT).
Escreva os métodos
validate_environmenteupdate_dtype. Esses métodos são chamados antes da criação do modelo quantizado para garantir que os usuários utilizem a configuração correta. Consulte outros quantizadores para ver um exemplo de como eles são implementados.Escreva o método
_process_model_before_weight_loading. No Transformers, os modelos quantizados são inicializados primeiro no dispositivo"meta"antes de carregar os pesos. Isso significa que o método_process_model_before_weight_loadingse encarrega de manipular o esqueleto do modelo para substituir alguns módulos (nn.Linear) pelos módulos de destino (módulos de quantização).
Você pode definir a lógica de substituição de módulos ou qualquer outro método utilitário criando um novo arquivo em transformers/src/integrations/ e expondo os métodos relevantes no arquivo __init__.py dessa pasta.
Adicione o método
get_quantize_opsà classe do quantizador se a quantização suportar quantização em tempo real. No Transformers, materializamos cada tensor e aplicamos uma sequência de operações diferentes nele. No nosso caso, a operação de quantização ocorre no final. Você precisa criar umXXXQuantize, uma subclasse deConversionOps, e adicionar um métodoconvert. No métodoconvert, você precisa quantizar os pesos e retornar um dicionário de parâmetros quantizados.Adicione o método
get_weight_conversionsà classe do quantizador, caso a quantização suporte o carregamento de pesos pré-quantizados. No transformers, é possível coletar múltiplos tensors e aplicar operações neles. Isso é particularmente útil quando há tensors no checkpoint que precisam ser reagrupados para recriar os tensors quantizados.Escreva o método
_process_model_after_weight_loading, se necessário. Esse método permite implementar recursos adicionais que exigem manipular o modelo após o carregamento dos pesos.Documente tudo! Certifique-se de que seu método de quantização está documentado adicionando um novo arquivo em
docs/source/en/quantization.Você deve adicionar testes incluindo o pacote no nosso Dockerfile noturno dentro de
docker/transformers-quantization-latest-gpue, em seguida, adicionando um novo arquivo de teste emtests/quantization/xxx. Sinta-se à vontade para consultar os métodos de quantização existentes para ver como é implementado.
Visão geral dos arquivos
| Arquivo | Propósito |
|---|---|
utils/quantization_config.py | Defina YourMethodConfig herdando de QuantizationConfigMixin |
quantizers/quantizer_your_method.py | Implemente YourMethodHfQuantizer herdando de HfQuantizer |
integrations/your_method.py | Implemente subclasses de ConversionOps e funções auxiliares |
quantizers/auto.py | Registre o quantizador e a configuração em AUTO_QUANTIZER_MAPPING e AUTO_QUANTIZATION_CONFIG_MAPPING |
docs/source/en/quantization/your_method.md | Uso da documentação para usuários |
tests/quantization/your_method/ | Adicionar testes de integração |
Entendendo get_quantize_ops vs get_weight_conversions
Esses dois métodos lidam com cenários diferentes para o carregamento de pesos. Compreender quando usar cada um é essencial.
get_quantize_ops — Quantização em tempo real
Use isso ao carregar um checkpoint não quantizado (por exemplo, pesos em float16/bfloat16) e quantizar durante o carregamento.
Checkpoint: model.safetensors (float16 weights for example)
↓
get_quantize_ops → YourQuantize.convert()
↓
Result: Quantized weights in memoryO método convert recebe um tensor por vez, o quantiza e pode retornar um dicionário de parâmetros quantizados, por exemplo:
class YourQuantize(ConversionOps):
def convert(self, input_dict, model, full_layer_name, missing_keys, **kwargs):
# input_dict = {"layer.weight": <float16 tensor>}
value = list(input_dict.values())[0]
module, tensor_name = get_module_from_name(model, full_layer_name)
# Quantize and assign
quantized, scale, zero_point = your_quantize_fn(value)
return {full_layer_name: quantized, full_layer_name + ".scale": scale, full_layer_name + ".zero_point": zero_point}get_weight_conversions — Carregar checkpoints pré-quantizados
Use isso ao carregar um checkpoint pré-quantizado em que os pesos quantizados são salvos como vários componentes separados (como data, scale e zero point) e que precisam ser combinados em um único tensor durante o carregamento. Nem todos os métodos de quantização exigem essa etapa de reconstrução: por exemplo, alguns métodos, como FP8, simplesmente carregam os pesos e as escalas como estão, sem combiná-los. Outros, como torchao, exigem a reconstituição do tensor quantizado a partir de seus múltiplos componentes salvos.
Checkpoint: model.safetensors (quantized components)
- layer._weight_qdata
- layer._weight_scale
- layer._weight_zero_point
↓
get_weight_conversions → WeightConverter + YourDeserialize.convert()
↓
Result: Reconstructed quantized tensor → layer.weightO WeightConverter coleta os tensores relacionados com base em source_patterns e, em seguida, os passa para o seu método convert:
def get_weight_conversions(self):
if self.pre_quantized:
return [
WeightConverter(
source_patterns=["_weight_qdata", "_weight_scale", "_weight_zero_point"],
target_patterns="weight",
operations=[YourDeserialize(self)],
),
]
return []
class YourDeserialize(ConversionOps):
def convert(self, input_dict, model, full_layer_name, **kwargs):
# input_dict contains all collected tensors
# Reconstruct the quantized tensor from components
reconstructed_tensor = reconstruct_from_components(input_dict)
return {full_layer_name: reconstructed_tensor}