От 12 до 38 токенов в секунду: как и почему ускорился M3 Ultra
Всё стартовало с тривиальной, казалось бы, задумки.
Стояла цель развернуть локальную версию Qwen3.8–27B без потери точности — строго в формате BF16. Речь шла не о запуске стандартного чекпоинта PyTorch через прослойки совместимости, а об использовании mlx-community/Qwen3.8-27B-bf16 — сборки, изначально оптимизированной под экосистему Apple Silicon на базе фреймворка MLX. Вся коллекция Qwen3.8 от mlx‑community создавалась специально для архитектуры чипов Apple.
Иными словами, нейросеть уже имела нативную адаптацию под Mac. Я сознательно отказался от 8-битного и 4-битного квантования: погоня за дутыми показателями в синтетических тестах меня не интересовала. Требовалась максимальная глубина и точность рассуждений для аналитической работы, программирования и разбора нетривиальных сценариев.
Аппаратных ресурсов, судя по спецификациям, должно было хватить с огромным запасом.
В тестировании участвовал Mac Studio образца 2025 года (идентификатор Mac15,14, артикул Z1CE001BMZP/A) на базе флагманского чипа Apple M3 Ultra: 32 процессорных ядра (24 из которых высокопроизводительные), 80-ядерная графика, 512 ГБ унифицированной памяти и накопитель емкостью 2 ТБ. Заявленная пропускная способность подсистемы памяти достигает внушительных 819 ГБ/с.
Это отнюдь не портативный лэптоп, нагруженный непосильной задачей, а предельная конфигурация M3 Ultra по вычислительным блокам и объему памяти.
Тем не менее, адаптированная под Apple Silicon версия Qwen3.8–27B в BF16 смогла выдать лишь скромные 12 токенов в секунду.
Подобный темп вызывал недоумение. Монструозный массив ядер CPU и GPU, модель целиком помещается в ОЗУ, используется «родной» фреймворк MLX — почему производительность оказалась столь далекой от ожиданий для топового чипа? Я решил разобраться в корне проблемы.
Почему 80 графических ядер не помогли формату BF16
Распространенное заблуждение — оценивать скорость вывода LLM исключительно по количеству ядер GPU.
При обработке входящего контекста (prompt processing) графический процессор превосходно параллелит операции. Однако авторегрессионный вывод строится принципиально иначе: генерация строго последовательна, и каждый новый токен опирается на контекст предыдущего. Не рассчитав шаг $N$, модель физически не способна перейти к шагу $N+1$.
Здесь и кроется главный нюанс.
Архитектура Qwen3.8–27B насчитывает около 27 миллиардов весов. В 16-битном формате (BF16) каждому параметру отводится 2 байта, что дает чистый объем модели порядка 54 ГБ. Для генерации единственного токена полносвязная модель обязана прогнать активации через всю глубину слоев, то есть вычитать из оперативной памяти практически весь массив своих весов.
Этот тип нагрузки классифицируется как memory-bound: узким горлышком выступает не вычислительная мощь ALU, а скорость доставки данных из памяти к вычислительным блокам. При генерации одного потока ядра GPU быстро завершают локальный расчет и простаивают в ожидании следующего блока весов. Эта фундаментальная черта фазы декодирования детально проанализирована, например, в материалах конференции OSDI по инференсу LLM.
Упрощенный расчет дает следующую теоретическую планку:
819 ГБ/с ÷ 54 ГБ ≈ 15 токенов/с
Это абсолютно идеализированный предел без учета оверхеда фреймворка, синхронизации потоков, обновления KV-кэша и сопутствующих вычислений. В этом контексте фактические 12 токенов/с уже не кажутся аномалией: для прямого последовательного инференса в BF16 это показатель, вплотную приближенный к физическим возможностям шины памяти.
Колоссальный объем в 512 ГБ снимает ограничения по вместимости моделей, но емкость и пропускная способность — фундаментально разные параметры. Унифицированная память избавляет от накладных расходов на пересылку между RAM и VRAM, однако не отменяет необходимости прокачивать десятки гигабайт на каждом дискретном шаге.
Процессорные ядра тоже не способны переломить ситуацию — их специфика не позволяет превратить последовательную генерацию в параллельную. Причина крылась не в программном сбое или неполной утилизации M3 Ultra, а в базовых законах авторегрессии.
Две стратегии преодоления барьера
Если увеличить скорость шины памяти физически невозможно, остается другой путь: извлекать больше одного токена за каждый дорогостоящий проход весов основной модели.
Это приводит нас к технике спекулятивного декодирования (speculative decoding). Суть метода: легковесный алгоритм генерирует блок токенов-кандидатов, после чего массивная модель валидирует их пачкой за один шаг. При успешном совпадении стоимость чтения 54 ГБ распределяется сразу на группу сгенерированных токенов.
Применительно к Qwen3.8–27B существовало два основных инструмента:
-
MTP (Multi-Token Prediction) — нативный механизм параллельного предсказания нескольких токенов, заложенный в саму модель;
-
DFlash2 — автономная вспомогательная draft-модель на принципах блочной диффузии (block diffusion), формирующая пакет токенов для последующей сверки. Детали реализации изложены в описании модели DFlash2.
В среде oMLX данные подходы взаимоисключающи: активировать MTP и DFlash одновременно нельзя. Исследование разделилось на два самостоятельных направления.
Работу MTP я разберу в отдельном материале, здесь же сосредоточимся на экспериментах с DFlash2.
Критерии выбора oMLX
Исходная модель уже находилась в хранилище LM Studio, поэтому возник закономерный вопрос: зачем было разворачивать сторонний серверный стек?
Причина — специфика DFlash2.
LM Studio поддерживает стандартную схему спекулятивного вывода: компактная модель пошагово формирует токены, а флагманская их валидирует (как описано в документации LM Studio). Однако DFlash2 работает принципиально иначе: это диффузионный генератор блоков, требующий от движка поддержки одновременной генерации пула кандидатов, групповой валидации, применения совпадений и отката состояния кэша при первой же ошибке.
В использованной сборке LM Studio данный алгоритм для Qwen3.8–27B-DFlash2 отсутствовал.
В случае с mlx-vlm картина сложнее. Проект уже получил интеграцию DFlash для ряда моделей Qwen, поэтому списывать его со счетов нельзя. Однако для целевого тандема Qwen3.8-27B + Qwen3.8-27B-DFlash2 требовался не сырой код, а стабильная серверная среда с гибкой параметризацией и детальной телеметрией выполнения.
Этим требованиям полностью соответствовал oMLX, обеспечив:
-
индивидуальное управление DFlash для каждой целевой модели;
-
точный выбор вспомогательной draft-модели;
-
тонкую настройку квантования драфта, параметров Window, Sink и режимов валидации (Verify Mode);
-
OpenAI-совместимый API для автоматизации замеров;
-
прозрачные серверные логи с фиксацией активности
DFlashEngine, коэффициента принятия (acceptance rate) и циклов инференса.
Выбор oMLX обусловлен не эстетикой интерфейса, а тем, что на момент тестов это было единственное решение, где связка с DFlash2 для Qwen3.8–27B гарантировала стабильную и воспроизводимую работу. Сама схема интеграции DFlash в oMLX охватывает полный контур: draft, verify, accept и replay.
При этом дублировать файлы не потребовалось — директория ~/.lmstudio/models была подключена в oMLX напрямую. LM Studio послужила файловым репозиторием, а oMLX — вычислительным ядром.
Факт № 1: активность тумблера не гарантирует результат
Прежде всего требовалось подтвердить, что алгоритм DFlash физически выполняет инференс, а не просто отображается активным в UI.
В качестве целевой модели на старте использовалась только оригинальная mlx-community/Qwen3.8-27B-bf16. Приоритет оставался неизменным: добиться прироста скорости в BF16 без компромиссов по точности весов.
Роль вспомогательного модуля выполняла incoai/Qwen3.8-27B-DFlash2.
Механика процесса прозрачна: черновая модель генерирует предположения, а целевая проводит их ревизию. При высоком проценте совпадений итоговая скорость возрастает; в случае регулярных расхождений холостая работа лишь тратит ресурсы.
Соответственно, определяющей метрикой становится не только быстродействие вспомогательной модели, но и acceptance — доля принятых токенов.
Подтверждением работы служили системные логи сервера:
DFlashEngine loaded: target=... draft=...
По завершении ответа логировалась финальная статистика:
DFlash generation complete: ... acceptance=... cycles=...
Это дало твердую уверенность: движок DFlash штатно инициализирован, провел полный цикл генерации и выдал измеримый acceptance rate. Эксперимент можно было углублять.
Гипотеза 1: влияние размера контекстного окна драфта
Базовый профиль настроек содержал:
-
Draft Window — 2048;
-
Draft Sink — 0;
-
Verify Mode —
adaptive; -
Draft Quantization —
OFF.
В такой связке версия Qwen3.8–27B в BF16 продемонстрировала 17,9 токена/с при уровне валидации 68,3%.
Возникла гипотеза: поможет ли сужение окна до 1024 токенов? Уменьшение контекста для черновой модели снижает объем вычислений, что в теории могло дать прирост.
Реальность показала обратное: скорость просела до 13,8 токена/с, а процент принятых токенов упал до 58,8%. Черновая модель стала чаще ошибаться, и накладные расходы на исправление промахов перечеркнули всю выгоду от легкого контекста.
Это фундаментальный вывод: в спекулятивных архитектурах оптимизация отдельного узла вне контекста всей цепочки губительна. Локальная операция становится быстрее, но учащение перепроверок основной моделью обрушивает общую пропускную способность.
Конфигурация с окном 2048 осталась эталоном.
Гипотеза 2: квантование draft-модели
Следующая идея казалась очевидной: если квантование ускоряет инференс, логично сжать саму модель DFlash.
Были протестированы три конфигурации:
|
Draft‑конфигурация |
Скорость |
Acceptance |
|---|---|---|
|
Quantization OFF |
17,9 ток/с |
68,3% |
|
W8A16 |
14,3 ток/с |
58,0% |
|
W4A16 |
13,3 ток/с |
55,3% |
Результаты оказались показательными.
Квантованный драфт действительно выполняет предсказания быстрее, но общая производительность системы падает. Из-за снижения точности гипотез целевая модель отклоняет значительную часть токенов, что приводит к деградации результирующего throughput.
Мы ускорили ассистента, но тот начал выдавать больше брака, заставляя основную модель тратить время на переделывание работы.
В итоге объем вычислений только вырос.
Вывод однозначен: квантование DFlash (Draft Quantization) необходимо отключать — во всяком случае, в рамках данной модели и проверенных параметров.
Неожиданный вывод: квантовать следовало основной модуль
По итогам тестов возможности ускорения BF16 были исчерпаны. В чистом виде модель выдавала 12,0 токенов/с. Подключение DFlash2 (окно 2048, полноточный драфт) подняло темп до 17,9 токенов/с (при acceptance 68,3%), дав прирост в 1,49 раза (+49%).
Результат достойный, но все еще недостаточный для динамичной комфортной работы с массивными текстами. Сокращать окно нельзя, квантовать драфт бессмысленно. Дополнительных резервов для формата BF16 не оставалось.
На этом этапе в игру вступила 8-битная модификация.
Сохранив выверенную конфигурацию DFlash2, я переключил целевую модель на mlx-community/Qwen3.8-27B-8bit, чтобы оценить влияние квантования основного ядра на суммарный темп генерации.
Без спекулятивного декодирования 8-битная версия выдала 21,4 токена/с, сразу опередив BF16 с поддержкой DFlash2.
Когда же к ней подключили полноточный Qwen3.8-27B-DFlash2 (окно 2048, режим adaptive), метрики кардинально изменились:
|
Target‑модель |
DFlash |
Скорость |
Acceptance |
|---|---|---|---|
|
Qwen3.8–27B‑bf16 |
OFF |
12,0 ток/с |
— |
|
Qwen3.8–27B‑bf16 |
ON |
17,9 ток/с |
68,3% |
|
Qwen3.8–27B-8bit |
OFF |
21,4 ток/с |
— |
|
Qwen3.8–27B-8bit |
ON |
38,0 ток/с |
66,8% |
DFlash увеличил темп 8-битной сборки в 1,78 раза (+78%).
При этом тандем «8-bit + DFlash» оказался в 2,12 раза быстрее комбинации «BF16 + DFlash» (38,0 против 17,9 токенов/с).
Кажущееся противоречие легко объяснимо: квантование основной модели существенно удешевило фазу валидации, в то время как точный, неквантованный драфт сохранил высокий acceptance (66,8%). Основной модуль стал менее требовательным к пропускной способности памяти, а качество прогнозов ассистента осталось на высоте.
Именно синергия компонентов, а не единичная настройка, обеспечила качественный скачок.
Оптимальный профиль настроек
Итоговая победная конфигурация сформировалась следующим образом:
-
Target —
Qwen3.8-27B-8bit; -
Draft —
Qwen3.8-27B-DFlash2; -
Draft Quantization —
OFF; -
Draft Window — 2048;
-
Draft Sink — 0;
-
Verify Mode —
adaptive; -
L1 In‑memory cache —
ON; -
Max entries — 4;
-
Cache size — 8 ГиБ;
-
Max Context — unlimited.
Итог — 38,0 токенов в секунду при точности предсказаний 66,8%.
Безусловно, это значение отражает поведение модели на конкретном оборудовании, с заданными параметрами и библиотеками. На иных промптах или длинах контекста цифры могут варьироваться, поэтому ценность имеет именно воспроизводимая методология тестирования.
Для локальной модели на 27 млрд параметров 38 ток/с — это порог, превращающий модель из лабораторного эксперимента в полноценный инструмент повседневной продуктивности.
Но точку ставить рано.
Производительность достигнута. Что произошло с качеством?
Максимальный темп генерации не гарантирует сохранение интеллектуального уровня.
8-битная модель может выдавать 38 токенов/с, но уступать в логике, написании кода, отладке или точности выполнения сложных инструкций. Опираясь лишь на бенчмарки скорости, делать выводы о качестве нельзя.
В связи с этим я организовал комплексное слепое тестирование трех форматов Qwen3.8–27B — BF16, 8-bit и 4-bit — по ключевым направлениям:
-
рассуждения и логика (reasoning);
-
генерация программного кода (coding);
-
дебаггинг и поиск уязвимостей;
-
точность следования инструкциям (instruction following);
-
многофакторный аналитический синтез.
Проверка кода выполнялась с помощью реальной компиляции и закрытых тестов (hidden tests), исключая субъективные оценки со стороны других нейросетей. Попытка судить качество одной LLM с помощью другой лишь заменяет воспроизводимые данные вероятностными суждениями.
Результаты преподнесли немало сюрпризов. Чтобы не перегружать статью, анализ качества вынесен отдельно: здесь решалась инженерная задача ускорения BF16, а в следующем исследовании мы выясним, какую цену пришлось заплатить за эту оптимизацию и всегда ли углубленный режим reasoning приводит к качественному результату.
Главный вывод текущего этапа прост.
Максимальная производительность системы достигается не простым разгоном отдельных модулей, а их сбалансированным взаимодействием. Квантование черновой модели обрушило acceptance, тогда как квантование целевой модели дало резкий буст за счет сохранения сильного прогнозиста и удешевления валидации.
В зачете чистой скорости лидер определен: Qwen3.8–27B-8bit + DFlash2 со скоростью 38 токенов в секунду.
Анализ качества уже проведен — подробности будут в следующей публикации.
Примечание. Сравнительный анализ точности Qwen3.8–27B в форматах BF16, 8-bit и 4-bit полностью завершен. Это не тизер: код проверен компиляторами и скрытыми тестами, а данные систематизированы. В следующем материале я представлю цифры и раскрою ключевой парадокс — почему избыточный режим размышлений не просто не гарантировал успех, но в ряде кейсов препятствовал получению корректного решения.
Max дарит бонусы за заселение по «Цифровому ID»
Как производители кулеров и корпусов обманывают покупателей
Седьмая бета-версия One UI 9.0 стала доступна для смартфонов линейки Samsung Galaxy S26
Трио камер по 200 Мп и оптика Hasselblad: Oppo Find X10 Pro Max претендует на звание абсолютного камерофона
Цифровой рубль временно будет недоступен владельцам iPhone
Представлен Honor 600S 5G: долговечная батарея на 8100 мА·ч и защита IP69K всего за $255
Samsung Galaxy S26 Ultra превзошел все ожидания и стал главным хитом продаж компании во втором квартале 2026 года
В Коста-Рике заработал сервис Starlink Mobile: прямая спутниковая связь на смартфонах без визита к оператору