PEFT documentation

ShadowPEFT

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

and get access to the augmented documentation experience

to get started

ShadowPEFT

ShadowPEFT дополняет замороженную базовую модель, работающую только в режиме декодирования, лёгкой, обучаемой теневой сетью, которая работает параллельно с основным каркасом. Небольшой теневой каркас формирует начальное теневое состояние s^(0), которое затем проходит по циклу декодера базовой модели: на каждом целевом блоке расхождение между скрытыми состояниями базовой модели и теневым состоянием добавляется обратно во вход блока (низкоранговая коррекция), а теневое состояние обновляется по гейтированному остаточному обновлению, вычисленному на основе выхода блока. Обучаются только теневые компоненты; базовая модель остаётся замороженной.

Input
  ├──► Shadow backbone (small, trainable) ──► s^(0)
  └──► Base model (frozen, large)
         block_0 ◄── inject(h, s) ─► h_0 ──► update ─► s_1
         block_1 ◄── inject(h, s) ─► h_1 ──► update ─► s_2
         ...                       (the (hidden, shadow) pair rides the loop together)

Поскольку адаптация представляет собой зависящую от входных данных траекторию в пространстве слоёв (теневое состояние эволюционирует вместе с данными), а не статическую дельту в пространстве весов, ShadowPEFT не может быть объединён с базовыми весами. Вызов merge, merge_adapter или merge_and_unload приводит к явной ошибке. Для языковых моделей Transformers можно получить лёгкую теневую сеть отдельно с помощью model.base_model.unload_shadow(), что возвращает автономный DetachedShadowModel. Автономная выгрузка не поддерживается для моделей Diffusers, поскольку восстановление полного денойзера зависит от архитектуры.

Добавление нескольких адаптеров, переключение между ними с помощью set_adapter, их удаление, а также включение и отключение работают так же, как и в других методах PEFT. Одновременно может быть активен только один адаптер, поскольку теневое состояние представляет собой единственную траекторию через сеть.

Теневой базовый блок можно построить двумя способами, которые контролируются параметром ShadowConfig.shadow_model:

  • "mirror" (по умолчанию): автоматически создаётся более лёгкий теневой backbone. Языковые модели используют уменьшенную копию базовой архитектуры. Архитектуры Diffusers с зарегистрированным backend используют уменьшенную модель, аналогичную архитектуре, инициализированную из выбранных базовых весов; совместимые архитектуры без backend откатываются к поэлементному residual MLP. Если размер скрытого слоя теневой модели отличается от базового, обученная проекция компенсирует эту разницу.
  • идентификатор модели или локальный путь: базовая модель загружается как более мелкая предобученная модель. Модели Transformers используют AutoModel; зарегистрированные бэкенды Diffusers определяют собственную совместимую загрузку контрольных точек.

Поддержка Diffusers с учётом архитектуры выбирается автоматически на основе класса модели. Для Flux2 в настоящее время зарегистрирован отдельный бэкенд; другие совместимые трансформерные модели Diffusers используют универсальный fallback на основе MLP. Самостоятельный вызов unload_shadow() по-прежнему не поддерживается для всех моделей Diffusers, поскольку восстановление полного денойзера зависит от конкретной архитектуры.

В отличие от методов в стиле LoRA, ShadowPEFT добавляет больше параметров и вычислений (он запускает параллельную сеть и оборачивает целые блоки декодера), но адаптер представляет собой автономную сеть, которую можно обучать централизованно, переиспользовать для разных задач и инициализировать из предварительно обученной небольшой модели. Необязательный вспомогательный потерь (auxiliary_loss_weight) применяет головку задачи к начальному теневому состоянию s^(0) и добавляет её к потере задачи, побуждая отключаемый теневой путь решать задачу самостоятельно. Для каузальных LM переиспользуется базовая головка вывода; включите "lm_head" в modules_to_save, чтобы обучить и сохранить её через стандартный механизм PEFT.

Кэш KV

ShadowPEFT поддерживает инкрементальное декодирование с dual KV-кэшем: один для замороженной базовой модели и один для теневой основы. Инжекция и обновление локальны по токенам, поэтому для нового токена требуется только его собственное теневое состояние s; причинность сохраняет валидность ключей и значений префикса базовой модели (вычисленных при инжекции). Сопоставленный объект — ShadowCache, который возвращается как past_key_values, если use_cache=True. Вы можете передать use_cache=True в generate() как обычно.

out = model.generate(input_ids, max_new_tokens=32)  # dual KV cache enabled by default
# or explicitly:
out = model.generate(input_ids, use_cache=True, max_new_tokens=32)

use_cache=False по-прежнему работает и пересчитывает всю последовательность на каждом шаге (полезно для отладки).

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

from transformers import AutoModelForCausalLM
from peft import ShadowConfig, get_peft_model

model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-0.6B")
config = ShadowConfig(r=8, shadow_num_hidden_layers=1, task_type="CAUSAL_LM")
model = get_peft_model(model, config)
model.print_healthcheck()

out = model.generate(input_ids, max_new_tokens=32)

Чтобы инициализировать теневой backbone из более мелкой предобученной модели, передайте её id или путь как shadow_model:

config = ShadowConfig(shadow_model="Qwen/Qwen3-0.6B", task_type="CAUSAL_LM")
model = get_peft_model(base_model, config)

Оценка теневой траектории

По умолчанию выход модели (logits) — это базовая модель с теневой адаптацией: теневые корректировки внедряются в скрытые состояния базовой модели на каждом слое, поэтому logits уже отражают ShadowPEFT (чтобы получить чистую базовую модель для сравнения, используйте model.disable_adapter()). Дополнительный вспомогательный loss дополнительно обучает теневой путь решать задачу самостоятельно.

Для оценки автономной теневой сети языковой модели Transformers (отделяемая, легковесная модель — аналог ShadowPEFT для merge_and_unload) используйте unload_shadow(). Она возвращает head(projection(backbone(x))) как обычную модель для задачи, которую можно оценивать так же, как любую другую: для задачи causal-LM это генерирующая causal LM (поддерживает generate() и кэширование KV), а для задачи классификации последовательности она агрегирует последний токен и возвращает классовые логиты. Вызов этого метода для модели Diffusers вызывает NotImplementedError.

shadow = model.base_model.unload_shadow()  # a DetachedShadowModel (a PreTrainedModel)
shadow.eval()
# causal LM:
out = shadow.generate(input_ids, max_new_tokens=32)
# sequence classification:
logits = shadow(input_ids=input_ids, attention_mask=attention_mask).logits  # (batch, num_labels)

По умолчанию (copy=False) возвращаемая модель разделяет свои модули с моделью PEFT, а теневой базовый блок, разделяющий замороженные входные эмбеддинги, получает к ним доступ через ссылку, которая не является подмодулем. Это нормально для оценки, но это означает, что save_pretrained запишет контрольную точку без таблицы эмбеддингов. Передайте copy=True, если вы хотите сохранить или опубликовать автономную модель:

shadow = model.base_model.unload_shadow(copy=True)
shadow.save_pretrained("standalone-shadow")

API

ShadowConfig

класс peft.ShadowConfig

< >

( 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 = Falsetarget_modules: list[str] | str | None = Noneexclude_modules: list[str] | str | None = Noner: int = 8shadow_alpha: float = 0.1shadow_dropout: float = 0.2init_weights: bool = Trueshadow_model: str = 'mirror'shadow_num_hidden_layers: int | None = Noneshadow_hidden_size: int | None = Noneshadow_num_attention_heads: int | None = Noneshadow_intermediate_size: int | None = Noneshare_embeddings: bool = Trueupdate_hidden_size: int | None = Noneauxiliary_loss_weight: float = 0.05layers_to_transform: list[int] | int | None = Nonelayers_pattern: list[str] | str | None = Nonemodules_to_save: list[str] | None = None )

Параметры

  • target_modules (Optional[Union[list[str], str]]) — Трансформерные блоки, которые нужно обернуть механизмом shadow (целые декодерные блоки, а не линейные слои). Может быть списком имён модулей или регулярным выражением, например r'.*\.layers\.\d+$', чтобы захватить каждый декодерный блок. По умолчанию None, в этом случае оборачиваются все декодерные блоки базовой модели. Обратите внимание, что оборачиваемые блоки должны быть непрерывными, поскольку shadow-состояние передаётся по циклу декодера от первого оборачиваемого блока до последнего.
  • exclude_modules (Optional[Union[list[str], str]]) — Имена модулей, которые не следует оборачивать с помощью теневой механики, заданные в виде списка или регулярного выражения. По умолчанию None.
  • r (int) — Ранг бутылочного горлышка низкорангового внедрения W_down / W_up. По умолчанию 8.
  • shadow_alpha (float) — Сила вводимой коррекции, добавляемой к входу блока (формула 4). По умолчанию 0.1.
  • shadow_dropout (float) — Вероятность dropout, применяемая к сигналу расхождения перед бутылочным горлышком (формула 3). По умолчанию 0.2.
  • init_weights (bool) — Определяет, следует ли обнулять инициализацию W_up, чтобы инъекция не влияла на модель в начале обучения (по аналогии с конвенцией B=0 в LoRA). Не изменяйте это значение, если точно не знаете, что делаете. По умолчанию True.
  • shadow_model (str) — Способ построения теневой базовой модели. "mirror" (по умолчанию) строит новую базовую модель той же архитектуры, что и исходная модель, но с меньшим количеством/размером слоёв (см. переопределения shadow_* ниже). Архитектуры Diffusers с зарегистрированным теневым бэкендом используют модель с уменьшенной архитектурой; другие совместимые диффузионные трансформеры откатываются к универсальному посимвольному MLP. Любая другая строка рассматривается как идентификатор модели или локальный путь. «Проецированная» теневая контрольная точка Transformers (model_type == "causal_lm_with_hidden_projection", например shadow-llm/Qwen3-0.6B-H8B) загружает её предобученную базовую модель вместе с обученным проекционным слоем теневых скрытых состояний -> скрытых состояний базовой модели. Явные контрольные точки Diffusers требуют зарегистрированного бэкенда; в настоящее время поддерживается Flux2.
  • shadow_num_hidden_layers (Optional[int]) — Глубина автоматически создаваемого ("mirror") теневого каркаса. Для Flux2 это определяет требуемое количество двухпоточных блоков и вдвое больше однопоточных блоков; для универсального fallback в Diffusers — это количество остаточных MLP-блоков. По умолчанию None (1 слой).
  • shadow_hidden_size (Optional[int]) — Размер скрытого слоя автоматически создаваемого теневого базового блока; может отличаться от базового размера скрытого слоя (проекция вставляется автоматически). Бэкенды архитектуры могут накладывать дополнительные ограничения; для сокращений Flux2 необходимо сохранять базовое измерение головы внимания. По умолчанию None (как у базовой модели).
  • shadow_num_attention_heads (Optional[int]) — Количество голок внимания в автоматически создаваемом теневом базовом блоке. По умолчанию None (как в базовой модели). Этот параметр используется архитектура-зависимыми бэкендами, но не универсальным фолбэком Diffusers на основе MLP.
  • shadow_intermediate_size (Optional[int]) — Ширина полносвязного слоя автоматически создаваемого теневого каркаса. По умолчанию None (совпадает с размером скрытого слоя для универсального резервного варианта MLP в Diffusers).
  • share_embeddings (bool) — Определяет, следует ли повторно использовать замороженные входные эмбеддинги базовой модели для подачи в теневой ствол (через inputs_embeds) вместо собственной таблицы эмбеддингов теневого ствола. По умолчанию True.
  • update_hidden_size (Optional[int]) — Скрытая ширина MLP-слоёв обновления T (кандидат) и G (шлюз). По умолчанию None (используется r).
  • auxiliary_loss_weight (float) — Вес lambda вспомогательной тени потери (формулы 8–9), который добавляется к потере задачи при передаче labels. Циклы обучения диффузии могут использовать то же значение для отсоединённой потери денойзинга. Установите 0, чтобы отключить. По умолчанию 0.05.
  • layers_to_transform (Optional[Union[list[int], int]]) — Индексы блоков для преобразования. Если передан список, механизм shadow применяется к блокам с этими индексами. Если передано одно целое число, он применяется только к блоку с этим индексом. По умолчанию None (преобразуются все подходящие блоки).
  • layers_pattern (Optional[Union[list[str], str]]) — Имя шаблона слоя, используется только в том случае, если layers_to_transform отличается от None. Это имя nn.ModuleList, содержащего блоки декодера (часто "layers" или "h"). По умолчанию None.
  • modules_to_save (Optional[list[str]]) — Дополнительные модули, которые нужно сделать обучаемыми и сохранить в итоговой контрольной точке (например, "lm_head" или классификатор). По умолчанию None.

Класс конфигурации для ShadowModel (ShadowPEFT).

ShadowPEFT дополняет замороженную базовую модель только с декодером небольшой обучаемой параллельной shadow-сетью. Shadow-каркас формирует начальное shadow-состояние s^(0), которое затем проходит по циклу декодера базовой модели: на каждом целевом блоке расхождение между скрытыми состояниями базовой модели и shadow-состоянием подмешивается обратно во вход блока (формулы 2–4), а shadow-состояние обновляется по выходу блока с помощью гейтированного остаточного обновления (формулы 5–7). Обучаются только shadow-компоненты; базовая модель остаётся замороженной. Поскольку адаптация представляет собой зависящую от входных данных траекторию в пространстве слоёв, а не статическую дельту весов, ShadowPEFT нельзя объединить с весами базовой модели.

ShadowModel

класс peft.ShadowModel

< >

( modelpeft_config: Union[PeftConfig, dict[str, PeftConfig]]adapter_name: strlow_cpu_mem_usage: bool = Falsestate_dict: Optional[dict[str, torch.Tensor]] = None )

Создаёт модель ShadowPEFT на основе предобученной модели transformers.

ShadowPEFT дополняет замороженную базовую модель только с декодером небольшой обучаемой параллельной shadow-сетью. Shadow-каркас формирует начальное shadow-состояние, которое проходит по циклу базового декодера; на каждом целевом блоке расхождение между скрытыми состояниями базовой модели и shadow-состоянием вводится в блок, а shadow-состояние обновляется по гейтированному остаточному обновлению. Обучаются только shadow-компоненты. См. ShadowConfig для конфигурации.

Метод не может быть объединён с базовыми весами (адаптация представляет собой зависящую от входных данных траекторию, а не статическую дельту весов); вместо этого используйте ShadowModel.unload_shadow(), чтобы получить автономную теневую сеть.

shadow_auxiliary_loss

< >

( labels: Tensorattention_mask: torch.Tensor | None = None )

Собственная функция потерь задачи теневого пути, CE(shadow_head(s^(0)), labels) (без весов; forward применяет вес).

Потери вычисляются на начальном теневом состоянии s^(0) (выход теневой базовой сети, проецированный) — ровно то, что автономная модель unload_shadow() вычисляет как head(projection(backbone(x))). Именно это позволяет использовать отсоединённую теневую сеть самостоятельно; обучение её на s^(L) (конечное состояние, которое зависит от выходов базовой модели по слоям и не существует автономно) оставило бы отсоединённую модель необученной.

unload_shadow

< >

( adapter_name: str | None = Nonecopy: bool = False )

Параметры

  • adapter_name (str, необязательный) — Адаптер, теневую сеть которого нужно выгрузить. По умолчанию используется активный адаптер.
  • copy (bool, необязательный, по умолчанию False) — Если True, выполняется глубокое копирование возвращаемой модели, чтобы она была независима от текущей (требует больше памяти). Если False (по умолчанию), модули разделяются — аналогично merge_and_unload, который переиспользует модули, а не клонирует их. Изменение одной модели влияет на другую.

Возвращает теневой backbone (+ head) как самостоятельную модель, без базовой модели.

Аналог merge_and_unload в ShadowPEFT: если тот возвращает базовую модель с «впечённой» адаптацией, то этот метод возвращает только легковесную теневую сеть для высокоэффективного / edge-инференса. Он выполняет head(projection(backbone(x))) — обновления по блокам требуют выходов базовой модели и поэтому не существуют автономно. Для языковых моделей результат ведёт себя как обычная каузальная LM (поддерживает generate() и кэширование KV). Модели Diffusers не поддерживаются, поскольку реконструкция полного автономного денойзера специфична для каждой архитектуры диффузии.

Присвойте результат переменной и используйте его; при copy=False модули остаются общими с этой моделью.

Передавайте copy=True, если вы планируете сохранить автономную модель с помощью save_pretrained. Теневой базовый блок, который разделяет замороженные входные эмбеддинги базовой модели (настройка по умолчанию "mirror"), обращается к ним через ссылку, которая не является подмодулем возвращаемой модели, поэтому чекпоинт с copy=False не содержит таблицу эмбеддингов; copy=True привязывает приватную копию и сохраняет полный чекпоинт.

ShadowCache

класс peft.tuners.shadow.ShadowCache

< >

( base: Any = Noneshadow: Any = None )

Связанные кэши KV для инкрементного декодирования ShadowPEFT.

Для авторегрессионной генерации требуется кэш базовой модели (ключи/значения, вычисленные при теневой инъекции) и отдельный кэш теневой модели (для продвижения токена s^(0) по одному токену). Это подкласс Cache из Transformers: операции, влияющие на структуру батча или последовательности (сброс, переупорядочивание, обрезка, повторение и выбор), применяются к обоим кэшам, тогда как метаданные внимания и обновления делегируются базовому кэшу. Неизвестные атрибуты кэша также делегируются базовому кэшу для обеспечения совместимости с реализациями кэша, специфичными для архитектуры.

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

Update on GitHub