# AdaLoRA

[AdaLoRA](https://hf.co/papers/2303.10512) (Adaptive LoRA) — это метод оптимизации количества обучаемых параметров, выделяемых матрицам весов и слоям. В отличие от LoRA, который распределяет параметры равномерно по всем модулям, AdaLoRA выделяет больше параметров для важных матриц весов и слоёв, а менее важным — меньше. Вы можете контролировать среднее желаемое *rank* или `r` матриц, а также то, к каким модулям применять AdaLoRA, с помощью `target_modules`. Другие важные параметры, которые необходимо задать, — это `lora_alpha` (коэффициент масштабирования) и `modules_to_save` (модули, помимо слоёв AdaLoRA, которые нужно обучить и сохранить). Все эти параметры, а также другие, можно найти в [AdaLoraConfig](/docs/peft/main/ru/package_reference/adalora#peft.AdaLoraConfig).

Аннотация из статьи:

*Дообучение крупных предобученных языковых моделей на задачах нижнего уровня стало важной парадигмой в области NLP. Однако в стандартной практике дообучаются все параметры предобученной модели, что становится недопустимо затратным при наличии большого количества задач нижнего уровня. В связи с этим предложено множество методов дообучения, которые обучают инкрементальные обновления предобученных весов с высокой эффективностью по параметрам, например, с использованием приращений низкого ранга. Эти методы часто равномерно распределяют бюджет инкрементальных обновлений между всеми матрицами предобученных весов, игнорируя различную важность отдельных весовых параметров. В результате качество дообучения оказывается неоптимальным. Чтобы преодолеть этот недостаток, мы предлагаем AdaLoRA, который адаптивно распределяет бюджет параметров между матрицами весов в соответствии с их оценкой важности. В частности, AdaLoRA параметризует инкрементальные обновления в форме разложения по сингулярным значениям. Такой новый подход позволяет эффективно отсекать сингулярные значения неважных обновлений, что по сути означает сокращение их бюджета параметров, но без необходимости интенсивных точных вычислений SVD. Мы провели обширные эксперименты с несколькими предобученными моделями на задачах обработки естественного языка, ответов на вопросы и генерации естественного языка, чтобы подтвердить эффективность AdaLoRA. Результаты показывают, что AdaLoRA демонстрирует значительное улучшение по сравнению с базовыми методами, особенно в условиях малого бюджета. Наш код доступен по адресу https://github.com/QingruZhang/AdaLoRA*.

> [!WARNING]
> У AdaLoRA есть метод [update_and_allocate()](/docs/peft/main/ru/package_reference/adalora#peft.AdaLoraModel.update_and_allocate), который следует вызывать на каждом шаге обучения для обновления бюджета параметров и маски, иначе шаг адаптации не будет выполнен. Для этого необходимо написать собственный цикл обучения или создать подкласс [Trainer](https://huggingface.co/docs/transformers/main/en/main_classes/trainer#transformers.Trainer), чтобы включить этот метод. В качестве примера посмотрите на этот [собственный цикл обучения](https://github.com/huggingface/peft/blob/912ad41e96e03652cabf47522cd876076f7a0c4f/examples/conditional_generation/peft_adalora_seq2seq.py#L120).

AdaLoRA управляет бюджетом параметров, введённым в LoRA, выделяя больше параметров — другими словами, более высокий ранг `r` — для важных матриц весов, которые лучше адаптированы под задачу, и удаляя менее важные. Ранг контролируется методом, аналогичным разложению по сингулярным значениям (SVD). $\Delta W$ параметризуется с помощью двух ортогональных матриц и диагональной матрицы, содержащей сингулярные значения. Этот метод параметризации позволяет избежать итеративного применения SVD, которое вычислительно дорого. На основе этого метода ранг $\Delta W$ корректируется в соответствии с оценкой важности. $\Delta W$ разбивается на тройки, и каждая тройка оценивается по её вкладу в производительность модели. Тройки с низкой оценкой важности удаляются, а тройки с высокой оценкой важности сохраняются для дообучения.

Обучение с AdaLoRA состоит из трёх фаз: начальной фазы, фазы распределения бюджета и финальной фазы. В начальной фазе распределение бюджета не применяется, поэтому ранги не изменяются. В фазе распределения бюджета применяется описанный выше процесс, и ранги перераспределяются в соответствии с бюджетом: более важным адаптерам выделяется больший ранг, а менее важным слоям — меньший. При переходе к финальной фазе распределение бюджета завершается, ранги перераспределяются, но обучение может продолжаться некоторое время с новыми рангами для дальнейшего повышения производительности.

> [!NOTE]
> **Приветствуем вклад**: Этот раздел нуждается в уточнении.
>
> Неясно, как измеряется значимость. Пояснения также несколько избыточны и могли бы быть объединены. См. [здесь](../developer_guides/contributing#documentation-improvements), как внести вклад.

## Обзор бенчмарков

<iframe src="https://peft-internal-testing-peft-method-comparison-embed.hf.space/?highlight[type]=ADALORA" frameborder="0" width="850" height="1000"
>

## Использование

```py
from peft import AdaLoraConfig, get_peft_model

config = AdaLoraConfig(
    r=8,
    init_r=12,
    tinit=200,
    tfinal=1000,
    deltaT=10,
    target_modules=["query", "value"],
    modules_to_save=["classifier"],
)
model = get_peft_model(model, config)
model.print_healthcheck()

[... training code ...]

model.update_and_allocate(step_idx)
```

# API

## AdaLoraConfig[[peft.AdaLoraConfig]]

#### peft.AdaLoraConfig[[peft.AdaLoraConfig]]

```python
peft.AdaLoraConfig(task_type: Optional[Union[str, TaskType]] = None, peft_type: Optional[Union[str, PeftType]] = None, auto_mapping: Optional[dict] = None, peft_version: Optional[str] = None, base_model_name_or_path: Optional[str] = None, revision: Optional[str] = None, inference_mode: bool = False, r: int = 8, target_modules: Optional[Union[list[str], str]] = None, exclude_modules: Optional[Union[list[str], str]] = None, lora_alpha: int = 8, lora_dropout: float = 0.0, fan_in_fan_out: bool = False, bias: Literal['none', 'all', 'lora_only'] = 'none', use_rslora: bool = False, modules_to_save: Optional[list[str]] = None, init_lora_weights: bool | Literal['gaussian', 'eva', 'olora', 'pissa', 'pissa_niter_[number of iters]', 'corda', 'astra', 'loftq', 'orthogonal', 'mica', 'nora'] = True, layers_to_transform: Optional[Union[list[int], int]] = None, layers_pattern: Optional[Union[list[str], str]] = None, rank_pattern: dict | None = None, alpha_pattern: Optional[dict] = <factory>, megatron_config: Optional[dict] = None, megatron_core: Optional[str] = 'megatron.core', trainable_token_indices: Optional[Union[list[int], dict[str, list[int]]]] = None, loftq_config: Union[LoftQConfig, dict] = <factory>, eva_config: Optional[EvaConfig] = None, corda_config: Optional[CordaConfig] = None, astra_config: Optional[AstraConfig] = None, lora_ga_config: Optional[LoraGAConfig] = None, use_dora: bool = False, velora_config: Optional[Union[VeloraConfig, dict]] = None, alora_invocation_tokens: Optional[list[int]] = None, use_qalora: bool = False, qalora_group_size: int = 16, monteclora_config: Optional[MontecloraConfig] = None, layer_replication: Optional[list[tuple[int, int]]] = None, runtime_config: LoraRuntimeConfig = <factory>, lora_bias: bool = False, target_parameters: Optional[list[str]] = None, use_bdlora: Optional[BdLoraConfig] = None, arrow_config: Optional[ArrowConfig] = None, kasa_config: Optional[KasaConfig] = None, ensure_weight_tying: bool = False, target_r: int = 8, init_r: int = 12, tinit: int = 0, tfinal: int = 0, deltaT: int = 1, beta1: float = 0.85, beta2: float = 0.85, orth_reg_weight: float = 0.5, total_step: int | None = None)
```

[Источник](https://github.com/huggingface/peft/blob/main/src/peft/tuners/adalora/config.py#L24)

**Параметры:**

target_r (`int`) : Целевое среднее ранговое число инкрементальной матрицы.

init_r (`int`) : Начальный ранг для каждой инкрементальной матрицы.

tinit (`int`) : Количество шагов начальной разминки при дообучении.

tfinal (`int`) : Количество шагов финальной дообучения.

deltaT (`int`) : Интервал времени между двумя выделенными бюджетами.

beta1 (`float`) : гиперпараметр EMA для сглаживания чувствительности.

beta2 (`float`) : гиперпараметр EMA для количественной оценки неопределённости.

orth_reg_weight (`float`) : Коэффициент ортогональной регуляризации.

total_step (`int`) : Общее количество шагов обучения, которое должно быть указано перед началом обучения.

rank_pattern (`list`) : назначенный ранг для каждой матрицы весов с помощью RankAllocator.

Это класс конфигурации для хранения конфигурации модели [AdaLoraModel](/docs/peft/main/ru/package_reference/adalora#peft.AdaLoraModel).

AdaLoRA имеет три фазы, определяемые `tinit`, `tfinal` и `total_step`.

Начальную фазу можно рассматривать как этап предварительного обучения адаптеров, чтобы при снижении их ранга уже была закодирована некоторая информация, которую можно сократить, вместо случайных матриц. Эта фаза определяется передачей `tinit`.

После завершения начальной фазы (прошло `tinit` шагов) и до начала финальной фазы AdaLoRA с каждым шагом сокращает бюджет, определяющий максимальный ранг, допустимый для каждого слоя. Именно на этом этапе происходит снижение ранга. Этот процесс продолжается до тех пор, пока не будет достигнуто `total_step - tfinal` шагов.

Последняя фаза, начинающаяся после достижения `total_step - tfinal` шагов, больше не изменяет ранги слоёв, а выполняет дообучение слоёв с пониженным рангом, полученных на предыдущей фазе.

Практический пример: `tinit` равно 10, `tfinal` равно 20, `total_step` равно 100. Мы тратим 10 шагов на предварительное обучение без снижения ранга, так как наш бюджет постоянен (фаза инициализации), затем 80 (100-20) шагов на фазе снижения, где наш бюджет уменьшается пошагово, и, наконец, 20 шагов на финальной стадии дообучения без снижения.

## AdaLoraModel[[peft.AdaLoraModel]]

#### peft.AdaLoraModel[[peft.AdaLoraModel]]

```python
peft.AdaLoraModel(model, config, adapter_name, **kwargs)
```

[Источник](https://github.com/huggingface/peft/blob/main/src/peft/tuners/adalora/model.py#L36)

**Параметры:**

model ([transformers.PreTrainedModel](https://huggingface.co/docs/transformers/main/en/main_classes/model#transformers.PreTrainedModel)): модель, подлежащая адаптации.

config ([AdaLoraConfig](/docs/peft/main/ru/package_reference/adalora#peft.AdaLoraConfig)) : конфигурация модели AdaLora.

adapter_name (`str`) : Имя адаптера, по умолчанию `"default"`.

low_cpu_mem_usage (`bool`, `optional`, по умолчанию `False`) : Создать пустые веса адаптера на мета-устройстве. Полезно для ускорения процесса загрузки.

**Возвращает:** `torch.nn.Module`

Модель AdaLora.

Создаёт модель AdaLoRA (Adaptive LoRA) на основе предобученной модели transformers. Статья: https://openreview.net/forum?id=lq62uWRJjiY

Пример:
```py
>>> from transformers import AutoModelForSeq2SeqLM
>>> from peft import AdaLoraConfig, get_peft_model

>>> config = AdaLoraConfig(
...     peft_type="ADALORA",
...     task_type="SEQ_2_SEQ_LM",
...     init_r=12,
...     lora_alpha=32,
...     target_modules=["q", "v"],
...     lora_dropout=0.01,
...     total_step=1000,
... )
>>> model = AutoModelForSeq2SeqLM.from_pretrained("t5-base")
>>> adalora_model = get_peft_model(model, config)
```

**Атрибуты**:
- **model** ([transformers.PreTrainedModel](https://huggingface.co/docs/transformers/main/en/main_classes/model#transformers.PreTrainedModel)) -- Модель, подлежащая адаптации.
- **peft_config** ([AdaLoraConfig](/docs/peft/main/ru/package_reference/adalora#peft.AdaLoraConfig)): конфигурация модели AdaLora.

#### add_weighted_adapter[[peft.AdaLoraModel.add_weighted_adapter]]

```python
add_weighted_adapter(*args, **kwargs)
```

[Источник](https://github.com/huggingface/peft/blob/main/src/peft/tuners/adalora/model.py#L370)

Этот метод не поддерживается для AdaLoRA, используйте LoRA вместо него.

#### update_and_allocate[[peft.AdaLoraModel.update_and_allocate]]

```python
update_and_allocate(global_step)
```

[Источник](https://github.com/huggingface/peft/blob/main/src/peft/tuners/adalora/model.py#L328)

**Параметры:**

global_step (`int`) : Текущий шаг обучения, используется для расчёта бюджета adalora.

Этот метод обновляет бюджет и маску Adalora.

Это следует вызывать на каждом шаге обучения после `loss.backward()` и перед `zero_grad()`.

`tinit`, `tfinal` и `deltaT` обрабатываются внутри метода.

Пример:

```python
>>> loss = model(**input).loss
>>> loss.backward()
>>> optimizer.step()
>>> model.base_model.update_and_allocate(i_step)
>>> optimizer.zero_grad()
```

