Transformers documentation

Внести вклад

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v5.22.1).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Внести вклад

Transformers поддерживает множество методов квантования, таких как QLoRA, GPTQ, LLM.int8 и AWQ. Однако существует ещё много подходов к квантованию, которые пока не интегрированы. Чтобы упростить добавление и использование этих методов квантования в Transformers, используйте класс HfQuantizer. HfQuantizer предназначен для того, чтобы выступать в роли внутреннего вспомогательного класса для добавления метода квантования, а не применяться к каждому модулю PyTorch.

В этом руководстве показано, как интегрировать новый метод квантования с HfQuantizer.

Требования

Прежде чем интегрировать новый метод квантования в Transformers, убедитесь, что он соответствует следующим требованиям. Поддерживаются только методы квантования, которые могут выполняться с модулями PyTorch.

  • Метод квантования доступен через пакет Python, который можно установить с помощью pip (также допустимо, если пакет можно установить только из исходного кода). В идеале в pip-пакет должны входить предварительно скомпилированные ядра.

  • Метод может выполняться на общепринятом оборудовании (CPU, GPU и т. д.).

  • Метод обернут в nn.Module (~bitsandbytes.nn.Linear8bitLt, ~bitsandbytes.nn.Linear4bit), и квантованный линейный слой должен иметь следующее определение.

    class Linear4bit(nn.Module):
        def __init__(self, ...):
            ...
    
        def forward(self, x):
            return my_4bit_kernel(x, self.weight, self.bias)

    Таким образом, модели Transformers легко квантуются путём замены экземпляров nn.Linear на целевой класс.

  • Метод квантования должен быть сериализуемым. Вы можете сохранить квантованные веса локально или загрузить их в Hub.

  • Убедитесь, что пакет, содержащий ядра/примитивы квантования, стабилен (без частых несовместимых изменений).

Некоторые методы квантования могут требовать «предварительного квантования» модели с помощью калибровки данных (AWQ). В этом случае мы предпочитаем поддерживать в Transformers только инференс, а само квантование модели делегировать сторонней библиотеке, поддерживаемой сообществом ML.

Создание нового класса HFQuantizer

  1. Лучшей отправной точкой будет изучение другого метода квантования, например Finegrained Fp8. В общей сложности вам потребуется обновить или создать три файла: файл конфигурации, файл интеграции и файл квантизатора.

  2. Создайте новый класс конфигурации квантования в файле src/transformers/utils/quantization_config.py. Добавьте новую конфигурацию квантования в _import_structure в файле src/transformers/__init__.py библиотеки Transformers.

  3. Создайте новый файл quantizer_your_method.py в каталоге src/transformers/quantizers/ и унаследуйте его от [`~quantizers.HfQuantizer`]. Не забудьте добавить новый квантизатор и конфигурацию квантизации в автоматическое сопоставление квантизации в src/transformers/quantizers/auto.py.

  4. Определите следующие атрибуты класса и методы-свойства для вашего метода квантования:

    • requires_calibration: требуется ли методу квантования процесс калибровки данных. Если установлено значение True, поддерживается только инференс (с квантованными весами), а не инференс и квантование.
    • is_serializable: Метод-свойство, определяющий, сериализуем ли данный метод.
    • is_trainable: метод-свойство, определяющий, можно ли дообучать модели поверх метода квантования (с использованием подходов PEFT или без них).
  5. Напишите методы validate_environment и update_dtype. Эти методы вызываются перед созданием квантованной модели, чтобы убедиться, что пользователь использует правильную конфигурацию. Пример реализации можно найти в других квантовщиках.

  6. Напишите метод _process_model_before_weight_loading. В Transformers квантованные модели сначала инициализируются на устройстве "meta" перед загрузкой весов. Это означает, что метод _process_model_before_weight_loading отвечает за модификацию каркаса модели для замены некоторых модулей (nn.Linear) целевыми модулями (модулями квантования).

Вы можете определить логику замены модулей или любой другой вспомогательный метод, создав новый файл в transformers/src/integrations/ и экспортировав соответствующие методы в файле __init__.py этой папки.

  1. Добавьте метод get_quantize_ops в класс квантизатора, если квантизация поддерживает квантизацию «на лету». В transformers каждый тензор материализуется, и к нему применяется последовательность различных операций. В нашем случае операция квантизации выполняется в конце. Необходимо создать XXXQuantize, подкласс ConversionOps, и добавить метод convert. В методе convert нужно заквантовать веса и вернуть словарь заквантованных параметров.

  2. Добавьте метод get_weight_conversions в класс квантизатора, если квантование поддерживает загрузку предварительно квантованных весов. В transformers можно собрать несколько тензоров и применить к ним операции. Это особенно полезно, когда в чекпоинте есть тензоры, которые необходимо перегруппировать, чтобы воссоздать квантованные тензоры.

  3. При необходимости реализуйте метод _process_model_after_weight_loading. Этот метод позволяет добавлять дополнительные функции, требующие манипуляций с моделью после загрузки весов.

  4. Документируйте всё! Убедитесь, что ваш метод квантования задокументирован, добавив новый файл в docs/source/en/quantization.

  5. Вы должны добавить тесты, включив пакет в наш ночной Dockerfile внутри docker/transformers-quantization-latest-gpu, а затем создав новый файл тестов в tests/quantization/xxx. Вы можете обратиться к существующим методам квантования, чтобы посмотреть, как это реализовано.

Обзор файлов

ФайлНазначение
utils/quantization_config.pyОпределите YourMethodConfig, наследующийся от QuantizationConfigMixin
quantizers/quantizer_your_method.pyРеализуйте YourMethodHfQuantizer, наследующий от HfQuantizer
integrations/your_method.pyРеализуйте подклассы ConversionOps и вспомогательные функции
quantizers/auto.pyЗарегистрируйте квантизатор и конфигурацию в AUTO_QUANTIZER_MAPPING и AUTO_QUANTIZATION_CONFIG_MAPPING
docs/source/en/quantization/your_method.mdИспользование документации пользователями
tests/quantization/your_method/Добавить интеграционные тесты

Понимание различий между get_quantize_ops и get_weight_conversions

Эти два метода предназначены для различных сценариев загрузки весов. Понимание того, когда следует использовать каждый из них, имеет решающее значение.

get_quantize_ops — Квантование на лету

Используйте это при загрузке неквантованного чекпоинта (например, весов float16/bfloat16) и квантовании во время загрузки.

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

Метод convert принимает по одному тензору за раз, квантует его и может возвращать словарь с квантованными параметрами, например:

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 — Загрузка предварительно квантованных контрольных точек

Используйте этот параметр при загрузке предварительно квантованной контрольной точки, в которой квантованные веса сохранены в виде нескольких отдельных компонентов (например, data, scale и zero point), которые необходимо объединить в один тензор при загрузке. Не все методы квантования требуют этого шага реконструкции: например, некоторые методы, такие как FP8, просто загружают веса и масштабы как есть, без их объединения. Другие, такие как torchao, действительно требуют сборки квантованного тензора из нескольких сохранённых компонентов.

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

Класс WeightConverter собирает связанные тензоры на основе source_patterns, а затем передаёт их в ваш метод 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}
Update on GitHub