Перейти к содержанию
Публикация AiManual

laya.cpp: как C++ и ggml ускоряют инференс Laya до сотен решений в секунду

Разбираем laya.cpp: автономный C++ инференс модели Laya на ggml с кастомными CUDA-ядрами. Конкретные цифры против Python, технические оптимизации, требования к

Коротко

Что будет в материале

  1. 01

    Что такое laya.cpp и почему это важно для локального инференса

  2. 02

    Насколько C++ быстрее Python: цифры и условия замеров

  3. 03

    Технические оптимизации: что именно ускорило laya.cpp

  4. 04

    Как запустить laya.cpp: сборка, зависимости и ограничения

Что такое laya.cpp и почему это важно для локального инференса

laya.cpp это автономная реализация инференса для открытой модели Laya, собранная на C++ поверх ggml с кастомными CUDA-ядрами. Внутри одного бинарника живут нативная токенизация, выполнение модели и форматирование вывода, поэтому для запуска не нужны ни Python, ни PyTorch. Цифры от автора такие: английский чекпоинт в BF16 на RTX PRO 6000 Blackwell с лимитом мощности 450 Вт выдаёт 366 вопросов в секунду при батче 1 против 149 у Python-версии, а при батче 4 - 761 против 460.

Что это даёт на практике. Python-инференс тащит за собой PyTorch и цепочку зависимостей, а вместе с ними лишние конвертации тензоров и копирования буферов. C++ версия работает с памятью напрямую и считает теми же CUDA-ядрами, что и продовые движки. Результат: выше пропускная способность и проще деплой там, где Python неудобен или нежелателен.

Есть и второй слой смысла. laya.cpp встраивается в ту же линию, что и другие рантаймы на ggml: llama.cpp для текстовых LLM, whisper.cpp для распознавания речи. Приём общий: вынести инференс из Python, оставив интерпретируемость для экспериментов. Объявление и полные замеры автор выложил в обсуждении на r/LocalLLaMA.

Кто стоит за проектом: lkarlslund и u/Nandakishor_ml

Роли разделены. u/Nandakishor_ml отвечает за архитектуру Laya, её обучение и открытый релиз. lkarlslund написал реализацию инференса laya.cpp. Это независимые участники, а не одна команда: laya.cpp сторонний вклад в экосистему модели, а не её официальная часть. По данным источника проект собран с помощью инструмента Codex Astra.

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

Зачем нужен отдельный C++ инференс, если есть Python

Python-путь удобен для экспериментов, но в продакшене он стоит денег. PyTorch добавляет слой абстракций: тензоры приходится приводить к нужным типам, синхронизировать с GPU и копировать между представлениями. Каждый такой шаг расходует пропускную способность памяти, а на инференсе именно она чаще всего и упирается в потолок.

laya.cpp убирает этот слой. Данные сразу лежат в нужном формате, кастомные CUDA-ядра выполняют вычисления без промежуточных конвертаций, а путь от строки запроса до готового ответа идёт внутри одного процесса на C++. Плюс к этому: нет зависимости от конкретной версии PyTorch и связанного набора пакетов, что упрощает сборку контейнера и обновления.

Насколько C++ быстрее Python: цифры и условия замеров

Автор сравнил обе реализации на английском чекпоинте. Аппаратная база одна: RTX PRO 6000 Blackwell с ограничением мощности 450 Вт. В BF16 разрыв максимален на малых батчах и сужается по мере роста: 366 против 149 вопросов в секунду при батче 1, 761 против 460 при батче 4. В FP32 картина похожая, но потолок ниже: 342 против 148 на батче 1 и 437 против 233 на батче 4.

ТочностьБатчPython, вопросов/сC++, вопросов/сОтношение
BF161149366≈2,5x
BF162268586≈2,2x
BF164460761≈1,7x
BF168663810≈1,2x
FP321148342≈2,3x
FP322202421≈2,1x
FP324233437≈1,9x
FP328232386≈1,7x

Что бросается в глаза: на батче 8 в BF16 преимущество падает до 810 против 663, а в FP32 C++ версия на батче 8 проседает даже относительно собственного результата на батче 4 (386 против 437). Вывод простой: выигрыш C++ максимален там, где запросы идут небольшими порциями, а не гигантскими пакетами.

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

Методика тестирования: что именно измерялось

Корпус фиксированный: 250 вопросов, внутри варианты выбора, оценки и булевы значения. Из замеров исключены загрузка модели и JSON-транспорт, то есть измерялся чистый инференс. Для каждой точности сделаны парные прогоны Python и C++ с чередующимся порядком, что убирает систематический сдвиг от прогрева GPU или троттлинга. Такой подход ближе к корректному сравнению, чем одиночные прогоны подряд. Как строить честный замер между рантаймами на своём железе, мы разбирали в материале про Qwen 3.8 27B на одной RTX 5090.

Как интерпретировать «вопросы в секунду»

Вопрос в секунду это не токен в секунду. Метрика считает полные ответы на вопросы корпуса, а не отдельные токены генерации. Для задач с коротким ответом (классификация, выбор варианта, оценка, да или нет) она ближе к реальной нагрузке сервиса. Для свободной генерации длинных текстов показатель менее полезен: там всё решают длина промпта и скорость decode, а не пропускная способность на коротких ответах. Разницу между prefill и decode и то, как она меняет выбор рантайма, мы разбирали на примере GLM-5.3-Flash и TensorSharp.

Технические оптимизации: что именно ускорило laya.cpp

Автор называет три источника прироста: отказ от лишних конвертаций и копирований, слияние операций с сохранением округления и улучшенный доступ к памяти в attention. Ни один из них не меняет математику модели, речь о накладных расходах вокруг вычислений.

Устранение конвертаций и копирований

В Python-пайплайне данные проходят несколько представлений: массивы NumPy, тензоры PyTorch, промежуточные буферы на GPU. Каждый переход означает выделение памяти и копирование, а синхронные копии тормозят конвейер. В C++ версии данные лежат в том формате, который нужен ядрам, поэтому лишние шаги просто исчезают. Основной выигрыш даёт разгрузка пропускной способности памяти: на инференсе она обычно и упирается в потолок.

Слияние операций с сохранением округления

Fusion сокращает число проходов по памяти: вместо отдельного умножения и сложения с промежуточной записью результата выполняется одна операция. Тонкость в округлении. В BF16 диапазон представимых значений узкий, и наивное слияние легко меняет результат на последних битах. Автор подчёркивает, что округление при слиянии сохранено, то есть скорость получена без сдвига численных результатов.

Оптимизация доступа к памяти в attention

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

Как запустить laya.cpp: сборка, зависимости и ограничения

Код распространяется под лицензией MIT, то есть его можно использовать в коммерческих продуктах без отчислений. Сборка ориентирована на CUDA: вычислительная часть идёт через собственные ядра, а не через универсальный слой PyTorch.

Требования к окружению и сборке

Для BF16 нужен документированный профиль сборки с CUDA 13.0 и cuBLAS 13.1.0. Это свежие версии, и на машине со старым драйвером или другой веткой CUDA сборка из коробки не пойдёт, тулчейн придётся обновлять. Про другие точности в объявлении не сказано: работают ли они без этого профиля, автор не уточняет, поэтому проверяйте README перед тем, как планировать деплой. Замеры сняты на одной конфигурации, RTX PRO 6000 Blackwell с лимитом 450 Вт, и на другой GPU цифры будут другими.

Использование HTTP-сервера и JEV-совместимого эндпоинта

Помимо работы с моделью напрямую рантайм поднимает HTTP-сервер с JEV-совместимым эндпоинтом. Это позволяет встроить модель в микросервисную схему: приложение шлёт запрос, получает структурированный ответ, а внутри процесса нет Python-зависимостей. Формат JEV в объявлении не расшифрован, так что перед интеграцией стоит посмотреть спецификацию в репозитории, а не угадывать схему полей.

Чекпоинты Laya: английский, мультиязычный и typed-decisions

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

Чем отличаются чекпоинты и как выбрать

Английский чекпоинт рассчитан на задачи на английском, и именно на нём сняты приведённые замеры. Мультиязычный адресован сценариям с несколькими языками; конкретный список языков в объявлении не приводится, поэтому про русский язык утверждать ничего нельзя, проверяйте карточку модели. Typed-decisions ориентирован на ответы определённого типа: выбор из вариантов, оценку, булево значение. Если задача сводится к разметке или извлечению структуры, этот чекпоинт ближе к делу, чем свободная генерация.

Кому и когда стоит переходить на laya.cpp

Сценарии, где C++ инференс даёт максимальный выигрыш

Высоконагруженные сервисы с множеством коротких запросов: классификация, выбор варианта, булевы решения, разметка. Именно на малых батчах разрыв максимален, до 2,5 раза в BF16. Подходят и проекты, где Python в проде нежелателен: встроенные системы, узкие контейнеры, жёсткие требования к времени старта. Отсутствие PyTorch в зависимостях заметно упрощает образ и обновления.

Когда Python-версия остаётся предпочтительной

Эксперименты, дообучение, быстрая смена гипотез: здесь Python вне конкуренции по гибкости. Не оправдан переход и на машинах, где обновление до CUDA 13.0 с cuBLAS 13.1.0 невозможно или не стоит усилий, особенно если нагрузка небольшая и разница в скорости не видна. Если у вас уже отлажен Python-пайплайн и узкое место не в инференсе, выигрыш от смены рантайма будет нулевым. Оценить, где именно упирается ваша конфигурация, помогает разбор выбора модели под конкретный GPU на примере GLM-5.3-Flash и DeepSeek-V4-Flash-0731.

Ограничения и подводные камни laya.cpp

  • BF16 требует сборки с CUDA 13.0 и cuBLAS 13.1.0. Для окружений на более старых версиях это блокер.
  • Про другие точности требований в объявлении нет: работают ли они без этого профиля, не сказано.
  • Раскрытые цифры относятся только к английскому чекпоинту; данные по двум другим автор приводит в README.
  • Все замеры сняты на одной GPU (RTX PRO 6000 Blackwell, лимит 450 Вт) и на фиксированном корпусе из 250 вопросов с выборами, оценками и булевыми значениями. Переносить соотношения на другие GPU и другие задачи без проверки нельзя.
  • Проект молодой: возможны баги и неполная документация. Лицензия MIT даёт свободу использования, но не гарантии.
  • Формат JEV-эндпоинта в объявлении не описан, интеграцию придётся изучать по репозиторию.

Итоги: что laya.cpp значит для локального AI

laya.cpp показывает, сколько производительности лежит не в модели, а вокруг неё. Те же веса, та же GPU, тот же корпус вопросов, но отказ от Python-слоя и лишних копирований даёт до 2,5 раза на батче 1 в BF16 (366 против 149 вопросов в секунду) и около 1,65 раза на батче 4 (761 против 460). Три чекпоинта, нативная токенизация, HTTP-сервер с JEV-совместимым эндпоинтом и лицензия MIT делают проект пригодным для встраивания в сервисы, а не только для локальных экспериментов.

Практический шаг для читателя: откройте README проекта, сверьте требования к CUDA и cuBLAS со своим окружением и прогоните бенчмарк на своём железе, прежде чем переносить прод на новый рантайм. Если у вас короткие запросы и высокая нагрузка, разница будет заметна. Если вы гоняете длинные генерации или просто пробуете идеи, Python-путь пока остаётся удобнее.

Подписаться на канал