- BrainTools - https://www.braintools.ru -
Привет, хабровчане!
Признаюсь, я не большой любитель vLLM [1], Triton Inference Server [2] и всяких там NeMo [3], вместо них я предпочитаю ollama [4] вообще и llama.cpp [5] в частности, поскольку придерживаюсь мнения, что 1-2% потери в точности и отсутствие некоторых плюшек – не так важно, по сравнению с удобством деплоя, спекулятивным декодингом, многократным приростом скорости, динамическим оффлодом в память [6] системы и возможностью запускать модели на любом “ведре”, навроде древних зионов, андройдофонов, малинок или, скажем, макбуков.
Поэтому вполне ожидаемым для меня является, когда авторы моделей заморачиваются с конвертацией оных в GGUF [7] – особом формате сжатия весов моделей, пригодном для запуска через упомянутые выше ollama и llama.cpp.
Однако реальность обычно немного отличается от ожиданий, и конвертацию в GGUF с последующей квантизацией приходится делать самостоятельно, а чтобы качество работы модели не падало, желательно генерировать imatrix [8] через калибровочный датасет, о чём я и хочу рассказать в данной публикации.

Поскольку большинство вендоров (и наши соотечественники в том числе) частенько пренебрегают данным форматом, приходится брать рога за быка и конвертировать, а затем квантовать модельки в GGUF самостоятельно. Но у конвертации в данный формат с дальнейшей квантизацией “в лоб” есть один фатальный недостаток – такие квантованные модели обычно проседают в точности, так как сжатие выполняется наивно, без учёта архитектуры и знаний, заложенных при обучении [9] модели.
Более правильным методом является квантизация модели при помощи калибровочного датасета, содержащего в себе только необходимые для нас данные; данный приём можно условно описать как “LoRA наоборот”, так как мы не обучаем модель на специализированном корпусе, а наблюдаем за её поведением [10] на близких к продуктовым задачам кейсах, затем отсекаем всё ненужное. Нечто подобное применяется в методе GPTQ [11], но поскольку формат GPTQ так и не обрёл популярности, о его поддержке в llama.cpp (и, как следствие, ollama) не может быть и речи.
Да и зачем он нужен, когда в llama.cpp сравнительно недавно добавили утилиту imatrix [8]?
Вот небольшая справка от ChatGPT обогащённая контекcтом и моим советами:
Инструмент
llama-imatrixв llama.cpp предназначен для вычисления и сохранения матрицы важности (importance matrix), отражающей, насколько сильно различные тензоры модели (веса слоёв) влияют на результат при обработке реального текстового корпуса, эта статистика используется при квантизации, чтобы сохранить качество модели – более “важные” параметры квантуются с меньшими потерями.llama-imatrixанализирует активации модели на заданных текстах, накапливает показатели важности для каждого тензора, сохраняет их в файл, после чего квантизаторllama-quantizeможет учитывать эти данные для адаптивного понижения точности весов.
Поэтому решил разобраться сам и рассказать вам, как конвертировать, а затем квантовать в GGUF на примере модельки ai-sage/GigaChat-20B-A3B-instruct [12], используя для калибровки датасет wikimedia/wikipedia [13], а точнее – первые 500 элементов сабсета 20231101.ru.
Для начала понадобится скачать и конвертировать модель ai-sage/GigaChat-20B-A3B-instruct [12] в GGUF без квантизации, в формате F16. Для этого скачаем репозиторий llama.cpp, затем создадим в нём .venv, поставим пакеты и выполним сборку llama.cpp:
git clone https://github.com/ggml-org/llama.cpp.git
cd llama.cpp
python3.12 -m venv .venv
source .venv/bin/activate
Скомпилируем бинарники:
cmake -S . -B build -DGGML_CUDA=ON -DCMAKE_BUILD_TYPE=Release
Подробнее [14] про компиляцию llama.cpp под разные платформы, в том числе и CUDA в README проекта.
Поставим ещё пару пакетов до кучи:
pip install "datasets>=4.1" "transformers>=4.56"
Песочница готова, так что теперь можем скачать веса модели и выполнить конвертацию:
hf download ai-sage/GigaChat-20B-A3B-instruct --local-dir ./models/ai-sage/GigaChat-20B-A3B-instruct
python convert_hf_to_gguf.py models/ai-sage/GigaChat-20B-A3B-instruct
Результат будет сохранён тут:
./models/ai-sage/GigaChat-20B-A3B-instruct/GigaChat-20B-A3B-instruct-F16.gguf
Запомним и вернёмся к этому чуть позже.
Зная формат данных датасета wikimedia/wikipedia [15] и зная, как обычно тренеры моделей формируют из семплов датасета обучающие примеры (спойлер: при помощи метода apply_chat_template [16] объекта токенизатора), создадим небольшой скриптик, обзовём его wikipedia_generator.py [17], положим его в папку с llama.cpp и запустим вот так:
python wikipedia_generator.py
--model ai-sage/GigaChat-20B-A3B-instruct
--subset 20231101.ru
--split train
--limit 500
--output ./calib.txt
Рядом появится файлик ./calib.txt, его и будем использовать далее.
Теперь вызовем скомпилированный ранее бинарник llama-imatrix, передадим на вход путь до калибровачного датасета, созданного шагом ранее, и путь до квантованной в GGUF модели:
./build/bin/llama-imatrix
-m ./models/ai-sage/GigaChat-20B-A3B-instruct/GigaChat-20B-A3B-instruct-F16.gguf
-f ./calib.txt
-o ./models/ai-sage/GigaChat-20B-A3B-instruct/GigaChat-20B-A3B-instruct-F16.imatrix.gguf
--n-gpu-layers 10
И идём читать arXiv пару часов, так как процедура обычно не быстрая.
По прошествии некоторого времени результат работы скрипта будет сохранён тут:
./models/ai-sage/GigaChat-20B-A3B-instruct/GigaChat-20B-A3B-instruct-F16.imatrix.gguf
Размером примерно 41 мегабайт, для разных моделей размер может варьироваться от 1-2 до 30-40 мегабайт, как правило у классических dense моделей размер этого файла меньше чем у MoE моделей, вероятно в силу особенностей архитекруты.
Теперь мы можем при помощи скомпилированной утилиты llama-quantize выполнить квантизацию модели до уровня q4_k_m, но не абы как, а с учётом поправок полученных на датасете wikimedia/wikipedia при помощи llama-imatrix.
Пишем команду:
./build/bin/llama-quantize
--imatrix ./models/ai-sage/GigaChat-20B-A3B-instruct/GigaChat-20B-A3B-instruct-F16.imatrix.gguf
./models/ai-sage/GigaChat-20B-A3B-instruct/GigaChat-20B-A3B-instruct-F16.gguf
./models/ai-sage/GigaChat-20B-A3B-instruct/GigaChat-20B-A3B-instruct-Q4_K_M.gguf
Q4_K_M
Квантованная в q4_k_m модель будет сохранена тут:
./models/ai-sage/GigaChat-20B-A3B-instruct/GigaChat-20B-A3B-instruct-Q4_K_M.gguf
Аналогичным образом будет выглядеть процедура квантизации до других уровней, только циферки меняй, полный список всех доступных уровней квантизации тут [18].
Отлично, у нас есть моделька, конвертированная в GGUF и квантованная до q4_k_m, что дальше? Дальше можно запустить её, например, через llama-server или llama-cli и попробовать повыполнять на ней запросы, а можно пойти ещё дальше и импортировать её в локальную ollama.
Для этого создадим файл Modelfile следующего содержимого:
FROM ./models/ai-sage/GigaChat-20B-A3B-instruct/GigaChat-20B-A3B-instruct-Q4_K_M.gguf
TEMPLATE """
{{- if .System }}
<s>{{ .System }}<|message_sep|>
{{- end }}
{{- range .Messages }}
{{- if eq .Role "user" }}
{{ .Role }}<|role_sep|>{{ .Content }}<|message_sep|>
available functions<|role_sep|>[]<|message_sep|>
{{- else if eq .Role "assistant" }}
{{ .Role }}<|role_sep|>{{ .Content }}<|message_sep|>
{{- end }}
{{- end }}
{{- if not .Response }}assistant<|role_sep|>
{{- end }}
"""
Поле TEMPLATE обычно отличается у разных моделей.
Подробнее про создание Modelfile [19] в документации ollama.
Далее импортируем этот Modelfile в нашу локальную ollama:
ollama create -f Modelfile GigaChat-20B-A3B-instruct:Q4_K_M
Вместо GigaChat-20B-A3B-instruct:Q4_K_M можно указать любое другое название, это проссто тег, которым ollama пометит эту модель.
Попробуем запустить модель:
ollama run GigaChat-20B-A3B-instruct:Q4_K_M
И можем пообщаться.
Про интеграцию через API рассказывать уже не буду, это и так понятно, на http://localhost:11434 [20] ходим клиентом ollama [21], на http://localhost:11434/v1 [22] клиентом openai [23], в поле model узказываем GigaChat-20B-A3B-instruct:Q4_K_M.
Если коротко то история вида: конвертация в GGUF > калибровка imatrix > квантизация > запуск в llama.cpp/ollama помогает нам отлично масштабироваться “вниз”, не требуя дата-центров и дорогих GPU. Используя imatrix мы целенаправленно “подгоняем” квантизацию под свои кейсы (через калибровочный корпус), срезая лишнее, сохраняя только нужное, получаем быстрый деплой и переносимость, но при этом сохраняем качество.
Надеюсь моя небольшая инструкция пригодится вам в ваших начинаниях!
Если вам интересно, как это развивать дальше, то заглядывайте ко мне в Телегу @evilfreelancer [24], и само собой задавайте вопросы под постом и/или в личку, буду рад пообщаться.
Автор: efreelancer
Источник [25]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/20332
URLs in this post:
[1] vLLM: https://github.com/vllm-project/vllm
[2] Triton Inference Server: https://github.com/triton-inference-server/server
[3] NeMo: https://github.com/NVIDIA-NeMo/NeMo
[4] ollama: https://github.com/ollama/ollama
[5] llama.cpp: https://github.com/ggml-org/llama.cpp
[6] память: http://www.braintools.ru/article/4140
[7] GGUF: https://huggingface.co/docs/hub/en/gguf
[8] imatrix: https://github.com/ggml-org/llama.cpp/tree/master/tools/imatrix
[9] обучении: http://www.braintools.ru/article/5125
[10] поведением: http://www.braintools.ru/article/9372
[11] GPTQ: https://github.com/ModelCloud/GPTQModel
[12] ai-sage/GigaChat-20B-A3B-instruct: https://huggingface.co/ai-sage/GigaChat-20B-A3B-instruct
[13] wikimedia/wikipedia: https://huggingface.co/datasets/wikimedia/wikipedia
[14] Подробнее: https://github.com/ggml-org/llama.cpp?tab=readme-ov-file#supported-backends
[15] wikimedia/wikipedia: https://huggingface.co/datasets/wikimedia/wikipedia/viewer/20231101.ru
[16] apply_chat_template: https://huggingface.co/docs/transformers/en/chat_templating
[17] wikipedia_generator.py: https://gist.github.com/EvilFreelancer/dd1333ee965dc8a01a9218c7ffd95af2
[18] тут: https://github.com/ggml-org/llama.cpp/blob/master/gguf-py/gguf/constants.py#L2905
[19] Modelfile: https://ollama.readthedocs.io/en/modelfile/
[20] http://localhost:11434: http://localhost:11434
[21] ollama: https://pypi.org/project/ollama/
[22] http://localhost:11434/v1: http://localhost:11434/v1
[23] openai: https://pypi.org/project/openai/
[24] @evilfreelancer: https://t.me/evilfreelancer
[25] Источник: https://habr.com/ru/articles/953682/?utm_campaign=953682&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.