PEFT documentation
Lily: низко-ранговая адаптация с межслойными связями
Lily: низко-ранговая адаптация с межслойными связями
Lily — это метод эффективной дообучения, вводящий обмен весами между слоями для матриц адаптеров. Вместо обучения независимой пары AB для каждого слоя, как в LoRA, Lily использует локально общие адаптеры A (каждый A общий для блока из stride_A последовательных слоёв) и глобально общие эксперты B (небольшой пул из num_B адаптеров B общий для всех слоёв). На каждом прямом проходе лёгкий роутер, зависящий от данных, вычисляет комбинацию экспертов B с весами softmax, чтобы получить эффективный B для данного слоя и входа.
Такой подход позволяет сократить общее количество матриц адаптеров с 2N (стандартный LoRA) до N / stride_A + num_B, высвобождая бюджет параметров для использования значительно большего ранга r — как правило, в 2×–4× раз больше, чем в LoRA. Более высокий ранг и лучшая связанность увеличивают эффективный ранг обновления весов ΔW = A × combined_B, что приводит к улучшению качества адаптации.
Поскольку комбинация B является зависимой от данных (веса маршрутизатора зависят от активаций на входе во время выполнения), merge и unmerge не поддерживаются. Если для вашего развертывания требуется объединение весов, рассмотрите другие методы, такие как LoRA.
В настоящее время у Lily есть следующие дополнительные ограничения:
- Поддерживаются только слои
nn.Linear. - Квантованные слои не поддерживаются.
Если эти ограничения не подходят для вашего сценария использования, рассмотрите другие методы.
Аннотация из статьи:
Метод адаптации низкого ранга (LoRA) — это широко используемый параметрически эффективный метод дообучения (PEFT), который обучает обновления весов ΔW = AB для предобученных весов W с помощью адаптеров низкого ранга A и B. Хотя LoRA обеспечивает эффективность использования аппаратных средств, обновления весов низкого ранга ограничивают качество адаптации. В данной статье мы предлагаем метод адаптации низкого ранга с межслойными связями (Lily) — новый метод PEFT, который вводит взаимосвязанную архитектуру с локально общими экспертами A и глобально общими экспертами B. Эта структура устраняет избыточные пары AB для каждого слоя, позволяя получать ΔW более высокого ранга при том же или меньшем количестве параметров. Для повышения выразительности мы используем маршрутизаторы, зависящие от данных, для определения связей между A и B, что предотвращает сходимость экспертов B к одинаковому поведению и улучшает способность представления в различных областях. Эксперименты на разных модальностях, архитектурах и размерах моделей демонстрируют превосходство Lily по производительности и эффективности.
Обзор бенчмарков
API
LilyConfig
класс peft.LilyConfig
< source >( task_type: Optional[Union[str, TaskType]] = Nonepeft_type: Optional[Union[str, PeftType]] = Noneauto_mapping: Optional[dict] = Nonepeft_version: Optional[str] = Nonebase_model_name_or_path: Optional[str] = Nonerevision: Optional[str] = Noneinference_mode: bool = Falser: int = 32stride_A: int = 1num_B: int = 2scaling: float = 1.0target_modules: Optional[Union[list[str], str]] = Noneexclude_modules: Optional[Union[list[str], str]] = Nonemodules_to_save: Optional[list[str]] = Nonelayers_to_transform: Optional[Union[list[int], int]] = Nonelayers_pattern: Optional[Union[list[str], str]] = Noneinit_weights: bool = True )
Параметры
- r (
int) — ранг Lily. Определяет внутреннее скрытое измерение каждого адаптера и ранг обновления весовA @ B. В Lily количество адаптеров обычно меньше, чем в LoRA, поэтому каждому адаптеру требуется большая ёмкость, и рекомендуется использовать значениеrбольше, чем в LoRA, — как правило, в2x,3xили4xраз больше ранга LoRA, который вы обычно применяете. Общее количество обучаемых параметров масштабируется по формулеr * (total_layers / stride_A + num_B), поэтому рекомендуемый компромисс — увеличиватьr, сохраняяstride_Aбольшим, аnum_B— малым. - stride_A (
int) — Количество последовательных слоёв, которые используют один адаптер A. Например, еслиstride_A=4, каждые 4 соседних слоя используют один и тот же адаптер A, в результате чего общее количество уникальных адаптеров A составляетtotal_layers / stride_AАдаптер A сжимает входные данные до представления низкого ранга размераr.stride_Aдолжно быть не меньше- Рекомендуемые значения:
2,3или4(то есть обмен адаптерами каждые 2, 3 или 4 слоя). Сохранениеstride_Aбольшим (меньше различных адаптеров A) и увеличениеrвместо этого приводит к лучшей производительности, чем обратный компромисс (малоеstride_A, малоеr). Установкаstride_A=1означает, что каждый слой имеет собственный адаптер A. Примечание: обмен адаптерами A происходит внутри каждой целевой группы (слои с одинаковым суффиксом target). Например, если ваши target_modules равны['q_proj', 'v_proj']и вы установилиstride_A=2, то каждые 2 соседних слоя q_proj будут делить один адаптер A, а каждые 2 соседних слоя v_proj — другой адаптер A, но слои q_proj и v_proj не будут делить адаптеры A друг с другом, так как у них разные суффиксы.
- Рекомендуемые значения:
- num_B (
int) — Количество общих адаптеров B. В отличие от адаптеров A (которые группируются по слоям), все адаптеры B общие глобально для каждого слоя. При каждом прямом проходе маршрутизатор вычисляет взвешенную комбинацию всехnum_Bадаптеров B (используя веса, нормированные функцией softmax), чтобы получить единый объединенный адаптер B, который затем проецирует представление низкого ранга обратно в исходное измерение. Рекомендуется устанавливатьnum_Bв том же порядке, что иtotal_layers / stride_A. Рекомендуемые значения:total_layers / 2,total_layers / 3илиtotal_layers / 4. Аналогичноstride_A, предпочитайте меньшееnum_Bс большимr, чем большоеnum_Bс малымr. Примечание: для обучения маршрутизатора необходимо как минимум 2 адаптера B (т. е.num_B >= 2), поскольку маршрутизатор учится вычислять взвешенную комбинацию адаптеров B. Примечание: общее использование адаптеров B происходит внутри каждого целевого модуля (слои с одинаковым суффиксом целевого модуля). Например, если ваши target_modules равны['q_proj', 'v_proj']и вы установилиnum_B=4, то будет 4 адаптера B, общих для всех слоев q_proj, и еще 4 адаптера B, общих для всех слоев v_proj, но слои q_proj и v_proj не будут делить адаптеры B между собой, так как у них разные суффиксы. - target_modules (
Union[List[str], str], необязательный) — Имена модулей, к которым следует применить Lily. Может быть списком строк с именами модулей (например,['q_proj', 'v_proj']) или регулярным выражением (например,'.*decoder.*(SelfAttention|EncDecAttention).*(q|v)$'). Если не указано, Lily будет применена ко всем поддерживаемым линейным слоям. - scaling (
float) — Скалярный множитель, применяемый к объединённому выводу адаптера (scaling * A @ combined_B) перед добавлением к результату прямого прохода замороженных весов. В отличие от LoRA, Lily не использует формулировкуalpha / r; вместо этогоscalingявляется прямым множителем. Такой подход упрощает перебор значений по логарифмической шкале (например,0.01,0.1,1.0,10.0). Оптимальное значение зависит от задачи и должно рассматриваться как гиперпараметр. Рекомендуем начинать со значения1.0. - modules_to_save (
List[str], необязательный) — Список модулей, помимо слоёв Lily, которые должны быть установлены как обучаемые и сохранены в итоговой контрольной точке. Например, в задачах классификации последовательностей или классификации токенов последний слойclassifier/scoreинициализируется случайным образом, поэтому его необходимо сделать обучаемым и сохранить. - exclude_modules (
Union[List[str], str], необязательный) — Имена модулей, к которым не следует применять адаптер. При передаче строки выполняется сопоставление по регулярному выражению. При передаче списка строк выполняется точное совпадение или проверяется, заканчивается ли имя модуля каким-либо из переданных строк. - layers_to_transform (
Union[list[int], int], необязательный) — Индексы слоев для преобразования. Если этот аргумент указан, PEFT преобразует только те индексы слоев, которые перечислены в этом списке. Если передано одно целое число, PEFT преобразует только слой с этим индексом. - layers_pattern (
Optional[Union[List[str], str]], необязательный) — Имя шаблона слоя, используется только в том случае, еслиlayers_to_transformотличается от None и если шаблон слоя не входит в число общих шаблонов слоёв. Этот параметр должен указывать наnn.ModuleListмодели, который часто называется'layers'или'h'. - init_weights (
bool) — Следует ли инициализировать веса адаптера Lily с использованием схемы инициализации по умолчанию: матрицы A инициализируются методом Kaiming uniform, а матрицы B — нулями, что гарантирует нулевой выход адаптера в начале обучения и отсутствие влияния на предобученную модель. Настоятельно рекомендуется оставить это значение равнымTrue, если у вас нет конкретной причины для его изменения.
Это класс конфигурации для хранения конфигурации модели LilyModel.
LilyModel
класс peft.LilyModel
< source >( modelpeft_config: Union[PeftConfig, dict[str, PeftConfig]]adapter_name: strlow_cpu_mem_usage: bool = Falsestate_dict: Optional[dict[str, torch.Tensor]] = None ) → torch.nn.Module
Параметры
- model (
torch.nn.Module) — Модель, подлежащая адаптации. - config (LilyConfig) — конфигурация модели Lily.
- adapter_name (
str) — имя адаптера, по умолчанию"default".
Возвращает
torch.nn.Module
Модель Lily PEFT.
Создаёт модель Low-Rank Interconnected Adaptation Across Layers (Lily) на основе предобученной модели transformers.
Метод подробно описан в https://arxiv.org/abs/2407.09946.
Атрибуты:
- model (PreTrainedModel) — Модель, подлежащая адаптации.
- peft_config (LilyConfig): конфигурация модели Lily.