Своя модель

Слияние адаптера с моделью: когда это нужно

Слияние нужно ровно тогда, когда рантайм не понимает адаптеры. Взамен вы теряете возможность переключать поведение и получаете лишние гигабайты на диске. Команды и таблица «когда сливать».

После обучения у вас на диске лежит папка на десятки мегабайт. Это адаптер, а не модель: он работает только вместе с базой, под которую обучен. Большинство инструкций сразу советуют «слить его в базу» — и почти никогда не объясняют, что вы при этом теряете.

#Зачем это нужно и когда не нужно

Слияние нужно ровно в одном случае: движок, в котором вы собираетесь запускать модель, не умеет загружать адаптеры отдельно. Это касается большинства массовых локальных движков — они ожидают один файл модели.

Не нужно, если вы работаете в среде, которая адаптеры понимает. Тогда раздельное хранение даёт то, ради чего адаптеры и придумали: одна база на диске и несколько сменных файлов поведения. Механика этого разобрана в статье про устройство адаптеров.

#Что понадобится

  • Папка с адаптером после обучения (файлы адаптера и его конфигурация).
  • Та же базовая модель, на которой обучали, — той же версии.
  • Свободное место на диске: результат слияния весит столько же, сколько база, то есть гигабайты.
  • Оперативная память под загрузку базы в полной точности. Слияние делается не в 4 битах.

#Шаг 1. Слияние

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

from peft import AutoPeftModelForCausalLM
from transformers import AutoTokenizer

ADAPTER = "out/persona-lora"
MERGED  = "out/persona-merged"

model = AutoPeftModelForCausalLM.from_pretrained(ADAPTER)
model = model.merge_and_unload()          # поправка складывается с базовыми весами
model.save_pretrained(MERGED)

# Токенизатор переносится отдельно — без него модель не запустится
AutoTokenizer.from_pretrained(ADAPTER).save_pretrained(MERGED)

Две ловушки в этих пяти строках.

Токенизатор. Его надо сохранить явно. Забыли — получите папку с весами, которую нечем токенизировать, и обнаружите это только на запуске.

Точность загрузки. Сливать надо базу в её обычной точности, а не в 4 битах, даже если обучали в QLoRA. Слияние поправки со сжатыми весами вносит дополнительную ошибку — разбор компромисса в статье про LoRA и QLoRA.

#Шаг 2. Что делать с результатом

После слияния у вас обычная модель в формате библиотеки. Для локального запуска её ещё нужно перевести в формат вашего движка и, скорее всего, квантовать — полный маршрут в статье про конвертацию в GGUF и запуск локально.

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

#Проверка результата

Слияние прошло успешно, если:

  1. Папка результата содержит и веса, и файлы токенизатора. Отсутствие второго — самая частая поломка.
  2. Модель загружается без упоминания адаптера в конфигурации.
  3. Ответы на ваш проверочный набор совпадают с тем, что давала связка «база + адаптер». Не «похожи», а совпадают по манере: расхождение означает, что слияние выполнено в другой точности или с другой версией базы.
  4. Размер папки соответствует базе, а не адаптеру. Если результат весит десятки мегабайт, слияния не произошло.

Третий пункт проверяйте протоколом слепого сравнения — он же годится и для этой задачи, описан в статье про честную оценку дообученной модели.

#Таблица: когда сливать и когда нет

Ситуация Сливать Почему
Запуск в массовом локальном движке да адаптеры не поддерживаются
Конвертация в формат для локального запуска да конвертер ожидает цельную модель
Передача модели другому человеку да одна сущность вместо двух
Несколько режимов на одной базе нет теряется переключение
Место на диске ограничено нет база останется одна
Планируются новые прогоны обучения нет обучать надо от базы, не от слитой версии
База может обновиться нет адаптер переносится, слитая модель нет

Строки со «нет» сводятся к одному: слияние — операция односторонняя. Разделить слитую модель обратно на базу и адаптер нельзя.

#Что может пойти не так

  • Не сохранён токенизатор. Модель не запускается или выдаёт мусор. Сохраняйте явно, как в скрипте выше.
  • Слияние в 4 битах. Результат чуть хуже связки «база плюс адаптер», и разница проявляется не сразу. Сливайте в обычной точности.
  • Не хватило памяти. Слияние требует держать базу целиком. Если оперативной памяти мало, делайте слияние там же, где обучали, — на арендованной машине.
  • Другая версия базы. Адаптер обучен под конкретные веса; слияние с обновлённой базой формально пройдёт, а поведение будет непредсказуемым.
  • Слитая модель отвечает иначе, чем связка. Проверьте точность загрузки и версию базы. Совпадение поведения — критерий корректного слияния.
  • Адаптер удалён после слияния. Восстановить его из слитой модели невозможно. Держите оба.

Полный маршрут от датасета до запущенной локально модели, куда этот шаг встроен, — в гайде как обучить вторую копию на QLoRA, а общая рамка — в пилларе про свою модель и дообучение под себя.

#Частые вопросы

#Можно ли разделить слитую модель обратно?

Нет. Слияние складывает поправку с базовыми весами, и восстановить слагаемые из суммы нельзя. Именно поэтому адаптер стоит хранить: он и есть ваша страховка.

#Слитая модель работает быстрее?

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

#Можно ли слить два адаптера сразу?

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

#Что делать, если базовая модель обновилась?

Переобучить адаптер на новой базе и слить заново. Перенос старого адаптера на обновлённые веса формально возможен, но проверять его придётся полностью, и обычно это дороже нового прогона.

#Сколько весит результат слияния?

Столько же, сколько базовая модель, — гигабайты. Экономия адаптерного подхода при слиянии исчезает: три слитых режима это три полных копии базы, тогда как три адаптера — это база плюс десятки мегабайт.

#Вывод

Слияние — техническая операция ради совместимости, а не улучшение модели. Качество от него не растёт, а гибкость падает: вы меняете «база плюс сменный файл поведения» на монолит.

Правило простое: сливайте, если ваш движок запуска не понимает адаптеры или если модель надо кому-то передать. Во всех остальных случаях держите базу и адаптер раздельно — и не удаляйте адаптер даже после слияния.

Хотите ИИ, который помнит вас?

Persona держит контекст между чатами и работает на вашем железе — если развернуть её у себя и подключить локальную модель.

Создать аккаунт