В репозитории ggml-org/llama.cpp появился пул-реквест #28450 от участника frobnitzem. Формулировка в заголовке - «Performance tune for gemma4-26b-a4b flash attention shape»: см. описание PR #28450. Речь о подгонке формы (shape) flash attention под одну конкретную модель, Gemma 26B A4B, и цель обозначена прямо: ускорить её работу в llama.cpp.
Границы известного обозначу сразу. В доступных материалах нет ни диффа, ни цифр прироста, ни списка затронутых бэкендов, ни числа прогонов, на которых автор что-то мерил. Связь с производительностью подтверждают только сам заголовок с «Performance tune» и отдельное упоминание «Gemma 26B A4B speedup» в контенте источника. Всё остальное, включая проценты ускорения, пришлось бы додумывать, а этого я делать не буду.
Порядок разбора: сначала что за изменение и почему оно адресное, затем механика shape flash attention и её влияние на скорость и VRAM, условия, при которых эффект возможен, практический чек-лист по замерам и стратегия обновления с рисками сборки неслитого патча.
Что за PR #28450 и почему вокруг него шум
Из заголовка и содержимого источника вытаскиваются три проверяемых факта. Автор изменения - участник frobnitzem. Позиционируется оно как настройка производительности (performance tune), а не как новая возможность или исправление бага. Тема привязана к Gemma 26B A4B: ускорение этой модели в тексте источника названо отдельно (источник по PR #28450).
Шум вокруг таких патчей возникает по понятной причине: слово speedup в заголовке читается как готовая прибавка к tokens/s, хотя за словами performance tune может стоять что угодно. Настройка параметров ядра иногда даёт несколько процентов, иногда приводит код в порядок без заметной разницы на большинстве сетапов, иногда роняет производительность на неглавной ветке кода. Пока нет цифр и диффа, разумная позиция - интересоваться, но не планировать апгрейд на основе заголовка.
Что меняет сам тип изменения. Патчи с прицелом на производительность правят внутренности: раскладку тайлов, размеры блоков, распределение работы по потокам. Публичный интерфейс при этом не двигается, флаги не переименовываются, формат файлов модели не меняется. Риск здесь не в сборке. Скорее в том, что правка может задеть общий код пути flash attention и просадить производительность на соседних моделях. Проверка на своей конфигурации поэтому не формальность.
Кто такой frobnitzem и что это меняет для читателя
frobnitzem указан автором PR #28450, и это практически всё, что о нём сообщают доступные материалы: ни истории предыдущих патчей, ни статистики принятых изменений, ни специализации. Оценивать изменение по автору в такой ситуации бессмысленно, решение принимается по диффу и по результатам сборки у себя.
Практический вывод из одного факта «это performance tune» тоже скромный. Изменение узкое: адресовано одной модели и, вероятно, одному набору параметров запуска. Если вы не запускаете Gemma 26B A4B, вы, скорее всего, не увидите от него ничего. Если запускаете, эффект нужно измерять, а не предполагать.
Почему именно Gemma 26B A4B
В названии стоит gemma4-26b-a4b, то есть подгонка адресная. Так поступают, когда для модели дефолтные параметры разбиения работают неоптимально: общей раскладки хватает большинству архитектур, а у конкретной пропорции голов внимания, размерность головы и типичные длины последовательностей складываются в другой профиль нагрузки на GPU.
Про саму архитектуру Gemma 26B A4B в исходных материалах нет ничего, поэтому дальше только аккуратное предположение. Нотация с постфиксом в названиях моделей семейства Gemma обычно указывает на разрыв между общим числом параметров и числом параметров, активных на каждом токене. В llama.cpp такие архитектуры идут по ветке MoE-кода, и часть параметров там не участвует в вычислениях на каждом шаге. Если всё так, у модели нетипичное соотношение между числом attention-голов, их размерностью и глубиной, а значит, дефолтный shape FA может грузить вычислительные блоки не полностью. Это гипотеза о причине, а не содержимое PR: конкретных значений тайлов и обоснования выбора в доступных данных нет.
Как выглядит тюнинг MoE-моделей в llama.cpp на практике, включая замеры и найденные регрессии, разбиралось отдельно: опыт ускорения MoE-инференса на RTX 4080. Тот материал полезен как образец методики: одни и те же правки дают разный результат на предзаполнении и на генерации.
Что такое shape flash attention и зачем его тюнить
Flash attention считает внимание блоками. Полная матрица «запрос × ключ» не строится в памяти: ядро идёт по последовательности тайлами, накапливает промежуточные суммы в регистрах и разделяемой памяти, а KV-cache читает порциями. Отсюда два следствия, ради которых FA и включают: пиковая память под attention падает, а чтения KV-cache становятся более предсказуемыми.
«Shape» в этом контексте - набор параметров разбиения: сколько запросов и ключей попадает в один блок, как головы группируются по блокам, с каким шагом ядро движется по последовательности. Ядро выходит эффективным, когда эти размеры совпадают с реальными размерностями модели и с тем, что способен загрузить GPU. Когда совпадения нет, часть вычислительных блоков простаивает, часть данных читается повторно, и throughput падает. PR #28450 правит именно эту подгонку под Gemma 26B A4B. Значений тайлов в доступных материалах нет, так что здесь описан принцип, а не содержимое диффа.
Для контекста: работа над flash attention в llama.cpp идёт в нескольких направлениях одновременно, и shape - только одно из них. Рядом существует, например, разреженный вариант FA для Qwen4 на CUDA по пул-реквесту #28770 (разбор PR #28770). Общего у этих изменений мало: там меняют сам алгоритм, здесь настраивают параметры существующего ядра.
Как shape FA влияет на скорость
Механика простая. Неверный shape - это неполная загрузка вычислительных блоков и лишние обращения к памяти, а память в attention и есть основной узкий участок. Отсюда падение tokens/s, которое сильнее проявляется там, где доля attention в общем времени высока.
Логично ожидать, что подгонка shape заметнее на обработке промпта (prefill) и на длинных контекстах, чем на генерации по одному токену за шаг. На длинном контексте ядро проходит больше итераций по последовательности, поэтому накладные расходы на каждую итерацию накапливаются. Это рассуждение из механики ядра, а не результат замеров из PR #28450: цифр там нет, и обещать конкретные проценты нечем.
Как shape FA влияет на потребление VRAM
Flash attention снижает пиковую память под сам attention, потому что не хранит полную матрицу N×N. Shape влияет на вторичные вещи: размер промежуточных буферов и то, сколько KV-cache читается за одну итерацию. Удачная подгонка может убрать часть оверхеда, но это не замена квантизации и не способ запустить модель на карте, которой не хватает памяти.
Разделяйте два бюджета памяти. Первый - веса модели и KV-cache, они и определяют, влезет ли модель в VRAM при заданной длине контекста. Второй - рабочие буферы ядер, где и живёт shape. Выигрыш по второму бюджету измеряется десятками или сотнями мегабайт, а не гигабайтами, и точных цифр для этого PR никто не публиковал.
При каких условиях стоит ждать ускорения
Сочетание условий, при котором настройка shape FA для Gemma 26B A4B вообще может проявиться:
- вы запускаете именно Gemma 26B A4B, а не другую модель;
- flash attention у вас включён;
- инференс идёт на GPU-бэкенде, где FA реально используется. Список бэкендов, затронутых PR #28450, в материалах не раскрыт, так что проверять придётся на своём;
- у вас длинный контекст или батчинг, где неоптимальное разбиение успевает накопиться в измеримую разницу;
- узким местом служит внимание, а не загрузка весов с диска или пропускная способность шины.
Отдельно про бэкенды: работа над ними в llama.cpp идёт постоянно, и это не только NVIDIA. Пример из недавнего - правки под ROCm, которые ускоряют обработку промптов на AMD GPU (разбор ROCm-оптимизаций). Если вы на Radeon или Instinct, стоит сначала уточнить, к какому бэкенду относится изменение, а потом собирать ветку.
Когда эффекта не будет
Сценарии, где ждать нечего: инференс на CPU; flash attention отключён; модель не Gemma 26B A4B; контекст короткий, в несколько сотен токенов, где attention занимает малую часть времени; узкое место в другом - не хватает VRAM под KV-cache, модель читается с медленного диска, веса подгружаются по PCIe из оперативной памяти.
Отдельная ловушка: попытка поправить ситуацию настройкой одного ядра, когда модель не влезает в память. Если KV-cache уезжает в системную RAM или VRAM занята под веса с запасом в считаные сотни мегабайт, никакой shape этого не исправит. Сначала квантизация и длина контекста, потом тонкая настройка ядер.
Как проверить эффект у себя: практический чек-лист
Порядок действий без магии. Убедитесь, что у вас сборка llama.cpp с нужным GPU-бэкендом и что flash attention включается. Зафиксируйте конфигурацию: модель Gemma 26B A4B, конкретная квантизация, длина контекста, размер батча, число слоёв на GPU. Замерьте baseline. Затем повторите замер на сборке с патчем из PR #28450 и сравните результаты.
Какие флаги и инструменты использовать
Основные точки контроля в llama.cpp:
-fa(--flash-attn) для flash attention. В свежих версиях флаг принимает значения вида auto/on/off, в более старых работал как переключатель. Синтаксис менялся, поэтому проверьте--helpименно для своей сборки.-nglдля числа слоёв, выгруженных на GPU. При сравнении это значение обязано совпадать.-cдля длины контекста. Именно она определяет, насколько заметен вклад attention.-bи-ubдля размера логического и физического батча при обработке промпта.llama-benchдля синтетических замеров:-pзадаёт число токенов промпта,-nчисло генерируемых токенов,-rчисло повторов. Раздельные цифры по pp и tg - то, что нужно.llama-serverс логами для сценария, близкого к рабочему, иnvidia-smiилиrocm-smiдля пиковой VRAM.
Правило сравнения одно: между прогонами меняется ровно один параметр, версия сборки. Квантизация, длина контекста, батч и размещение слоёв остаются теми же, иначе вы измеряете не эффект PR, а разницу между конфигурациями.
Как читать результаты и не обмануться
Смотрите на pp и tg по отдельности. Ожидание из механики FA: сдвиг вероятнее в предзаполнении, чем в генерации по токену. Если вы видите прирост на tg и нулевой на pp, условия запуска стоит перепроверить.
Разброс между прогонами одной и той же конфигурации легко достигает нескольких процентов, особенно на первом запуске после прогрева GPU. Отсюда минимум три повтора на точку и оценка размаха, а не единственного числа. Учитывайте троттлинг: на ноутбуках и в плохо продуваемых корпусах результаты падают по ходу длинного теста, и патч тут ни при чём. Если разница укладывается в ваш разброс, честный вывод - на этом сетапе выигрыша нет.
Если разница в 2-3% на prefill попадает внутрь разброса в 3%, от шума её не отделить. Для Gemma 26B A4B это особенно верно, когда вы гоняете короткие промпты: доля attention в общем времени там мала.
Стоит ли обновляться и ждать ли мержа
Рамка решения простая. Не запускаете Gemma 26B A4B - PR #28450 вам не нужен, живите на обычных релизах и следите за changelog. Запускаете и хотите понять, что там внутри - соберите ветку отдельно от рабочей сборки и сравните на своих задачах.
Статус пул-реквеста в момент написания не подтверждён как смерженный. PR может пройти ревью и попасть в основную ветку, может быть переработан после замечаний, а может быть закрыт - это обычный процесс, а не гарантия результата. Аргументов за «срочно обновляться всем» тут нет.
Даже после мержа эффект зависит от бэкенда, версии драйверов и вашей конфигурации запуска. Полезно помнить, что ускорения инференса в llama.cpp редко приходят поодиночке: рядом развиваются CUDA graph для MTP draft (разбор PR #28549) и другие изменения, и складывать их эффект можно только после независимых замеров.
Риски использования неслитого патча
- Регрессии на других моделях, если правка задевает общий код пути flash attention.
- Нестабильность на бэкендах, которые автор не проверял.
- Отсутствие поддержки: если что-то падает, чинить придётся самому или ждать обновления ветки.
- Необходимость пересобирать ветку, когда основная ветка уезжает вперёд, а конфликты никто не разрешает.
- Отсутствие готовых бинарных сборок: обычно это компиляция из исходников со своим набором зависимостей и версией CUDA или ROCm.
Практика: отдельная директория, отдельный билд, рабочая установка не трогается. Если вы собираете llama.cpp сами, вторая сборка обходится дешевле, чем восстановление рабочего сетапа после неудачного эксперимента.
Что это говорит о зрелости llama.cpp
Появление адресных патчей под конкретные модели - нормальная черта llama.cpp. Изменения приходят в том числе от сообщества, а не только от мейнтейнеров, поэтому тюнинг под свежую архитектуру нередко появляется раньше, чем в альтернативных рантаймах. Для пользователя это плюс: можно найти правку под свою модель и проверить её на своём железе.
Обратная сторона: качество и стабильность таких изменений зависят от ревью и от того, насколько автор готов доводить патч. Часть PR остаётся в ветках навсегда. Практический вывод: если вы регулярно запускаете конкретную модель в llama.cpp, следите за PR по ней и по нужному бэкенду. Иногда это быстрее, чем ждать релиза, но проверять выигрыш на своих задачах придётся самостоятельно.