Перейти к содержанию
Публикация AiManual

Qwen3.8-27B на Jetson Thor: 39,6 tok/s от Embedl при точности уровня FP16

Embedl выжала из Qwen3.8-27B на Jetson Thor 39,6 tok/s декодирования при пике 24,8 GiB и точности на уровне FP16. Разбираем INT4-квантизацию, FlashHead, MTP-гол

Коротко

Что будет в материале

  1. 01

    Что именно сделала Embedl: короткий ответ

  2. 02

    Почему на Jetson Thor выходная голова и память важнее сырой квантизации

  3. 03

    Четыре компонента ускорения: что делает каждый

  4. 04

    Как читать цифры: decode, end-to-end и prompt processing - это разные вещи

Что именно сделала 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Разница
GSM8K96,496,1+0,3
IFEval83,581,9+1,6
MMLU-Pro79,179,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 тоже. Оптимизация под конкретное железо даёт больше, чем одна квантизация весов, но проверять её на своей нагрузке всё равно придётся самому.

Подписаться на канал