Чем глубже погружаюсь в тему нейросетей, тем больше разношерстных моделей мне требуется использовать для решения различных задач. Например, для создания проектов типа RAG (Retrieval-Augmented Generation) могут понадобиться модели-эмбеддеры. Эти модели превращают текстовые данные в векторные представления (эмбеддинги), что позволяет эффективно сравнивать и находить сходства между текстами, а полученные эмбеддинги используются для поиска, классификации и ранжирования информации в система векторного поиска.
Однако, нередко возникает необходимость запускать такие модели-эмбеддеры на слабом железе или же более эффективно утилизировать ресурсы сервера. В таких случаях можно выполнить сжатие модели, одним из способов сжатия является преобразование в формат GGUF (llama.cpp), который позволяет запускать её как на видеокарте, так и на процессоре, и там и сям одновременно.
В данной публикации мы рассмотрим, как сконвертировать сберовскую модель ai-forever/sbert_large_nlu_ru типа BERT в формат GGUF, однако, данный способ подойдёт и для любой другой BERTы которая обучена извлекать эмбеддинги (класс BertModel, обычно он указан в config.json).
Важно отметить, что нам нужна именно модель класса BertModel, так как она представляет собой чистую модель BERT, которая выдает сырые скрытые состояния без дополнительных слоев (head) для конкретных задач. Если ваша BERTа имеет имеет другой класс из неё потребуется удалить head слои.
Но давайте уже перейдём ближе к телу.
Нам понадобится
Прежде чем продолжить убедитесь, что у вас есть всё необходимое:
- Утилита git
- Python 3.11
- ОС Debian или Ubuntu
- Уровень доступа root (sudo)
Подготовка окружения
Для начала склонируйте репозиторий llama.cpp к себе на компьютер:
git clone https://github.com/ggerganov/llama.cpp.git
cd llama.cpp
Далее потребуется установить ряд пакетов, чтобы можно было выполнить компиляцию утилит проекта:
sudo apt update
sudo apt install build-essential
Выполним команду make для сборки всех бинарников:
make
И подождём некоторое время пока сборка не закончится.
Подробную инструкцию по сборке всех утилит можно найти в README файле проекта llama.cpp.
Далее создадим виртуальное окружение Python и установим все зависимости из файла requirements.txt:
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
# Пакеты ниже потребуются на шаге конвертации модели
pip install transformers torch
Подготовка скриптов конвертации
К сожалению в большинстве случаев нельзя просто взять и выполнить конвертацию модели, перед этим потребуется выполнить ряд манипуляций над скриптами которые используют для конвертации.
Скачаем модель на локальный диск:
huggingface-cli download ai-forever/sbert_large_nlu_ru --local-dir sbert_large_nlu_ru --local-dir-use-symlinks False
Этот скрипт скачает модель ai-forever/sbert_large_nlu_ru и положит её в локальную директорию с названием sbert_large_nlu_ru.
Так же для конвертации потребуется BERTовский токенизатор, скачаем его и положим в директорию sbert_large_nlu_ru следующей командой:
python -c "from transformers import AutoTokenizer; AutoTokenizer.from_pretrained('ai-forever/sbert_large_nlu_ru').save_pretrained('sbert_large_nlu_ru')"
Далее отредактируем скрипт convert_hf_to_gguf_update.py, добавив в массив models следующего вида запись:
{"name": "sbert", "tokt": TOKENIZER_TYPE.WPM, "repo": "./sbert_large_nlu_ru"},
Должно будет получится что-то типа этого:
Теперь выполним скрипт convert_hf_to_gguf_update.py, чтобы он обновил содержимое скрипта convert_hf_to_gguf.py:
python convert_hf_to_gguf_update.py <huggingface_token>
Вместо <huggingface_token> вам надо будет подставить токен, который был сгенерирован на сайте HuggingFace на странице Access Tokens.
Данная процедура займёт пару минут, по её завершению вы увидите изменение в скрипте convert_hf_to_gguf.py, там добавятся строки вида:
На этом подготовка закончена.
Конвертация модели
Ну чтож, у нас готов скрипт конвертации, а веса модели скачаны локально, поэтому давайте уже сконвертируем наконец нашу модель, для этого выполним следующую команду:
python convert_hf_to_gguf.py sbert_large_nlu_ru --outfile models/sbert_large_nlu_ru-f16.gguf --outtype f16
По завершению команда напишет, что модель сохранена по указанному пути.
И что же у нас получилось?
Теперь самое простое, запустим нашу модельку следующей командой:
./llama-server --model models/sbert_large_nlu_ru-f16.gguf --ctx-size 512 --batch-size 512 --embedding --log-disable --parallel 1 --port 8080
А в другом терминале выполним следующего вида запрос:
curl http://localhost:8080/embeddings -d '{"input": "The sky is blue because of Rayleigh scattering"}'
В ответе будет JSON следующего вида:
На название модели в поле model не обращаем внимания, оно никогда не меняется вне зависимости от того какую эмбеддинговуюю модель мы используем.
Я провёл небольшое сравнение того насколько сильно эмбеддинг у GGUF модели отличается от оригинальной PyTorch версии, получилась следующая картина:
Ссылка на Jupyter-блокнот тут.
То есть видно, что GGUF версия модели sbert генерирует примерно тоже самое, что и PyTorch версия модели, а также видно, что сущесвует значительные расхождения в результате, однако, не факт, что GGUF модель будет генерировать эмбеддинги хуже, в общем надо проверять.
Завершение
Ну вот и всё, теперь вы знаете, как конвертировать модель типа BERT, такую как сберовская модель ai-forever/sbert_large_nlu_ru, в формат GGUF. Этот процесс позволяет запускать модели-эмбеддеры на слабом железе и более эффективно использовать ресурсы сервера.
Надеюсь, этот простенький гайд был полезен и помог вам понять, как адаптировать модели под ваши нужды. Если у вас остались вопросы или вы хотите узнать больше о нейросетях и машинном обучении, подписывайтесь на мой Телеграм-канал и блог, а также не забудьте поставить лайк этой публикации. Ваши отзывы и поддержка мотивируют меня на создание новых полезных материалов.
Спасибо за внимание и удачи в ваших проектах!