# Квантование

Квантование представляет данные с меньшим количеством бит, что делает его полезной техникой для снижения потребления памяти и ускорения вывода, особенно в случае больших языковых моделей (LLM). Существует несколько способов квантования модели, в том числе:

* оптимизация выбора весов модели, квантизуемых алгоритмом [AWQ](https://hf.co/papers/2306.00978)
* независимое квантование каждой строки матрицы весов с помощью алгоритма [GPTQ](https://hf.co/papers/2210.17323)
* квантование до 8-битной и 4-битной точности с помощью библиотеки [bitsandbytes](https://github.com/TimDettmers/bitsandbytes)
* квантование до точности всего 2 бита с помощью алгоритма [AQLM](https://huggingface.co/papers/2401.06118)

Однако после квантования модель обычно не подвергается дальнейшему обучению для задач нижнего уровня, поскольку обучение может быть нестабильным из-за пониженной точности весов и активаций. Но поскольку методы PEFT добавляют только *дополнительные* обучаемые параметры, это позволяет обучать квантованную модель с адаптером PEFT поверх неё! Сочетание квантования с PEFT может стать хорошей стратегией для обучения даже самых больших моделей на одном GPU. Например, [QLoRA](https://hf.co/papers/2305.14314) — это метод, который квантует модель до 4 бит, а затем обучает её с помощью LoRA. Этот метод позволяет дообучать модель с 65 млрд параметров на одном GPU с 48 ГБ памяти!

В этом руководстве вы узнаете, как квантовать модель до 4 бит и обучить её с помощью LoRA.

## Квантование модели

[bitsandbytes](https://github.com/TimDettmers/bitsandbytes) — это библиотека квантования с интеграцией в Transformers. Благодаря этой интеграции вы можете квантовать модель до 8 или 4 бит и включить множество других опций, настроив класс [BitsAndBytesConfig](https://huggingface.co/docs/transformers/main/en/main_classes/quantization#transformers.BitsAndBytesConfig). Например, вы можете:

* Установите `load_in_4bit=True`, чтобы квантовать модель до 4 бит при её загрузке
* установите `bnb_4bit_quant_type="nf4"`, чтобы использовать специальный 4-битный тип данных для весов, инициализированных из нормального распределения
* Установите `bnb_4bit_use_double_quant=True`, чтобы использовать схему вложенной квантизации для квантизации уже квантованных весов
* установите `bnb_4bit_compute_dtype=torch.bfloat16`, чтобы использовать bfloat16 для более быстрого вычисления

```py
import torch
from transformers import BitsAndBytesConfig

config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_use_double_quant=True,
    bnb_4bit_compute_dtype=torch.bfloat16,
)
```

Передайте `config` в метод [from_pretrained](https://huggingface.co/docs/transformers/main/en/model_doc/auto#transformers.AutoModelForCausalLM.from_pretrained).

```py
from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1", quantization_config=config)
```

Далее вам следует вызвать функцию [prepare_model_for_kbit_training()](/docs/peft/main/ru/package_reference/peft_model#peft.prepare_model_for_kbit_training), чтобы подготовить квантованную модель для обучения.

```py
from peft import prepare_model_for_kbit_training

model = prepare_model_for_kbit_training(model)
```

Теперь, когда квантованная модель готова, давайте настроим конфигурацию.

## LoraConfig

Создайте [LoraConfig](/docs/peft/main/ru/package_reference/lora#peft.LoraConfig) со следующими параметрами (или выберите свои):

```py
from peft import LoraConfig

config = LoraConfig(
    r=16,
    lora_alpha=8,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM"
)
```

Затем используйте функцию [get_peft_model()](/docs/peft/main/ru/package_reference/peft_model#peft.get_peft_model), чтобы создать [PeftModel](/docs/peft/main/ru/package_reference/peft_model#peft.PeftModel) из квантованной модели и конфигурации.

```py
from peft import get_peft_model

model = get_peft_model(model, config)
```

Вы готовы к обучению с использованием любого удобного вам метода!

### Инициализация LoftQ

[LoftQ](https://hf.co/papers/2310.08659) инициализирует веса LoRA таким образом, чтобы минимизировать ошибку квантования, и может улучшить производительность при обучении квантованных моделей. Для начала следуйте [этим инструкциям](https://github.com/huggingface/peft/tree/main/examples/loftq_finetuning).

LoftQ применяется только к линейным слоям, включая те, которые указаны через `target_parameters`. Слои встраиваний и свёрточные слои не поддерживаются и используют стандартную инициализацию LoRA. Слои `nn.MultiheadAttention` не поддерживаются и вызывают ошибку.

В целом, для наилучшей работы LoftQ рекомендуется применять LoRA к как можно большему количеству слоёв, поскольку к слоям, не включённым в целевой список, LoftQ применить невозможно. Это означает, что передача `LoraConfig(..., target_modules="all-linear")` с наибольшей вероятностью даст лучшие результаты. Кроме того, при использовании 4-битного квантования в конфигурации квантования следует указывать `nf4` в качестве типа квантования, то есть `BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type="nf4")`.

В целом, для наилучшей работы LoftQ рекомендуется применять LoRA к как можно большему количеству слоёв, поскольку к слоям, не включённым в целевой список, LoftQ применить невозможно. Это означает, что передача `LoraConfig(..., target_modules="all-linear")` с наибольшей вероятностью даст лучшие результаты. Кроме того, при использовании 4-битного квантования в конфигурации квантования следует указывать `nf4` в качестве типа квантования, то есть `BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type="nf4")`.

В настоящее время существует два предусмотренных способа применения LoftQ:

1. загрузите базовую модель без квантования, примените LoftQ с вашим целевым уровнем квантования (например, `bits=4` для nf4) и сохраните полученный адаптер. Затем выполните квантование базовой модели, например, с помощью `BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type="nf4")` и загрузите инициализированный LoftQ адаптер поверх неё
2. загрузить квантованную базовую модель, инициализировать PEFT-модель с LoRA (без loftq) и использовать `replace_lora_weights_loftq` для применения инициализации LoftQ путём потоковой загрузки эталонных весов неквантованной базовой модели из файла весов (подробнее в следующем разделе)

#### Использование `replace_lora_weights_loftq` для применения LoftQ на лету

Более простой, но менее гибкий способ применить инициализацию LoftQ — использовать вспомогательную функцию `replace_lora_weights_loftq`. Она принимает квантованную модель PEFT на вход и заменяет веса LoRA на месте их аналогами, инициализированными с помощью LoftQ.

```python
from peft import replace_lora_weights_loftq
from transformers import BitsAndBytesConfig

bnb_config = BitsAndBytesConfig(load_in_4bit=True, ...)
base_model = AutoModelForCausalLM.from_pretrained(..., quantization_config=bnb_config)
# note: don't pass init_lora_weights="loftq" or loftq_config!
lora_config = LoraConfig(task_type="CAUSAL_LM")
peft_model = get_peft_model(base_model, lora_config)
replace_lora_weights_loftq(peft_model)
```

`replace_lora_weights_loftq` также позволяет передать аргумент `callback`, чтобы получить больший контроль над тем, какие слои следует изменять, а какие — нет; эмпирически это может значительно улучшить результаты. Более подробный пример можно найти в [этом ноутбуке](https://github.com/huggingface/peft/blob/main/examples/loftq_finetuning/LoftQ_weight_replacement.ipynb).

`replace_lora_weights_loftq` реализует только один итерационный шаг LoftQ. Это означает, что обновляются только веса LoRA, а не веса LoRA и квантованной базовой модели поочерёдно. Это может привести к снижению производительности, но имеет преимущество: можно использовать исходные квантованные веса, полученные из базовой модели, вместо необходимости хранить дополнительную копию изменённых квантованных весов. Стоит ли этот компромисс того, зависит от конкретного случая использования.

В настоящее время `replace_lora_weights_loftq` имеет следующие дополнительные ограничения:

- Файлы модели должны храниться в формате `safetensors`.
- Поддерживается только 4-битное квантование bitsandbytes.

### Инициализация PiSSA

[PiSSA](https://hf.co/papers/2404.02948) нельзя применять к квантованным весам. Обычно его применяют к неквантованной базовой модели, после чего сохраняют и загружают с квантованием полученный остаток, что требует, чтобы вся неквантованная модель помещалась в память.

В качестве альтернативы `replace_lora_weights_pissa` принимает квантованную модель PEFT и загружает веса неквантованной модели из файла весов послойно. LoRA-веса каждого слоя инициализируются с помощью PiSSA, а его базовый вес заменяется пере-квантованным остатком.

```python
from peft import replace_lora_weights_pissa
from transformers import BitsAndBytesConfig

bnb_config = BitsAndBytesConfig(load_in_4bit=True, ...)
base_model = AutoModelForCausalLM.from_pretrained(..., quantization_config=bnb_config)
# note: don't pass init_lora_weights="pissa" here!
lora_config = LoraConfig(task_type="CAUSAL_LM")
peft_model = get_peft_model(base_model, lora_config)
replace_lora_weights_pissa(peft_model, init_lora_weights="pissa_niter_4")
```

Поддерживаются как `"pissa"`, так и `"pissa_niter_[number of iters]"`.

Поскольку базовые веса изменяются, сохранения только адаптера недостаточно для восстановления модели. Как и в случае с другими инициализациями PiSSA, необходимо либо сохранить базовую модель, либо преобразовать обученный адаптер с помощью аргумента `path_initial_model_for_weight_conversion` в [save_pretrained()](/docs/peft/main/ru/package_reference/peft_model#peft.PeftModel.save_pretrained).

В настоящее время `replace_lora_weights_pissa` имеет следующие дополнительные ограничения:

- Файлы модели должны храниться в формате `safetensors`.
- Поддерживается только 4-битное квантование bitsandbytes.
- Варианты LoRA, такие как DoRA, не поддерживаются.

### Обучение в стиле QLoRA

QLoRA добавляет обучаемые веса во все линейные слои в архитектуре трансформера. Поскольку имена атрибутов для этих линейных слоев могут различаться в зависимости от архитектуры, установите `target_modules` в `"all-linear"`, чтобы добавить LoRA во все линейные слои:

```py
config = LoraConfig(target_modules="all-linear", ...)
```

## Квантование GPTQ

Подробнее о квантовании на `[2, 3, 4, 8]` бит на основе GPTQ можно узнать в [GPT-QModel](https://github.com/ModelCloud/GPTQModel) и в документации Transformers по [GPTQ](https://huggingface.co/docs/transformers/quantization/gptq). PEFT поддерживает пост-обучение GPTQ через GPT-QModel.

```bash
# GPT-QModel install
pip install "gptqmodel>=7.0.0"
```

```py
from transformers import AutoModelForCausalLM, AutoTokenizer, GPTQConfig

model_id = "facebook/opt-125m"
tokenizer = AutoTokenizer.from_pretrained(model_id)

gptq_config = GPTQConfig(bits=4, group_size=128, dataset="wikitext2", tokenizer=tokenizer)

quantized_model = AutoModelForCausalLM.from_pretrained(model_id, device_map="auto", quantization_config=gptq_config)

# save quantized model
quantized_model.save_pretrained("./opt-125m-gptq")
tokenizer.save_pretrained("./opt-125m-gptq")
```

После квантования вы можете выполнять пост-обучение моделей GPTQ с помощью API PEFT.

## Квантование AQLM

Аддитивное квантование языковых моделей ([AQLM](https://huggingface.co/papers/2401.06118)) — это метод сжатия больших языковых моделей. Он квантует несколько весов совместно, используя взаимозависимости между ними. AQLM представляет группы из 8–16 весов в виде суммы нескольких векторных кодов. Это позволяет сжимать модели до 2 бит с незначительной потерей точности.

Поскольку процесс квантования AQLM требует значительных вычислительных ресурсов, рекомендуется использовать предварительно квантованные модели. Частичный список доступных моделей можно найти в официальном репозитории aqlm [repository](https://github.com/Vahe1994/AQLM).

Модели поддерживают настройку адаптеров LoRA. Для настройки квантованной модели необходимо установить библиотеку вывода `aqlm`: `pip install aqlm>=1.0.2`. Дообученные адаптеры LoRA следует сохранять отдельно, так как их объединение с квантованными весами AQLM невозможно.

```py
quantized_model = AutoModelForCausalLM.from_pretrained(
    "BlackSamorez/Mixtral-8x7b-AQLM-2Bit-1x16-hf-test-dispatch",
    dtype="auto", device_map="auto", low_cpu_mem_usage=True,
)

peft_config = LoraConfig(...)

quantized_model = get_peft_model(quantized_model, peft_config)
```

С примером [Google Colab](https://colab.research.google.com/drive/12GTp1FCj5_0SnnNQH18h_2XFh9vS_guX?usp=sharing) можно ознакомиться, чтобы получить общее представление о дообучении AQLM+LoRA.

## Квантование EETQ

Вы также можете выполнять дообучение с использованием LoRA для квантованных моделей EETQ. Пакет [EETQ](https://github.com/NetEase-FuXi/EETQ) предлагает простой и эффективный способ выполнения 8-битного квантования, который, по утверждениям, работает быстрее алгоритма `LLM.int8()`. Сначала убедитесь, что у вас установлена версия transformers, совместимая с EETQ (например, установив её из последней версии pypi или из исходного кода).

```py
import torch
from transformers import EetqConfig

config = EetqConfig("int8")
```

Передайте `config` в метод [from_pretrained](https://huggingface.co/docs/transformers/main/en/model_doc/auto#transformers.AutoModelForCausalLM.from_pretrained).

```py
from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1", quantization_config=config)
```

и создайте `LoraConfig` и передайте его в `get_peft_model`:

```py
from peft import LoraConfig, get_peft_model

config = LoraConfig(
    r=16,
    lora_alpha=8,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM"
)

model = get_peft_model(model, config)
```

## Квантование HQQ

Модели, квантованные с помощью Half-Quadratic Quantization of Large Machine Learning Models ([HQQ](https://mobiusml.github.io/hqq_blog/)), поддерживают настройку адаптеров LoRA. Для настройки квантованной модели необходимо установить библиотеку `hqq` с помощью команды: `pip install hqq`.

```python
from hqq.engine.hf import HQQModelForCausalLM

device = torch.accelerator.current_accelerator().type if hasattr(torch, "accelerator") else "cuda"

quantized_model = HQQModelForCausalLM.from_quantized(save_dir_or_hfhub, device=device)
peft_config = LoraConfig(...)
quantized_model = get_peft_model(quantized_model, peft_config)
```

Или используйте версию transformers, совместимую с HQQ (например, установив её из последней версии pypi или из исходного кода).

```python
from transformers import HqqConfig, AutoModelForCausalLM

quant_config = HqqConfig(nbits=4, group_size=64)
quantized_model = AutoModelForCausalLM.from_pretrained(save_dir_or_hfhub, device_map=device_map, quantization_config=quant_config)
peft_config = LoraConfig(...)
quantized_model = get_peft_model(quantized_model, peft_config)
```

## torchao (Оптимизация архитектуры PyTorch)

PEFT поддерживает модели, квантованные с помощью [torchao](https://github.com/pytorch/ao) ("ao") для int8-квантования.

```python
from peft import LoraConfig, get_peft_model
from transformers import AutoModelForCausalLM, TorchAoConfig
from torchao.quantization import Int8WeightOnlyConfig

model_id = ...
quantization_config = TorchAoConfig(quant_type=Int8WeightOnlyConfig())
base_model = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=quantization_config)
peft_config = LoraConfig(...)
model = get_peft_model(base_model, peft_config)
```

### Ограничения:

- Используйте самые последние версии torchao (>= v0.4.0) и transformers (> 4.42).
- В настоящее время поддерживаются только линейные слои.
- `quant_type = "int4_weight_only"` в настоящее время не поддерживается.
- `NF4` пока не реализован в transformers, поэтому не поддерживается.
- В настоящее время DoRA работает только с `quant_type = "int8_weight_only"`.
- Для использования torchao в сочетании с LoRA предусмотрена явная поддержка. Однако, когда torchao квантует слой, его класс не меняется, изменяется только тип базового тензора. По этой причине методы PEFT, отличные от LoRA, как правило, также работают с torchao, даже если они не поддерживаются явно. Обратите внимание, однако, что **слияние работает корректно только с LoRA и с `quant_type = "int8_weight_only"`**. Если вы используете другой метод PEFT или тип данных, слияние, скорее всего, приведёт к ошибке, а даже если ошибки не будет, результаты всё равно будут неверными.

## Квантование INC

Intel Neural Compressor ([INC](https://github.com/intel/neural-compressor)) позволяет выполнять квантование моделей для различных устройств, включая ускорители Intel Gaudi (также известные как HPU-устройства). Вы можете выполнять дообучение с использованием LoRA для моделей, квантованных с помощью INC. Для использования INC с моделями PyTorch установите библиотеку командой: `pip install neural-compressor[pt]`. Квантование модели до точности FP8 для HPU-устройств можно выполнить с помощью следующего одношагового процесса квантования:

```python
import torch
from neural_compressor.torch.quantization import FP8Config, convert, finalize_calibration, prepare
quant_configs = {
    ...
}
config = FP8Config(**quant_configs)
```

Передайте конфигурацию в метод `prepare`, выполните инференс для сбора статистики калибровки, а затем вызовите методы `finalize_calibration` и `convert`, чтобы квантовать модель до точности FP8:

```python
model = prepare(model, config)
# Run inference to collect calibration statistics
...
# Finalize calibration and convert the model to FP8 precision
finalize_calibration(model)
model = convert(model)
# Load PEFT LoRA adapter as usual
...
```

Пример, демонстрирующий, как загрузить адаптер PEFT LoRA в модель FLUX для генерации изображений по тексту с квантованием INC для устройств HPU, приведён [здесь](https://github.com/huggingface/peft/blob/main/examples/stable_diffusion/inc_flux_lora_hpu.py).

### Ограничения:

- Методы `merge()` и `unmerge()` в настоящее время не поддерживаются для моделей с квантованием INC.
- В настоящее время при загрузке адаптеров PEFT поддерживаются только слои **Linear** с квантованием INC.

## Другие поддерживаемые методы PEFT

Помимо LoRA, квантование поддерживают следующие методы PEFT:

- **VeRA** (поддерживает квантование bitsandbytes)
- **AdaLoRA** (поддерживает квантование как с помощью bitsandbytes, так и с помощью GPTQ)
- **(IA)³** (поддерживает квантование bitsandbytes)

## LoRA для Transformer Engine (TE)

PEFT поддерживает адаптеры LoRA поверх слоёв [NVIDIA Transformer Engine](https://docs.nvidia.com/deeplearning/transformer-engine/) (`te.pytorch.Linear`, `te.pytorch.LayerNormLinear` и `te.pytorch.LayerNormMLP`). Слои TE используют FP8 и объединённые ядра для ускорения обучения трансформеров, а подключение адаптеров LoRA позволяет выполнять параметрически эффективную дообучение моделей, ускоренных TE.

```python
from peft import LoraConfig, get_peft_model

config = LoraConfig(
    r=8,
    lora_alpha=16,
    target_modules=["q_proj", "v_proj"],
    task_type="TOKEN_CLS",
)
model = get_peft_model(te_model, config)
```

Если Transformer Engine установлен, PEFT автоматически направляет соответствующие слои в адаптер `TeLinear` — дополнительная настройка не требуется.

### Ограничения

- `merge()` и `unmerge()` пока не поддерживаются для слоёв TE.
- DoRA не поддерживается с слоями TE.

Полный пример классификации токенов ESM2 доступен в `examples/lora_finetuning_transformer_engine/`.

## Объединение адаптеров с квантованными весами

Для любого метода квантования, который это поддерживает, [merge_adapter()](/docs/peft/main/ru/package_reference/tuners#peft.tuners.tuners_utils.BaseTuner.merge_adapter) деквантует базовые веса, добавляет веса адаптера и снова квантует результат. [unmerge_adapter()](/docs/peft/main/ru/package_reference/tuners#peft.tuners.tuners_utils.BaseTuner.unmerge_adapter) выполняет те же действия в обратном порядке, поэтому не восстанавливает исходные квантованные веса, а многократные циклы слияния и разделения могут накапливать ошибку округления. Чтобы вернуть исходные веса, перезагрузите базовую модель. Чтобы переключаться между базовой моделью и адаптером без слияния, используйте контекстный менеджер [disable_adapter()](/docs/peft/main/ru/package_reference/peft_model#peft.PeftModel.disable_adapter).

## Дальнейшие шаги

Если вы хотите узнать больше о квантовании, вам могут помочь следующие материалы:

* Подробнее о QLoRA и о некоторых бенчмарках, демонстрирующих его влияние, можно узнать в блоге [Making LLMs even more accessible with bitsandbytes, 4-bit quantization and QLoRA](https://huggingface.co/blog/4bit-transformers-bitsandbytes).
* Подробнее о различных схемах квантования читайте в руководстве [Quantization](https://hf.co/docs/transformers/main/quantization) для Transformers.

