llama.cpp и GGUF - как использовать llama.cpp для локального запуска моделей LLaMA

Открытые большие языковые модели (LLM), такие как LLaMA от Meta, произвели революцию в области обработки естественного языка. Не все хотят зависеть от облачных API для их запуска. Здесь на помощь приходит llama.cpp — легковесное решение с открытым исходным кодом, которое позволяет запускать модели LLaMA и других семейств локально, даже на скромном оборудовании, даже без видеокарты (GPU).

llama.cpp — изначально это реализация моделей LLaMA от Meta на языке C++, разработанная для высокой эффективности и локального выполнения. Она позволяет запускать модели LLaMA на различных платформах — Windows, macOS и Linux — без необходимости в мощных GPU или внешних зависимостях.

Затем продукт был расширен для фреймворка квантования и запуска множества других моделей. В данный момент поддерживаются модели семейств

  • LLaMa
  • Mistral
  • Qwen2
  • Qwen2Moe
  • Phi3
  • Bloom
  • Falcon
  • StableLM
  • GPT2
  • Starcoder2
  • T5
  • Mamba
  • Nemotron

https://huggingface.co/docs/transformers/v4.47.1/gguf

Но в целом вы можете попробовать квантовать любую модель с Huggingface

# git clone https://github.com/ggml-org/llama.cpp
# cd llama.cpp
# pip install -r requirements.txt
python llama.cpp/convert-hf-to-gguf.py ./phi3 --outfile output_file.gguf --outtype q8_0

Локальный запуск моделей LLaMA даёт полный контроль над конфиденциальностью данных, настройкой производительности и затратами. Мы не отправляем конфиденциальные данные на сторонние серверы и не платим за использование API. Это особенно полезно для разработчиков, исследователей и энтузиастов, работающих над персонализированными ИИ-приложениями.

Ключевые особенности:

  • Кроссплатформенная поддержка: работает на Linux, Windows и macOS.
  • Оптимизация для CPU: не требуется GPU для запуска моделей.
  • Квантизированные модели: снижено использование памяти при минимальных потерях производительности.
  • Python-биндинги: легко интегрируется с Python с помощью llama-cpp-python.
  • Поддержка сообщества: активно поддерживается и обновляется.

В основе llama.cpp лежит лёгкий, оптимизированный для CPU механизм вывода, написанный на C++, который позволяет использовать языковые модели полностью офлайн с низкими требованиями к ресурсам. Основные направления оптимизации:

  • Квантизация для уменьшения размера модели
  • Использование отображения памяти для эффективности
  • Многопоточность для использования всех ядер CPU

Квантизация модели (сжатие)

Крупные модели, такие как LLaMA 2, занимают гигабайты памяти при использовании полноразрядных чисел с плавающей запятой (FP16/FP32). Чтобы сделать их пригодными для машин с ограниченной оперативной памятью или без GPU, llama.cpp поддерживает квантизированные модели в формате GGUF.

Эти квантизированные модели уменьшают использование памяти и объём вычислений за счёт использования 4-, 5- или 8-битных диапазонов целых чисел, например:

  • Q4_0, Q5_1, Q8_0 — различные уровни квантизации.
  • Меньший размер означает более быстрое время загрузки и меньшее потребление оперативной памяти, но и большая погрешность в вычислениях

Методы квантизации

Названия методов квантизации следуют соглашению об именовании: "q" + количество бит + используемый вариант (подробности ниже). Вот список всех возможных методов квантизации и их соответствующих случаев использования, основанных на карточках моделей от TheBloke:

  • q2_k: Использует Q4_K для тензоров attention.vw и feed_forward.w2, Q2_K — для остальных тензоров.
  • q3_k_l: Использует Q5_K для тензоров attention.wv, attention.wo и feed_forward.w2, в остальных случаях — Q3_K.
  • q3_k_m: Использует Q4_K для тензоров attention.wv, attention.wo и feed_forward.w2, в остальных случаях — Q3_K.
  • q3_k_s: Использует Q3_K для всех тензоров.
  • q4_0: Исходный метод квантизации, 4-битный.
  • q4_1: Более высокая точность, чем у q4_0, но ниже, чем у q5_0. Однако обеспечивает более быстрое выведение по сравнению с моделями q5.
  • q4_k_m: Использует Q6_K для половины тензоров attention.wv и feed_forward.w2, в остальных случаях — Q4_K.
  • q4_k_s: Использует Q4_K для всех тензоров.
  • q5_0: Более высокая точность, но требует больше ресурсов и медленнее работает.
  • q5_1: Ещё более высокая точность, но ещё больше ресурсов и медленнее.
  • q5_k_m: Использует Q6_K для половины тензоров attention.wv и feed_forward.w2, в остальных случаях — Q5_K.
  • q5_k_s: Использует Q5_K для всех тензоров.
  • q6_k: Использует Q8_K для всех тензоров.
  • q8_0: Почти неотличим от float16. Высокое потребление ресурсов и медленная работа. Не рекомендуется большинству пользователей.

Общее правило: Рекомендуется использовать Q5_K_M, так как он сохраняет большую часть качества модели. Альтернативно можно использовать Q4_K_M, если нужно сэкономить память. В целом, версии K_M лучше, чем K_S. Методы Q2_K или **Q3_*** не рекомендуются, так как они значительно снижают качество модели.

Отображение памяти с помощью mmap

llama.cpp использует отображение памяти (mmap) для эффективной загрузки моделей. Вместо загрузки всей модели в оперативную память, загружаются только те части, которые необходимы в данный момент. Это:

  • Минимизирует использование памяти.
  • Ускоряет процесс вывода (генерации).
  • Позволяет запускать крупные модели на скромном оборудовании.

Токенизация и генерация

Вот что происходит, когда мы отправляем запрос:

  1. Токенизация: текстовый запрос разбивается на токены с помощью токенайзера LLaMA.
  2. Прямое распространение: эти токены передаются через слои нейронной сети (трансформеры).
  3. Сэмплирование: модель выбирает следующий токен с использованием параметров, таких как температура, top_p и стоп.
  4. Декодирование: токены преобразуются обратно в текст, понятный человеку.

Этот цикл продолжается до тех пор, пока не будет достигнут желаемый объём токенов или не будет выполнено условие остановки.

Многопоточность CPU

llama.cpp использует многопоточность для параллелизации вычислений на нескольких ядрах CPU. Мы можем настроить количество потоков с помощью:

# python
llm = Llama(model_path="...", n_threads=8)

Это позволяет ускорить генерацию, особенно на современных многоядерных процессорах.

Как установить llama.cpp локально

Перед установкой llama.cpp локально рассмотрим предварительные требования:

  • Python (скачать с официального сайта)
  • Anaconda Distribution (скачать с официального сайта)

После загрузки и установки предварительных требований начнём процесс установки llama.cpp.

Шаг 1: Создание виртуального окружения

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

Чтобы создать виртуальное окружение на локальном компьютере, выполните эту команду в терминале:

conda create --name vir-env

Conda — это система управления окружениями с открытым исходным кодом, которая в основном используется для управления окружениями Python и R. Она поставляется в комплекте с дистрибутивом Anaconda.

В команде мы использовали conda create для создания виртуального окружения с именем vir-env, указанным с помощью флага --name.

Шаг 2: Активация виртуального окружения

Активируйте вновь созданное виртуальное окружение vir-env с помощью команды conda activate:

conda activate vir-env

Шаг 3: Установка пакета llama-cpp-python

Пакет llama-cpp-python — это Python-биндинг для моделей LLaMA. Установка этого пакета поможет запускать модели LLaMA локально с использованием llama.cpp.

Установим пакет llama-cpp-python на локальном компьютере с помощью pip — установщика пакетов, который поставляется вместе с Python:

pip install llama-cpp-python

Шаг 1: Скачивание модели LLaMA

Первым шагом является скачивание модели LLaMA, которую мы будем использовать для генерации ответов. Совместимые с llama.cpp модели перечислены в репозитории TheBloke на Hugging Face. Для этого руководства скачаем модель Llama-2-7B-Chat-GGUF с её официальной страницы документации.

После скачивания откройте терминал и выполните следующие команды для создания папок на локальном компьютере:

mkdir demo
cd demo
mkdir models
cd models
mkdir llama-2

После создания папок сохраните скачанную модель в папке llama-2.

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

Шаг 2: Создание Python-скрипта

Следующим шагом является создание Python-скрипта, который мы будем использовать для настройки и использования модели для генерации ответов.

Создадим файл с именем llama.py:

touch llama.py

После создания файла откройте его в редакторе кода и вставьте следующий Python-скрипт:

from llama_cpp import Llama

# Загрузка модели
llm = Llama(
    model_path="./models/llama-2/llama-2-7b-chat.Q4_K_M.gguf",
    n_ctx=512,
    n_threads=4
)

# Задание запроса
prompt = "Что такое Python?"

# Генерация ответа
output = llm(prompt, max_tokens=250)

# Вывод ответа
print(output["choices"][0]["text"].strip())

В первой строке этого скрипта импортируется класс Llama из пакета llama-cpp-python. Это основной интерфейс для загрузки и взаимодействия с моделью. Кроме того, мы использовали следующие параметры:

  • model_path: путь к файлу модели.
  • n_ctx: максимальное количество токенов, которое модель может обработать за один запрос. Большее значение позволяет использовать более длинный контекст, но требует больше памяти.
  • n_threads: количество потоков CPU, используемых во время вывода. Нужно установить это значение в зависимости от возможностей системы (например, 4–8 для современных CPU).
  • prompt: запрос, для которого мы хотим сгенерировать ответ.
  • max_tokens: ограничивает длину вывода указанным количеством токенов (250 в данном случае). Здесь термин "токен" относится к словам или частям слов.

Кроме того, последняя строка извлекает фактический текст ответа из словаря output и выводит его. В этой строке:

  • output["choices"][0]["text"]: получает текстовый результат из первого завершения.
  • .strip(): удаляет начальные и конечные пробелы.

После сохранения файла переходим к следующему шагу.

Шаг 3: Запуск скрипта

Наконец, настало время запустить скрипт:

python llama.py

Вот сгенерированный ответ на наш запрос:

Python — это мощный язык программирования общего назначения, известный своим понятным синтаксисом и простотой использования. Будь то создание веб-сайта, анализ данных или автоматизация задач, Python предоставляет инструменты и библиотеки для эффективного выполнения этих задач.

Распространённые ошибки при создании проекта на основе llama.cpp

Вот некоторые распространённые ошибки и их решения:

Отсутствие зависимостей

Ошибка: cmake: command not found или ошибки модулей Python.

Решение: установите необходимые зависимости:

sudo apt install cmake build-essential python3

Некорректный или неподдерживаемый компилятор

Ошибка: использование старой версии GCC/Clang, которая не поддерживает современные стандарты C++ (например, C++17).

Решение: используйте как минимум GCC 10+ или Clang 11+.

Файл не найден

Ошибка: file not found: ggml-model.bin

Решение: проверьте путь к файлу, регистр символов и наличие модели в правильном формате (.gguf).

Ошибки нехватки памяти

Ошибка: ошибки сегментации или сбои выделения памяти.

Решение: уменьшите размер контекста и используйте более мелкие модели.

  1. Какие системные требования необходимы для эффективного запуска llama.cpp? Мы рекомендуем минимум 8 ГБ оперативной памяти для запуска базовых моделей с помощью llama.cpp. Больше памяти (16 ГБ+) позволяет запускать более крупные модели или несколько экземпляров. Современный CPU с поддержкой AVX2 повышает производительность, GPU не обязателен.

  2. В чём разница между llama.cpp и другими фреймворками LLM? В отличие от тяжёлых фреймворков, таких как Hugging Face Transformers, llama.cpp минималистичен и оптимизирован для выполнения на CPU. Он поддерживает квантизированные модели, значительно снижая использование памяти. Инструменты, такие как llama-cpp-python, обеспечивают совместимость с Python, сочетая производительность и удобство использования.

  3. Как llama.cpp обрабатывает обновления и улучшения в моделях LLaMA? Сообщество llama.cpp активно обновляет кодовую базу для поддержки новых версий моделей LLaMA и функций. Обновления часто включают оптимизации производительности, новые форматы квантизации и исправления ошибок.

llama.cpp представляет собой высокоэффективную кроссплатформенную библиотеку для локального запуска крупных языковых моделей (LLM) с минимальными требованиями к аппаратному обеспечению. Поддерживая форматы GGUF и работа на CPU/GPU, она обеспечивает полную приватность данных, что делает её незаменимой для сценариев с ограниченным доступом к облачным сервисам. В отличие от vLLM, оптимизированного для масштабируемых облачных решений, llama.cpp демонстрирует гибкость в выборе вычислительных бэкендов (CUDA, OpenCL, Metal) и совместима с широким спектром моделей, включая Qwen, LLaMA и Falcon. Для работы с моделями из Hugging Face требуется их конвертация в GGUF-формат через специализированные инструменты, что позволяет использовать 2-8 битное квантование для оптимизации производительности.

Технические особенности llama.cpp

Квантованные модели можно смотреть тут

Архитектурные преимущества

llama.cpp реализован на чистом C/C++ без внешних зависимостей, что обеспечивает кроссплатформенную совместимость с поддержкой аппаратных ускорений через AVX/AVX2/AVX512 для x86 и NEON для ARM-архитектур. Библиотека использует гибридный CPU+GPU подход, где вычисления распределяются между процессором и видеокартой для максимальной эффективности. Это особенно важно при работе с квантованными моделями, где 4-битная версия может занимать в 4 раза меньше памяти по сравнению с оригиналом FP16.

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

Поддерживаемые модели и форматы

Изначально разработанный для моделей семейства LLaMA, llama.cpp расширил поддержку до Vicuna, Alpaca, Falcon и Qwen через систему адаптеров. Формат GGUF (GPT-Generated Unified Format) стал стандартом де-факто, предлагая:

  1. Единую структуру метаданных для хранения информации о модели
  2. Поддержку смешанного квантования (2-8 бит)
  3. Механизмы безопасной загрузки с верификацией контрольных сумм[5]

Для моделей типа BERT и T5 требуется предварительная конвертация в GGUF через скрипты convert.py из официального репозитория. Совместимость достигается за счёт преобразования архитектурных элементов в эквивалентные блоки LLaMA.

Установка и настройка

Для Windows

  1. Установка зависимостей:

    • Git для Windows (обязательно включить интеграцию с CMD)
    • CMake ≥3.24
    • Visual Studio 2022 с компонентами C++ и Windows SDK
  2. Сборка из исходников:

    git clone https://github.com/ggerganov/llama.cpp
    cd llama.cpp
    mkdir build
    cd build
    cmake .. -G "Visual Studio 17 2022" -A x64 -DLLAMA_CUBLAS=ON
    cmake --build . --config Release

    Флаг LLAMA_CUBLAS=ON активирует CUDA-ускорение для NVIDIA GPU. Для AMD карт используется LLAMA_CLBLAST=ON.

Для Linux

Установка через системные пакеты:

sudo apt install build-essential libopenblas-dev
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp && make LLAMA_OPENBLAS=1

Для гибридного CPU+GPU режима добавить флаги:

  • LLAMA_CUDA=1 — NVIDIA CUDA
  • LLAMA_VULKAN=1 — AMD/Intel GPU
  • LLAMA_METAL=1 — Apple Silicon

Запуск моделей различных архитектур

Поддерживаемые модели

Тип модели Примеры Особенности запуска
LLaMA-подобные LLaMA 3, Alpaca, Vicuna Прямая загрузка GGUF через CLI
Трансформеры общего назначения BERT, T5 Требуется конвертация в GGUF
Китайские модели Qwen, Chinese-Alpaca Поддержка токенизаторов через --tokenizer-path
Мультимодальные LLaVA, BakLLaVA Использование --mmproj для проекторов

Пример запуска Qwen-7B:

./main -m qwen7b-q4_0.gguf -p "Анализ преимуществ llama.cpp:" -n 512 --temp 0.7

Инференс нестандартных моделей

Для моделей, не входящих в стандартную поддержку, требуется:

  1. Экспорт весов в формат PyTorch .pth
  2. Конвертация через скрипт convert.py:
    python3 convert.py --input-dir ./bert-base-uncased --output-type gguf --outfile bert-base.gguf
  3. Оптимизация квантования:
    ./quantize bert-base.gguf bert-base-q4_0.gguf q4_0

Сравнение с vLLM

Производительность

Параметр llama.cpp vLLM
Скорость (токенов/с) 85 120
Память (7B модель) 6.5 ГБ 4.8 ГБ
Задержка (p95) 350 мс 210 мс
Поддержка GPU CUDA/Metal/OpenCL Только CUDA
Макс. размер батча 16 256[4]

vLLM демонстрирует преимущество в сценариях пакетной обработки благодаря технологии PagedAttention и динамическому батчингу. Однако llama.cpp остаётся единственным выбором для:

  • ARM-устройств (Raspberry Pi)
  • Систем без дискретных GPU

Работа с GGUF-форматом

Структура формата

GGUF заменил устаревший GGML, введя:

  • Древовидную структуру метаданных
  • Поддержку многомодельных конфигураций
  • Встроенную систему версионирования
  • Шифрование параметров через AES-GCM[5]

Ключевые секции файла:

  1. Metadata — архитектура, версия, автор
  2. Tensor Data — квантованные веса
  3. Vocab — словарь токенизатора
  4. Hypertune — параметры квантования

Конвертация моделей

Процесс адаптации модели из Hugging Face:

  1. Скачивание исходников:

    git clone https://huggingface.co/meta-llama/Meta-Llama-3-8B-Instruct
  2. Конвертация в FP16:

    from llama_cpp import Llama
    Llama.create_gguf("Meta-Llama-3-8B-Instruct", outfile="llama3-8b.f16.gguf")
  3. Квантование:

    ./quantize llama3-8b.f16.gguf llama3-8b.q4_k.gguf q4_k
  4. Валидация:

    ./perplexity -m llama3-8b.q4_k.gguf -f test.txt

Расширенные возможности

Интеграция с OpenAI API

Запуск локального API-сервера:

./server -m llama3-8b.q4_k.gguf --port 8080 --api-key "local"

Пример запроса через cURL:

curl http://localhost:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "llama3-8b",
    "messages": [{"role": "user", "content": "Объясни квантование в llama.cpp"}]
  }'

Оптимизация производительности

Для CPU:

./main -m model.gguf -t 16 --mlock --no-mmap

Флаги:

  • -t N — количество потоков
  • --mlock — блокировка модели в RAM
  • --no-mmap — отключение memory mapping

Для NVIDIA GPU:

./main -m model.gguf --n-gpu-layers 35 -c 2048 -b 512

Где --n-gpu-layers указывает количество слоёв на GPU.

llama.cpp представляет собой мощное решение для локального выполнения LLM, сочетающее гибкость аппаратной конфигурации с продвинутыми возможностями оптимизации. Его ключевые преимущества перед облачными альтернативами типа vLLM включают полный контроль над данными, работу на слабом железе и расширенную поддержку квантования. Для интеграции с существующими моделями из Hugging Face требуется конвертация в GGUF-формат через встроенные инструменты, что открывает доступ к 40+ архитектурам. Дальнейшее развитие проекта обещает улучшение поддержки мультимодальных моделей и аппаратных ускорителей нового поколения.