Что именно изменилось в llama.cpp и почему это заметно на Arc B70
В пул-реквесте #29864 проекта llama.cpp автор под ником budiony предложил переработать обращение к матричным движкам Intel XMX в SYCL-бэкенде. По сообщению автора, изменение дало большой прирост скорости спекулятивного декодирования на его видеокарте Intel Arc B70, работающей через SYCL. Публикация с результатами вышла у nickm_27 в сообществе r/LocalLLaMA (исходный пост с цифрами).
Ключевые числа: агрегированное время девяти тестовых запросов сократилось с 46,86 до 26,68 секунды, а скорость генерации выросла примерно с 36-53 до 54-88 токенов в секунду в зависимости от задачи. Суммарное число предсказанных токенов при этом почти не изменилось: 1724 до правки и 1728 после. То есть модель генерировала тот же объём текста, просто быстрее.
Конфигурация теста известна полностью: модель Muse Glimmer Q6_K (30B), спекулятивное декодирование с DFlash2, видеокарта Intel Arc B70, SYCL-бэкенд llama.cpp. Это отчёт автора изменения о своём железе, а не независимый бенчмарк и не результат работы тестовой лаборатории. Все оценки ниже стоит читать с этой поправкой.
Смысл правки в одном предложении: обращение к XMX-движкам в SYCL-пути стало эффективнее, проверка токенов при спекулятивном декодировании подешевела, и автор смог отправлять на проверку заметно больше драфт-токенов за то же время.
Speculative decoding в llama.cpp: как он работает и где было узкое место
Обычная генерация в llama.cpp последовательная: модель выдаёт один токен, затем второй, и каждый шаг упирается в задержку обращения к памяти и скорость вычисления матриц. Спекулятивное декодирование ломает эту цепочку. Черновая модель или специальный механизм (в тесте из PR использовался DFlash2) предлагает несколько токенов вперёд, а целевая модель проверяет всю пачку за один проход и оставляет совпавший префикс плюс один уточняющий токен.
Выигрыш берётся из параллелизма: проверить пять токенов пачкой дешевле, чем сгенерировать пять токенов по одному. Схема подробно разбиралась в материале про CUDA graph для MTP draft в llama.cpp, там же видно, насколько результат зависит от накладных расходов на каждом шаге.
Узкое место спекулятивного декодирования - стоимость проверки. Верификация это те же матричные умножения на целевой модели, только применённые к батчу токенов. На GPU Intel такие операции быстрее всего выполняют XMX-движки. Если SYCL-бэкенд задействует их неоптимально, проверка выходит дорогой, и смысл в длинных драфтах пропадает: проще генерировать по одному токену. Насколько именно рефакторинг меняет расклад внутри ядра, видно по диффу самого пул-реквеста, в источнике таких деталей нет.
Драфт-токены, accept rate и n-max: три параметра, которые связаны
В отчётах llama.cpp по спекулятивному декодированию встречаются четыре величины. total_draft - сколько токенов предложила черновая модель. total_draft_accepted - сколько из них целевая модель приняла. aggregate_accept_rate - отношение второго к первому, то есть доля принятия. n-max - верхняя граница числа драфт-токенов на один шаг проверки.
Логика настройки простая, хотя и неочевидная. Когда проверка дорогая, выгодно предлагать мало токенов и добиваться высокой доли принятия: каждая ошибка оплачивается по полной. Когда проверка дешевеет, выгоднее отправлять много предложений даже при низком accept rate, если итоговое время генерации падает. Именно этот сдвиг и произошёл в PR #29864.
Intel XMX и SYCL: что это и при чём тут локальные LLM на Intel Arc
XMX (Xe Matrix Extensions) - матричные движки в GPU Intel, отдельные блоки для умножения матриц. Инференс языковых моделей почти целиком состоит из таких операций, поэтому от загрузки XMX напрямую зависит скорость генерации и обработки промпта.
SYCL - программная модель для гетерогенных вычислений, на которой построен бэкенд llama.cpp для GPU Intel. Через него карта получает вычислительные задачи. Если бэкенд общается с XMX неэффективно, часть аппаратного потенциала простаивает: карта справляется, но медленнее, чем позволяет железо.
Для владельцев Arc это существенно, потому что SYCL остаётся основным путём запуска llama.cpp на их видеокартах. Любая правка в этом бэкенде меняет не абстрактный бенчмарк, а скорость работы с локальной моделью на конкретной машине. Похожая история происходит и на стороне AMD: в материале про оптимизацию llama.cpp под ROCm разбирается пул-реквест с приростом до 15% на обработке промптов, и там тоже речь про эффективность бэкенда, а не про новые модели.
Цифры до и после: что показывают тесты на B70
Агрегат по девяти запросам: общее время 46,86 с до правки и 26,68 с после, то есть примерно на 43% меньше. Число предсказанных токенов осталось тем же (1724 и 1728), значит ускорение не связано с урезанием генерации.
| Запрос | tok/s до | accept rate до | tok/s после | accept rate после |
|---|---|---|---|---|
| code_python | 38,0 | 0,835 | 73,0 | 0,441 |
| translation | 45,1 | 0,760 | 87,7 | 0,427 |
| stepwise_math | 53,2 | 0,868 | 77,6 | 0,320 |
| creative_short | 37,1 | 0,808 | 53,6 | 0,330 |
Разброс прироста большой. Минимум до правки составлял 36,2 tok/s на запросе code_cpp, максимум до - 53,2 tok/s на stepwise_math. После правки диапазон сместился к 53,6 tok/s на creative_short и 87,7 tok/s на translation. Перевод и код получили кратный рост, короткий креативный запрос - примерно в полтора раза.
Тип задачи влияет на результат сильнее, чем хотелось бы: чем предсказуемее продолжение, тем чаще черновая модель угадывает и тем больше токенов проходит проверку за один шаг. Все значения получены на Muse Glimmer Q6_K (30B) с DFlash2 на Arc B70 под SYCL (детали теста). На другой модели, другом квантовании и другой карте цифры будут другими.
Почему доля принятых драфтов упала с 0,7845 до 0,363 и почему это не регресс
Сам автор объясняет это прямо: проверка токенов подешевела настолько, что он увеличил n-max. Драфтов стало больше, абсолютное число принятых тоже выросло, а доля принятия закономерно просела.
Смотрите на цифры. total_draft вырос с 1383 до 3504, то есть предложений стало в 2,5 раза больше. total_draft_accepted увеличился с 1085 до 1272. При этом aggregate_accept_rate упал с 0,7845 до 0,363. Принятых токенов больше, мусорных предложений тоже больше, время на выходе меньше.
accept rate не описывает ни качество текста, ни скорость. Это техническая величина, зависящая от того, сколько токенов вы разрешили предлагать. Сравнивать конфигурации по ней некорректно: режим с высоким accept rate и короткими драфтами может оказаться медленнее режима с низким accept rate и длинными драфтами. Ориентир - суммарное время на одинаковый набор запросов и одинаковый объём генерации.
Что это значит на практике для владельцев GPU Intel
Изменение касается тех, кто запускает llama.cpp на видеокартах Intel Arc через SYCL и включает спекулятивное декодирование. Если вы генерируете текст, код или переводы на локальной модели и раньше отключали спекулятивное декодирование из-за медленной проверки, этот сценарий стоит перепроверить на своей сборке.
Логика настройки n-max после такого ускорения: поднимайте значение и измеряйте итоговые tok/s, а не гоняйтесь за красивым accept rate. Оптимум зависит от модели, квантования, типа задач и объёма VRAM. На B70 с Muse Glimmer Q6_K (30B) автор остановился на режиме с accept rate 0,363 - и получил 26,68 с вместо 46,86 с. На другой карте баланс может сместиться.
Переносить цифры с B70 на Arc A770 или встроенную графику нельзя: другой объём памяти, другая пропускная способность, другая поддержка XMX в конкретной сборке. Практический опыт с других конфигураций показывает, насколько велика разница между «включил и заработало» и «подобрал параметры»: в кейсе апгрейда AI-сервера с 3x RTX 3090 на 2x RTX 5090 отдельный вклад спекулятивного декодирования приходится оценивать заново под каждое железо.
Как проверить эффект на своей конфигурации
- Зафиксируйте условия: одна модель и одно квантование, одинаковые параметры запуска, одинаковый набор запросов, включённый DFlash2.
- Снимите базовые замеры на текущей сборке: агрегированное время по набору запросов, tok/s по каждой задаче, total_predicted, total_draft, total_draft_accepted.
- Повторите замер на сборке с рефакторингом XMX, меняя только n-max и не трогая остальные параметры.
- Сравнивайте по общему времени и tok/s при сопоставимом total_predicted. Если объём генерации разошёлся, сравнение недействительно.
- Проверьте разные типы задач отдельно: код, перевод, пошаговая математика и короткий креатив ведут себя по-разному, в тесте из PR разница достигала 1,6 раза.
Это методика проверки, а не воспроизведённый нами бенчмарк. Свои цифры придётся получать самостоятельно.
Ограничения и статус данных: чему эти цифры не учат
- Один пользовательский тест на одной конфигурации: Arc B70, SYCL, Muse Glimmer Q6_K (30B), DFlash2. Выборка маленькая, повторных прогонов в источнике не описано.
- Источник - сообщение автора пул-реквеста и публикация nickm_27, а не независимая проверка третьей стороной. Цифры не воспроизводились вне этой машины.
- Пул-реквест это предложение изменения, а не гарантия того, что код уже вошёл в стабильную сборку. Перед обновлением проверяйте статус PR и наличие правки в вашей версии llama.cpp.
- Прирост зависит от задачи: от 53,6 до 87,7 tok/s после правки в одном и том же тесте. Единой цифры «стало быстрее в N раз» здесь нет.
- Падение accept rate с 0,7845 до 0,363 вызвано намеренным ростом n-max, а не ухудшением работы движка. Сравнивать эти значения между конфигурациями с разным n-max бессмысленно.
- О влиянии на другие GPU Intel, другие бэкенды и другие модели источник данных не содержит (первоисточник).
Вывод: стоит ли следить за XMX-рефакторингом в llama.cpp
Рефакторинг XMX для SYCL в PR #29864, по сообщению автора, сократил время выполнения девяти запросов с 46,86 до 26,68 секунды на Arc B70. Механика прироста понятна: проверка токенов подешевела, n-max вырос, драфтов стало больше (1383 против 3504), принятых токенов тоже больше (1272 против 1085), а доля принятия упала до 0,363 именно из-за смены режима.
Для владельцев GPU Intel это сигнал, что SYCL-бэкенд продолжает оптимизироваться, причём в части, которая напрямую влияет на спекулятивное декодирование. Решение о переходе стоит принимать после собственных замеров: соберите llama.cpp с SYCL, прогоните одинаковый набор задач на текущей и новой сборке, сравните общее время и tok/s при одинаковом объёме генерации. Если прирост подтвердится на вашей конфигурации, поднимите n-max и повторите замер.