# Contribuir

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 Transformers, utilize a classe [HfQuantizer](/docs/transformers/main/pt/main_classes/quantization#transformers.quantizers.HfQuantizer). [HfQuantizer](/docs/transformers/main/pt/main_classes/quantization#transformers.quantizers.HfQuantizer) foi projetada 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](/docs/transformers/main/pt/main_classes/quantization#transformers.quantizers.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](https://pytorch.org/docs/stable/generated/torch.nn.Module.html) (`~bitsandbytes.nn.Linear8bitLt`, `~bitsandbytes.nn.Linear4bit`), e a camada linear quantizada deve ter a seguinte definição.

  ```py
  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](https://pytorch.org/docs/stable/generated/torch.nn.Linear.html) 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 da quantização do modelo em si.

## Criar a nova classe HFQuantizer

0. 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](https://github.com/huggingface/transformers/blob/main/src/transformers/utils/quantization_config.py), o [arquivo de integração](https://github.com/huggingface/transformers/blob/main/src/transformers/integrations/finegrained_fp8.py) e o [arquivo do quantizador](https://github.com/huggingface/transformers/blob/main/src/transformers/quantizers/quantizer_finegrained_fp8.py).

1. Crie uma nova classe de configuração de quantização dentro de [src/transformers/utils/quantization_config.py](https://github.com/huggingface/transformers/blob/abbffc4525566a48a9733639797c812301218b83/src/transformers/utils/quantization_config.py). Adicione a nova configuração de quantização ao [\_import_structure](https://github.com/huggingface/transformers/blob/abbffc4525566a48a9733639797c812301218b83/src/transformers/__init__.py#L1088) dentro do arquivo [src/transformers/\_\_init\_\_.py](https://github.com/huggingface/transformers/blob/abbffc4525566a48a9733639797c812301218b83/src/transformers/__init__.py) dos Transformers.

2. Crie um novo arquivo dentro de [src/transformers/quantizers/](https://github.com/huggingface/transformers/tree/abbffc4525566a48a9733639797c812301218b83/src/transformers/quantizers) chamado `quantizer_your_method.py` e 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](https://github.com/huggingface/transformers/blob/abbffc4525566a48a9733639797c812301218b83/src/transformers/quantizers/auto.py).

3. 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 como `True`, 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).

4. Escreva os métodos `validate_environment` e `update_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.

5. 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_loading` se encarrega de manipular o esqueleto do modelo para substituir alguns módulos ([nn.Linear](https://pytorch.org/docs/stable/generated/torch.nn.Linear.html)) 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/](https://github.com/huggingface/transformers/tree/abbffc4525566a48a9733639797c812301218b83/src/transformers/integrations) e expondo os métodos relevantes no arquivo `__init__.py` dessa pasta.

6. 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 um `XXXQuantize`, uma subclasse de `ConversionOps`, e adicionar um método `convert`. No método `convert`, você precisa quantizar os pesos e retornar um dicionário de parâmetros quantizados.

7. 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.

8. 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.

9. Documente tudo! Certifique-se de que seu método de quantização está documentado adicionando um novo arquivo em `docs/source/en/quantization`.

10. Você deve adicionar testes incluindo o pacote no nosso Dockerfile noturno dentro de `docker/transformers-quantization-latest-gpu` e, em seguida, adicionando um novo arquivo de teste em `tests/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.

```text
Checkpoint: model.safetensors (float16 weights for example)
     ↓
get_quantize_ops → YourQuantize.convert()
     ↓
Result: Quantized weights in memory
```

O método `convert` recebe um tensor por vez, o quantiza e pode retornar um dicionário de parâmetros quantizados, por exemplo:

```py
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.

```text
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.weight
```

O `WeightConverter` coleta os tensores relacionados com base em `source_patterns` e, em seguida, os passa para o seu método `convert`:

```py
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}
```

