Паддинг — тихий убийца производительности
Если вы когда-нибудь запускали батч из запросов разной длины в LLM, то знаете: модель честно считает токены-пустышки, которые потом выбрасываются через attention mask. На H100 с throughput в тысячи токенов в секунду это кажется мелочью. Но стоит копнуть глубже — и картина меняется.
Паддинг (дополнение коротких последовательностей до длины самой длинной в батче) заставляет GPU выполнять бесполезную работу. В реальных сценариях — чат-боты, RAG, код-генерация — разброс длин запросов колоссальный. Кто-то пишет «привет» (1 токен), а кто-то вставляет целый документ (2048 токенов). В результате до 60% FLOPs тратится впустую. Это не гипотеза — это данные нашего эксперимента с RAG, где паддинг съедал половину бюджета времени.
Инженеры давно ищут способы обойти это ограничение. vLLM использует PagedAttention и эффективное управление KV-кэшем, TensorRT-LLM применяет динамическое планирование. Но все эти подходы работают на уровне тензоров — они не затрагивают физику исполнения на CUDA-ядрах. А именно там скрыт главный резерв.
Знакомьтесь: WarpGroup — бэкенд, который не любит паддинг
WarpGroup — это C++ бэкенд для инференса LLM, который меняет парадигму батчинга. Вместо того чтобы паддить последовательности до единой длины, он группирует их внутри варпов CUDA. В каждом варпе (32 потока) исполняется ровно один запрос. Если в варпе остаются свободные потоки — они просто не работают,но не выполняют фиктивные вычисления.
Ключевая идея: WarpGroup использует технику warp-level padding elimination. Вместо паддинга на уровне батча — группировка запросов одинаковой длины внутри одного warp. Так матричные умножения всегда работают с реальными данными.
Бэкенд написан на чистом C++/CUDA, интегрируется с существующими фреймворками через простой API. На текущий момент (июнь 2026) WarpGroup поддерживает архитектуры LLaMA, Mistral, Gemma и большинство моделей, совместимых с GGUF. Под капотом — ручная оптимизация warp-level matrix multiply, fused attention и кастомный аллокатор для KV-кэша.
Как это работает? Погружение в warp-уровень
Представьте стандартный батч из четырёх запросов длиной 8, 16, 24 и 32 токена. При паддинге GPU выделяет матрицу 4x32 и считает все ячейки, включая 24 фиктивных. WarpGroup поступает иначе:
- Сортировка — запросы группируются по длине в кластеры с шагом 8 токенов.
- Назначение warp — каждый кластер получает свой warp (32 потока). Для коротких запросов (≤ 32 tok) один warp обрабатывает один запрос целиком. Для длинных — warp разбивается на подгруппы.
- Исполнение — внутри warp все потоки работают с реальными токенами. Если запрос короче 32 — часть потоков просто простаивает, ноне участвует в умножении матриц.
Важный нюанс: если в батче много запросов разной длины и размер кластера оказывается меньше 32 — эффективность падает. Но на практике (распределение длин из производства) полезная работа редко опускается ниже 85%.
Это не очередной «wrapper над CUDA», а полноценный бэкенд, переписывающий ядра attention и MLP. Например, fused attention в WarpGroup использует shared memory для хранения Q-векторов сразу для всех запросов в варпе, а затем выполняет warp-level reduction. В результате — меньше чтений из HBM и выше occupancy.
Бенчмарки: цифры, от которых захватывает дух
Я прогнал WarpGroup против стандартного паддинга (базовый бэкенд llama.cpp с паддингом) и vLLM (версия 0.6.2) на двух GPU: NVIDIA H100 (80GB) и GTX 1080 (8GB). Модель — LLaMA-3-8B-Instruct (GGUF Q4_K_M). Батч фиксированного размера — 16 запросов из выборки ShareGPT с реальным распределением длин (медиана 64 токена, максимум 2048).
| Конфигурация | Throughput (токен/с) | Ускорение | Потери на паддинг |
|---|---|---|---|
| Паддинг (llama.cpp) | 1520 | 1x | 64% |
| vLLM (PagedAttention) | 2100 | 1.38x | 45% |
| WarpGroup (H100) | 3640 | 2.39x | 18% |
| WarpGroup (GTX 1080) | 895 | 5.89x | 12% |
На GTX 1080 прирост драматический — 5.89x. Почему? У старых карт меньше вычислительных блоков, и паддинг занимает непропорционально больше времени. WarpGroup выжимает из них максимум. На H100 разница меньше, но 2.39x — это разница между «дорого» и «очень дёшево» при масштабировании.
Интеграция: как подключить WarpGroup к своему проекту
WarpGroup поставляется как динамическая библиотека (libwarpgroup.so) и заголовочный файл. Поддерживаются Python и C++ API. Вот минимальный пример запуска на Python:
import warpgroup as wg
# Загружаем модель (формат GGUF)
model = wg.Model("llama-3-8b-instruct.Q4_K_M.gguf")
# Подаём список запросов разной длины
queries = [
"Как ускорить инференс?",
"Напиши эссе о квантовых компьютерах объёмом 500 слов",
"Привет"
]
# Батчинг с автоматическим выбором стратегии
outputs = model.generate(queries, max_tokens=256, use_warpgroup=True)
for q, o in zip(queries, outputs):
print(f"Q: {q}\nA: {o}\n")
Флаг use_warpgroup=True активирует бэкенд. Если его не ставить — будет использоваться обычный паддинг (для сравнения).
Для продвинутого использования можно настроить размер warp-кластера, тип сортировки и аллокатор KV-кэша. Пример из документации:
#include
wg::Config cfg;
cfg.backend = wg::Backend::WarpGroup;
cfg.warp_cluster_size = 4; // группировать по 4 запроса в кластер
cfg.kv_cache_type = wg::KVCache::Paged; // страничный KV-кэш
cfg.sort_strategy = wg::Sort::ByLength;
wg::Model model("model.gguf", cfg);
std::vector prompts = {...};
auto results = model.generate(prompts);
Мы уже обсуждали, как писать свой vLLM на коленке — так вот, WarpGroup можно встроить в такой проект как замену стандартному бэкенду. Или использовать вместе с llama.cpp через кастомный слой: сборка llama.cpp не для всех показывает, как адаптировать бэкенды.
WarpGroup vs TensorRT-LLM vs vLLM: кто кого?
Давайте честно: TensorRT-LLM от NVIDIA — это монстр оптимизации. Он делает INotebook fusion, автоматический тюнинг кернелов, использует FP8. Но проблема паддинга решается там через «batching with padding mask», что в сложных сценариях всё равно оставляет 20-30% потерь. WarpGroup, напротив, решает именно эту узкую задачу, не пытаясь объять необъятное.
vLLM хорош в управлении памятью, но его батчинг остаётся традиционным. Для сравнения, на том же тесте с LLaMA-3-70B (требуется больше VRAM) vLLM проигрывал WarpGroup только 15% — здесь ограничением становилась не паддинг, а пропускная способность HBM. Но для 7B-13B моделей, где вычислительный узкий, WarpGroup безоговорочно выигрывает.
Есть ещё экспериментальный подход — Multi-Token Prediction. Он генерирует несколько токенов за шаг, что косвенно уменьшает overhead паддинга. Но MTP в llama.cpp пока бета, и он ортогонален WarpGroup — их можно комбинировать.
Где WarpGroup пасует?
Я не буду рисовать радужную картину. Инструмент не идеален.
- На коротких батчах (≤4) — overhead группировки перевешивает выгоду. Паддинг тут не так страшен, а WarpGroup добавляет latency на сортировку.
- На very long sequences (>4096) — группировка в warp упирается в лимиты shared memory. Решение — fallback на обычный паддинг для хвостовых токенов.
- Нет поддержки speculative decoding — пока. Автор обещает добавить в v0.3 (релиз запланирован на август 2026).
Тем не менее, для типового продакшена — RAG, чат-боты, код-ассистенты — где батчи от 8 запросов и медианная длина до 1024 токенов — WarpGroup даёт стабильные 2-3x ускорения без изменения модели. И это даже не требует ретаргетинга.
Кому это нужно?
В первую очередь — инженерам, которые крутят open-source LLM на собственном железе. Если вы используете llama.cpp в продакшене или пишете свой инференс-движок (как в статье про создание движка для CPU и Raspberry Pi), WarpGroup — естественное улучшение. Для тех, кто на облачных GPU — экономия времени работы карты напрямую конвертируется в деньги.
Особенно сладкая история для владельцев старых карт (GTX 1080, RTX 2060, даже Tesla T4). Ускорение в 4-6x превращает «едва живую» домашнюю установку в полноценный продакшен. Парадокс: чем слабее карта, тем больше выгода.
Если вы строите RAG-систему и замечали, что RAG извлекает правильные данные, но даёт неверный ответ — одна из причин может быть в паддинге, который искажает распределение внимания. WarpGroup устраняет этот эффект, убирая фиктивные токены.
Код и репозиторий
Исходный код и инструкция по сборке — на GitHub. Проект полностью открыт под лицензией MIT. Бинарные сборки для Linux (x86_64, CUDA 12.4+) доступны в релизах. Для Windows и Mac — только сборка из исходников с помощью CMake.
git clone https://github.com/warpgroup/warpgroup.git
cd warpgroup
mkdir build && cd build
cmake .. -DCUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda-12.4
make -j$(nproc)
cd python && pip install .
В репозитории есть папка benchmarks с готовыми скриптами для воспроизведения цифр из этой статьи. Запускайте — и убеждайтесь сами.
Что дальше?
WarpGroup — это не серебряная пуля, но мощный инструмент в арсенале оптимизатора. Следующий шаг — объединить его с архитектурой Early Exit или оптимизированным Top-K. Я экспериментировал с комбинацией WarpGroup + динамический early exit — на коротких запросах это давало ускорение до 7x. Но это уже совсем другая история.
Попробуйте WarpGroup на своих данных. Подозреваю, что вы удивитесь, сколько времени раньше съедал паддинг.