Что именно сделала Embedl: короткий ответ
Embedl собрала оптимизированный инференс Qwen3.8-27B для NVIDIA Jetson Thor. Нижний слой - порт на TensorRT Edge-LLM 0.10.1, поверх него три надстройки: собственная INT4-квантизация весов, FlashHead (ускоренная выходная голова модели) и MTP-голова для спекулятивного декодирования. Модель на 27B параметров исполняется локально, без обращения к внешнему API.
Цифры одного замера: batch 1, промпты на 2 048 токенов из реальных диалогов OpenAssistant, 128 токенов вывода, greedy-декодирование, среднее по 20 запросам. Результат - 39,6 tok/s на декодировании, 23,6 tok/s end-to-end, 926 tok/s на обработке промпта, пик памяти 24,8 GiB. Публикация Embedl в r/LocalLLaMA приводит эти числа вместе с полными условиями, поэтому сценарий можно повторить или оспорить.
Точность держится около FP16-версии: GSM8K 96,4 против 96,1, IFEval 83,5 против 81,9, MMLU-Pro 79,1 против 79,5. Проверка шла на полных тестовых наборах, не на выборке.
Все метрики опубликованы Embedl. Независимого воспроизведения в этом материале нет, и это главная оговорка ко всему тексту ниже.
Почему на Jetson Thor выходная голова и память важнее сырой квантизации
При batch 1 декодирование упирается в память. На каждом шаге нужно прочитать веса слоёв и KV-кэш, а параллелизма, который спрятал бы задержки, почти нет. Выигрыш даёт всё, что сокращает объём чтения или число шагов; битность весов здесь один из рычагов, и не самый крупный.
Отдельная статья расходов - выходная голова. Словарь Qwen3.8-27B содержит 262k токенов, и на каждый новый токен строится распределение по всему словарю. При batch 1 это заметная доля времени шага: арифметика мелкая, а матрицу головы всё равно надо прочитать. FlashHead бьёт ровно в это место.
Память в 24,8 GiB складывается из весов, KV-кэша под 2 048 токенов промпта и рабочих буферов. Точного разбиения Embedl не публиковала, поэтому любые оценки долей по компонентам останутся прикидкой. Ориентир для планирования другой: около 20 GiB скачиваемых весов задают нижнюю границу, остальное приходится на кэш и буферы.
Практический вывод простой. На компактном устройстве главный лимит - объём весов и кэша, а не пиковая арифметика, поэтому ускорение здесь собирается из точечных решений под конкретное железо.
Четыре компонента ускорения: что делает каждый
Embedl перечисляет компоненты единым стеком и не приводит вклад каждого в процентах. Разбирать их можно по назначению, не по измеренному эффекту.
INT4-квантизация Embedl: вдвое меньшая ошибка, чем у AWQ
Переход с FP16 на INT4 сокращает объём весов примерно вчетверо и во столько же раз трафик памяти на их чтение. Плата - ошибка квантования, которая накапливается по слоям и вылезает в качестве ответов. AWQ - распространённый метод с активационно-осведомлённым подбором масштабов; Embedl заявляет, что её вариант даёт примерно вдвое меньшую ошибку, чем стандартный AWQ.
Формулировка «вдвое меньшая ошибка» взята из публикации. В чём именно измерялась ошибка (perplexity, KL-дивергенция или что-то ещё) и на каких данных, источник не раскрывает. Воспринимать это стоит как ориентир разработчика, не как воспроизводимую величину. Косвенная проверка - итоговые бенчмарки: если бы квантизация заметно портила модель, GSM8K и IFEval так близко к FP16 не выглядели бы.
FlashHead: не скорить весь словарь на 262k токенов
FlashHead - ускоренная выходная голова LM. Вместо полного скоринга словаря на 262k токенов она оценивает только вероятных кандидатов.
Механика понятна из описания: полный проход по словарю даёт вектор логитов на 262 тысячи значений, и если заранее ограничить пул кандидатов, шаг декодирования становится короче. Это эвристика, у неё есть цена: маловероятный токен может не попасть в пул. Отдельного замера качества именно FlashHead в источнике нет, судить можно только по итоговым цифрам модели. Схема генерации при этом не меняется, ускоряется тот же шаг.
MTP-голова и спекулятивное декодирование
MTP-голова включает спекулятивное декодирование: модель предсказывает несколько следующих токенов, основная модель проверяет их за один проход, и при удачных догадках за шаг принимается больше одного токена. Выигрыш зависит от предсказуемости текста и режима сэмплирования. В greedy, где следующий токен почти детерминирован, попадания чаще, и замер Embedl сделан именно в greedy.
MTP встречается и в альтернативном рецепте Jetson AI Lab (llama.cpp Q4_K_M + MTP), так что приём общий для платформы. Разница между решениями не в наличии головы, а в том, что её окружает. Почему увеличение длины черновика не всегда ускоряет генерацию, разбирали в материале про MTP для Ling-3.0-Flash на DGX Spark.
Порт на TensorRT Edge-LLM 0.10.1
TensorRT Edge-LLM - стек NVIDIA для инференса LLM на edge-устройствах. Порт на версию 0.10.1 означает, что квантизованные веса, FlashHead и MTP-голова работают внутри этого рантайма и выдают те же ответы, что референс. Это отдельный пласт работы: графы, ядра под конкретное железо, совместимость версий.
Деталей API и полного списка поддержанных сценариев источник не раскрывает. Смысл в другом: 39,6 tok/s получились на связке алгоритмов и рантайма, а не на одном удачном кванте.
Как читать цифры: decode, end-to-end и prompt processing - это разные вещи
Три метрики отвечают на три разных вопроса.
- Обработка промпта, 926 tok/s: скорость префилла, то есть чтения входного контекста перед генерацией.
- Декодирование, 39,6 tok/s: скорость появления новых токенов, когда промпт уже прочитан.
- End-to-end, 23,6 tok/s: сколько токенов вывода в среднем выходит за секунду с учётом префилла.
Арифметика сходится. 2 048 токенов промпта при 926 tok/s - около 2,2 с. 128 токенов вывода при 39,6 tok/s - около 3,2 с. Итого примерно 5,4 с на запрос, а 128 разделить на 5,4 даёт 23,6 tok/s. Промпт и генерация занимают сопоставимое время, поэтому end-to-end почти вдвое ниже декодирования.
Практический вывод: в чате с коротким вопросом и развёрнутым ответом вы ближе к 39,6 tok/s, в RAG с длинным контекстом и короткой репликой - к 23,6 tok/s. Все числа получены при batch 1, greedy и 128 токенах вывода; других режимов в источнике нет.
Как отделять скорость чтения контекста от скорости генерации на другой конфигурации и почему пиковые значения без условий почти ничего не говорят, разбирали в разборе запуска Qwen 3.8 27B на одной RTX 5090. Там же есть чек-лист метрик для сравнения движков, он пригодится и здесь.
Сравнение с Jetson AI Lab: почему 35 tok/s и 39,6 tok/s - не прямой матч
Jetson AI Lab сообщает около 35 tok/s декодирования на llama.cpp с Q4_K_M и MTP, но не указывает длину промпта и не публикует точность.
Это ломает прямое сравнение. Длина промпта влияет на префилл и на end-to-end, а без данных о точности нельзя утверждать, что 35 tok/s получены при сопоставимом качестве. Q4_K_M и INT4 от Embedl - разные схемы квантизации с разной ошибкой, и сравнение скоростей без сравнения качества неполное.
Что сказать корректно: оба подхода используют MTP и 4-битные веса, оба работают на Jetson Thor, порядок скорости близкий (35 и 39,6 tok/s). Плюс Embedl в том, что она публикует точность на трёх бенчмарках и полные условия замера, то есть результат можно проверить. Минус в том, что независимой проверки пока нет ни у одной из сторон.
Победителя по этим цифрам объявлять нельзя. Разница 4,6 tok/s меньше неопределённости, которую вносит неизвестная длина промпта. Как строить честное сравнение и какие выводы из чужих замеров делать не стоит, разбирали на примере тестов DeepSeek V4.1 Flash на восьми A40.
Точность: насколько INT4 действительно близка к FP16
| Бенчмарк | Сборка Embedl (INT4) | FP16 | Разница |
|---|---|---|---|
| GSM8K | 96,4 | 96,1 | +0,3 |
| IFEval | 83,5 | 81,9 | +1,6 |
| MMLU-Pro | 79,1 | 79,5 | -0,4 |
Два набора выше FP16, один ниже на 0,4 пункта. Такие расхождения выглядят как шум, а не как систематическая деградация: на IFEval сборка выигрывает 1,6 пункта, и на масштабе 80+ это скорее вариативность, чем реальное превосходство над FP16.
Методическая деталь важнее самих чисел. Замер шёл на полных тестовых наборах и на том же движке, что используется при обслуживании. Это исключает разрыв между «лабораторной» и «рабочей» конфигурацией, который часто прячется за красивыми таблицами.
Ограничение по охвату: три бенчмарка не проверяют длинный контекст, генерацию кода и мультиязычность. Данных по этим сценариям в источнике нет.
Как запустить: команды, память и OpenAI-совместимый API локально
Разовый запрос к модели:
embedl infer Qwen/Qwen3.8-27B/thor --prompt "Hello"
Постоянный сервер с OpenAI-совместимым API:
embedl serve Qwen/Qwen3.8-27B/thor
Контейнер занимает около 1 ГБ, веса скачиваются отдельным шагом и весят около 20 GiB. Место на диске и время загрузки планируйте заранее: это не мелочь при развёртывании на устройстве.
По памяти ориентир такой: пик в замере 24,8 GiB при batch 1. Столько занимает сам инференс, к этому добавляется система и другие процессы, поэтому запас нужен. Меньше 24,8 GiB свободной памяти под модель рассчитывать не на что.
OpenAI-совместимый API даёт практическую вещь: существующие клиенты и SDK, написанные под OpenAI, можно направить на локальный endpoint и не переписывать код. Это удобный путь для агентов, RAG и автоматизации прямо на устройстве, без выхода в интернет.
Других флагов, параметров и версий источник не приводит, придумывать их не нужно: начните с двух команд выше.
Кому это нужно и где ограничения
Кейс полезен тем, кто строит локальный инференс на компактном устройстве под одиночные диалоги, агентов и RAG с умеренным контекстом, и кому важна точность уровня FP16 при 4-битных весах. Это сценарий «одна модель, один пользователь или небольшой поток запросов», а не сервер под нагрузку.
Ограничения перечислим прямо:
- Замер только при batch 1. Про пропускную способность под параллельной нагрузкой данных нет.
- Только greedy. Поведение при сэмплировании с temperature и top-p не измерено, а для спекулятивного декодирования это важный режим.
- Вывод 128 токенов. Как ведёт себя модель на длинной генерации в несколько тысяч токенов, неизвестно.
- Промпты 2 048 токенов. Что происходит на 8k и выше, по опубликованным цифрам не проверить.
- Цифры опубликованы Embedl, независимого воспроизведения нет.
- Сравнение с llama.cpp неполное: у Jetson AI Lab нет данных о длине промпта и точности.
Что показывает этот кейс на более широком горизонте: связка собственной квантизации, ускоренной выходной головы, MTP-головы и порта на TensorRT Edge-LLM позволяет держать 27B-модель на компактном устройстве без заметной потери точности. Универсальным рецептом это не делает, и доказательством превосходства над llama.cpp тоже. Оптимизация под конкретное железо даёт больше, чем одна квантизация весов, но проверять её на своей нагрузке всё равно придётся самому.