N-gram mod в llama.cpp: ускорение вывода LLM | Анализ PR ggerganov | AiManual
AiManual Logo Ai / Manual.
30 Янв 2026 Гайд

Что такое n-gram mod в llama.cpp и как он ускоряет вывод моделей (анализ PR от ggerganov)

Разбираем pull request ggerganov в llama.cpp: как n-gram мод ускоряет генерацию текста. Объяснение работы, настройка и сравнение с другими оптимизациями.

Когда токены ползут как улитки: проблема повторного счета

Вы запускаете модель в llama.cpp и смотрите, как курсор мигает. Каждый новый токен появляется с паузой, которая сводит с ума. Основная причина - модель заново считает вероятности для каждого слова, даже если аналогичную последовательность она уже видела три предложения назад. Кажется, что кэш ключей-значений (KV-cache) должен решить все проблемы, но нет. Он ускоряет внимание, но не спасает от повторного вычисления всего контекста для банальных фраз.

Если ваша модель генерирует код, списки или шаблонные ответы, она тратит до 40% времени на вычисление того, что уже знает. Это и исправляет n-gram mod.

Старая идея, которая взорвала llama.cpp

N-gram - это не новая концепция. В лингвистике это просто последовательность из N элементов. Триграмма (3-gram) для фразы "быстрый бурый лис" - это ["быстрый", "бурый", "лис"]. В NLP их десятилетиями использовали для предсказания следующего слова. Гениальность ggerganov в том, что он применил эту идею не к словам, а к внутренним вычислениям модели во время инференса.

💡
PR #6854 от 15 января 2025 года (актуально на 30.01.2026) добавил флаг --ngram. Суть: система запоминает выходные логиты (распределение вероятностей) для часто встречающихся последовательностей токенов и подставляет их из кэша, минуя тяжелые вычисления в трансформере.

Как это работает: не магия, а хэш-таблица

При генерации каждого нового токена llama.cpp берет последние N-1 токенов (историю) и смотрит, есть ли эта последовательность в специальном кэше. Если есть - модель не вычисляет attention и FFN слои для этой n-граммы. Она сразу выдает сохраненный ранее вектор логитов. По сути, это мемоизация для трансформеров.

// Упрощенная логика из llama.cpp
struct ngram_cache {
    std::unordered_map> cache; // Хэш n-gram -> логиты
    bool find_and_use(const std::vector &tokens) {
        // Если нашли в кэше, пропускаем forward pass
        return true;
    }
};

Ключевой параметр - N. Если N=4, система кэширует результаты для всех уникальных последовательностей из 3 токенов. Для кода, где часто повторяются конструкции like for (int i = 0; i <, это дает феноменальный прирост скорости.

Включаем ускорение: одна строка в терминале

Начиная с версии llama.cpp b4580 (актуально на январь 2026), флаг --ngram работает из коробки. Не нужно пересобирать с особыми флагами.

./main -m /путь/к/model-q8_0.gguf \
  -p "Напиши функцию сложения на Python" \
  --ngram 4 \
  -n 512

Попробуйте сгенерировать один и тот же код с флагом и без. На моделях типа Llama 3.3 8B-Instruct разница в скорости может достигать 2.5 раз для задач с высокой избыточностью.

Не путайте --ngram с --repeat-penalty или Adaptive-P. Последние борются с зацикливанием текста, а n-gram mod борется с лишними вычислениями. Они могут работать вместе.

Цена скорости: память и аномалии

Кэш съедает оперативку. Для N=5 и контекста в 4096 токенов overhead может составить 200-500 МБ в зависимости от размера модели. Но главная опасность - потенциальные артефакты.

Если модель впервые встречает последовательность "The quick brown fox", а потом видит "The quick brown dog", но у них общая n-gram "The quick brown", кэш может подсунуть неверные логиты для "dog". На практике такое случается редко, но для задач, где важна точность (например, генерация JSON), лучше ставить N поменьше или отключать мод.

С чем едят n-gram mod: комбинированные оптимизации

Одна эта техника не сделает из вашего Intel Core i5 монстра для LLM. Но в связке с другими методами результат шокирует.

МетодУскорениеСовместимость с n-gram
KV-cache (включен по умолчанию)2-3xДа, идеально
Layer Pruning1.3-1.5xДа, но кэш может стать менее полезным
Квантование до Q4_K_M1.8-2xДа, абсолютно
Специализированные ядра (BLAS)1.5-2xДа, ускоряет и forward pass, и кэш

Для экстремальных сценариев, например, запуска на старом ноутбуке, комбинация n-gram mod с квантованием Q4_K_M - единственный способ получить приемлемую скорость.

Где это сломается: границы применения

  • Творческие тексты. Если модель генерирует уникальный роман, повторяющихся n-gram почти нет. Кэш будет пустым, а overhead - бесполезным.
  • Очень маленькие N. При N=1 или N=2 кэш захламляется тривиальными последовательностями, поиск по хэш-таблице начинает тормозить.
  • Мультиязычные модели. Для моделей типа PLaMo 3, которые работают с японским и английским, кэш должен быть больше из-за разной структуры языков.
  • Интерактивный режим. Если вы постоянно прерываете генерацию (например, в чат-интерфейсе), кэш сбрасывается. Польза минимальна.

Что дальше? Будущее за гибридным кэшированием

Идея ggerganov открыла ящик Пандоры. Теперь разработчики экспериментируют с адаптивным N, который меняется в зависимости от энтропии текста. Другое направление - кэширование не только логитов, но и промежуточных активаций для частичных n-gram.

Самое интересное - применение этой техники к архитектуре моделей на этапе обучения. Если модель изначально спроектирована с учетом n-gram кэширования, можно добиться еще большего ускорения.

Пока же совет простой: если ваша задача - генерация структурированного текста, включайте --ngram 4. Если модель начинает глючить - уменьшайте до 3. А если вы просто общаетесь с моделью, как с ассистентом, не заморачивайтесь. Разница будет почти незаметна. Но для автоматизации, где каждый миллисекунд на счету, это must-have опция.