Своя модель

Конвертация дообученной модели в GGUF и запуск локально

Последний разрыв маршрута: от папки с весами после обучения до модели, которая отвечает в вашем ассистенте. Команды конвертации и квантизации, Modelfile и проверка результата.

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

Этот разрыв закрывается тремя командами. Ниже — они и то, где на этом коротком пути обычно спотыкаются.

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

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

Что именно представляет собой целевой формат и почему он стал стандартом локального запуска — в разборе формата GGUF.

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

  • Слитая модель — база с вплавленным адаптером. Если у вас пока отдельный адаптер, сначала слияние: процедура в статье про слияние адаптера с моделью.
  • Исходники llama.cpp — конвертер и утилита квантизации лежат там.
  • Место на диске. Промежуточный файл в 16 битах весит примерно вдвое больше числа параметров в гигабайтах; квантованный — заметно меньше.
  • Python-окружение для конвертера. Отдельное от обучающего, чтобы не ломать версии.

#Шаг 1. Конвертация в GGUF

git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
pip install -r requirements.txt

python convert_hf_to_gguf.py ../out/persona-merged --outfile ../persona-f16.gguf

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

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

#Шаг 2. Квантизация

cmake -S . -B build
cmake --build build -j --target llama-quantize

./build/bin/llama-quantize ../persona-f16.gguf ../persona-q4.gguf Q4_K_M

Q4_K_M — практический выбор по умолчанию: заметное сокращение размера при умеренной потере качества. Что означают суффиксы и где проходит точка перелома — в разборе квантизации LLM.

Ориентир по размеру: для базы на четыре миллиарда параметров результат в Q4_K_M получается около двух с половиной гигабайт — именно это число записано в нашем Colab-ноутбуке для «второй копии». Для полутора миллиардов — порядка гигабайта.

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

#Шаг 3. Описание модели для движка

Рядом с квантованным файлом создайте Modelfile:

FROM ./persona-q4.gguf
PARAMETER temperature 0.7
PARAMETER num_ctx 4096
SYSTEM """Здесь тот же характер, который вы задавали при обучении."""

Три параметра здесь не случайны.

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

num_ctx. Длина контекста. Кэш контекста занимает память отдельно от весов модели, поэтому это первый параметр, который снижают при нехватке памяти.

temperature. Для рассуждающих баз важна отдельно: жадная генерация приводит их к зацикливанию, и в нашем ноутбуке для такой базы прямо указаны значения температуры 0,6 с ограничением по вероятностной массе. Для обычной инструктивной базы 0,7 — разумное начало.

Подробный разбор всех директив описания модели — в гайде по Modelfile.

#Шаг 4. Регистрация и запуск

ollama create persona-mini -f Modelfile
ollama run persona-mini

Дальше модель доступна как любая другая локальная: из терминала, по API и из вашего ассистента — в Persona она выбирается в настройках подключения модели как обычная модель провайдера Ollama.

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

Пять проверок, каждая ловит свой класс поломок:

  1. Модель отвечает и останавливается. Договаривает за пользователя или не умолкает — потерян шаблон чата или токен конца реплики.
  2. В ответе нет служебных строк. Маркеры ролей внутри текста — тот же диагноз.
  3. Стиль совпадает с тем, что показало слепое сравнение до конвертации. Разошёлся — виновата квантизация либо системный промпт в описании модели.
  4. Модель помещается в память. Если движок выгружает часть слоёв на процессор, скорость упадёт кратно, и вы это заметите.
  5. Ответы воспроизводимы при одинаковых настройках. Разброс при одинаковых параметрах — признак того, что настройки сэмплинга применяются не те, что вы задали.

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

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

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

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

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

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

Целевой формат рассчитан на цельную модель, поэтому практический путь — сначала слияние, потом конвертация. Если вам нужно именно переключение между несколькими адаптерами, оставайтесь в среде, которая их поддерживает, — после конвертации эта возможность теряется.

#Какой уровень квантизации выбрать?

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

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

Порядок величины: число параметров в миллиардах, умноженное примерно на 0,6–0,7 гигабайта для четырёхбитного варианта. Для базы на четыре миллиарда это около двух с половиной гигабайт. Точное значение зависит от архитектуры и уровня квантизации.

#Нужен ли системный промпт, если модель дообучена?

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

#Модель влезает по весу, но работает медленно. Почему?

Скорее всего, часть слоёв выгружена на процессор из-за кэша контекста: он занимает память отдельно от весов и растёт с длиной контекста. Снизьте её и проверьте, ушла ли выгрузка.

#Вывод

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

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

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

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

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