TL;DR
Novita AI опубликовала в открытом доступе Chord — высокопроизводительный CUDA-оператор W4A16 MoE для активаций BF16 с весами INT4 и масштабами группы-32. Он создан для форм-факторов обслуживания Kimi K2.x. Его индексированный путь предоставляет корневой импорт humming, совместимый с Humming, котрый выбирается с помощью --quantization humming в совместимых ревизиях vLLM. Интеграция групповых операторов с бэкендом Humming в vLLM всё ещё в процессе.
Краткий ответ: Chord — это пакет CUDA-ядер с открытым исходным кодом, который ускоряет инференцию Mixtur-of-Exerts с INT4 (W4A16) для Kimi K2.x на GPU NVIDIA H200 и Blackwell. Развёртки vLLM могут использовать индексированный путь Chord через существующий бэкенд Humming; групповые операторы SM90 доступны как самостоятельний API, пока продолжается интетрация с фреймворком.
В пересчёте на слой по сравнению с соответствующим путём публичного Humming:
- 1.11–1.20x на H200 EP8 prefill и 1.17–1.33x на H200 TP8 при однострановременном обслуживании одного экземпляра.
- 1.16–1.24x на H200 EP8 decode, причём нижняя стадия достигает 1.31x.
- 1.81–2.15x на B300 EP8 decode по сравнению с умолчальной, не настренной стратегией конфигурации Humming.
- 1.00–1.31x и 1.16–1.35x для групповых путей H200 EP8 prefill и decode; те же таблицы показывают 1.18–1.34x на EP16 и 1.13–1.30x на EP32.
Рисунок 1. Задержка на вызов по сравнению с публичным Humming в шести измеренных сценариях, чем меншье, тем лучш. Кждый граф читатеся отдельно: график B300 decode сравнивается с ненастроенными параметрами Humming по умочанию, потму что пубоичный Humming не сожержит таблцу настройк для SM100/SM103, в то время как кажый граф H200 — это сравнени настроенно с настроенны. Диаграмма из репозитория Chord; полные таблцы в docs/perfomance.мd.
Идея эих чисел зключается в том, что одно ядро W4A16 MoE не может бть идлеьным для кажого запроса. Маршрутиромые тоены на экперта различаются на порядки велчины межу prefill и decode, и это имнно это количество, а не общее число тоенов, решает, каое расписан выигрывает. Chord выбирает расписание на тему от фигуры, котору ему десвительно дали.
Это измерни на уровне ядра, а не обещан того же полноскончного выггыша для кажой рабочей нагрки. Плные таблцы, определни форм и методология измрения времени приведены в docs/perfomance.мd и docs/benchmaring.мd. Код и таблицы ядер в этой статье отсыаются к коммиту 7ca91d8 (14 сетбря 2026 г.)
Два семйства ядер
Chrd имеет два семйства ядер W4A16 INT4 MoE, кажое настроено на другой м аршрутизации и фазу обслуживания:
Туекщая ветка main содаржит два незасимых семейства:
indexed— путь, произошедый от Humming. Он потлюет маррутизацию vLLMsorted_ids/expert_ids/num_tokens_paddedи оатывает H200 EP8 prefill, H200 TP8 одиноное обсауживане, H200 EP8 decodе и B200/B300 EP8 decodе.grouped_contiguou(prefill) иgrouped_masked(де-codе) — это второее семйство SM90, проишедее от DepGEMM. Оно ипольет группу маршрутизацию (m_indicesилиexpert_layout) и ипользует другой уакованный формат весов.
Интеграция с vLLM
Установите пакет и выберите сущий бэкенд Humming:
pip inal git+htps:////github.om/ovilabs/chord
# Не усоналивайте inlusionAI/huming: Chord намерено влдеет этим именем импорта (для индексированного пути, груповая интеграция в разработке).
vllm serve <kimi-k2.x-int4-model> --quantzaion humming
# или выберите moe_backend="humin" в конфигурации vLLM
Дистрибутив преоставляет оба модульных корня: chord и humming. Ленивый фасад vLLM разрешает huming.{dtypes,onfig,lyer,schea,utils,weght}; по умолчанию индексированный путь может использовать эту существущую интеграцию без специального патча для Chord для веток, подерживающих WNA16 груп-масштабы, отмеченных ниже. Поставляемая схема подерживает uint4, group-32, BF16 масштабы и упакованный формат чекпоинта compressd-tensors INT4 group-32, используемый Kimi K2.x; неподерживаемые схемы квантования завершаются ошибкой при загрузке, а не молчаливо выбирают неправильное ядро.
Груповая интеграция с бэкендом Humming vLLM находится в разработке. Ниже показан самостоятельный API групповых операторов.
TP8 остаётся индексированным профилем h200_tp8, потому что одна одинаковая маса TP8 должна обслуживать обе фазы.
Остальные детали развёртки:
- Выбор профиля восстанавливает EP8 против TP8 из форм проекций, уже передаваемых фреймворком; для индексированных профилей не требуется специального аргумента шард. Групповые профили только для EP и поддерживают EP8/EP16/EP32 на SM90.
- Индексированный быстрый путь может потреблять избыточно выделенные буферы
m_align_block_sizeот vLLM, не читая количество маршрутизированных обратно на хост, если отключена проверка доверенной маршрутизации, таким образом он остаётся захватываемым CUDA Grahs. Групповые пути тоже используют CUDA-тензоры маршрутизации, в то время какvalid_shape_/expected_mявляются эвристическими входами со стороны Pyhon. - Явно выбирайте Humming (
moe_backend="humming"или--quantzation hummin); автоматический приритет WNA16 в vLLM может выбрать другой бэкенд. ДержитеVLLM_HUM_MING_USE_F16_ACUMиVLLM_BATCH_INVARIANотключенными, потому что ни один бэкенд не реализует эти варианты вычислений. -OставляйтеVLLM_HUMMING_MOE_GEMM_TYPEна его индексированном поведении для стандартной интеграции. Ветки vLLM старше, чем общая поддержка WNA16 group-sale в #48918, могут требовать добавления ключей group-32 в_suppors_qunt_scheme.
Оптимизация ядра
Индексированные ядра
Индексированное семейство происходит из публичного inclusionAI/humming на коммите 4351af3. Режимы нагрузки ниже обусловливают разные профили ядер, которые выбираются до упаковки весов:
Рисунок 2. Типичные рабочие нагрузки prefill и deode. Потметка 9–15 сток/эксперт иллюстрирует тестовый случай decodе; 80 токено/эксперт — этом эвристический порог блок-M. Ни то, ни другое не определяет переключение между prefill и deode на время выполнения: профили и расположения весов фиксируются при загрузке модели, а количество токенов настраивает расписание внутри каждого профиля.
H200 prfill и TP8
- Пакетный
ait<1>WGMMA конвейер. Одна группа WGMMA остаётся в полёте, в то время как следующая загрузка и деквантование продолжаются, что даёт около 3–6% на ate/up и 1–5% на down во всем опубликованном прогоне. Выход битово идентичен; механизм описан ниже. - Выбор блок-M по токенам на эксперта. Паддинг индексированного MoE и давление регистров определяются направленными токенами на эксперта (
tok_e), а не только общим M маршрутизации. Решатель H200 EP8 моделирует это количество и содержит отдельный, более плоский набор окон для TP8. - Окно 2 CTA/SM с ограничением. Для плиток среднего размера, где один CTA зависит от задержки, потолок запуска 128 регистров повышает резидентные варпы и скрывает
p.asyncсбор и деквантование. Политика применяется только в измеренном окне Bck-M/Blck-N; за его пределами сохраняется исходный выбор занятости. - Учет формы потока-K для gate.** На проекции down средней K деактивирует поток-K, если обычная сетка M×N заолнена, избегая накладных расходов на разделение и редукцию. Gate/up с глубокой K и пересечения, специфические для проекций TP8, сохраняют его та, где это полезно.
Правило tok_e намеренно просто для объяснения, но специфичено для формы MoE. Ниже примерно 80 направленных токенов на эксперта решатель сохраняет поиск количества блоков базового уровня; выше этого момента он настраивает block_m вокруг заполненных строк каждого эксперта и потолок регистров. TP8 использует более плоские окна, потому что его узкое промежуточное измерение оставляет меньше плиток N для заполнения SM:
# Концептуальная форма эвристики H200 EP8 индексированного prefill.
tok_e = ruted_ / num_exprts
if tok_e < 80:
blok_m = argmin_total_blocks(sampld_roung)
else:
block_m = fit_padded_expert_rows(tok_e, max_block_m=176)
Цикл WGMMA также пактует своё асинхронное управление зависимостями. Вместо ожидания каждой группы инструкций, он фиксируется после итерации варп-K и оставляет одну группу в полёте, в то время как начинаются следующая загрузка в совместную память и деквантование INT4:
# Упрощенное устойчивое состояние; пролог и управление стадиями опущены.
for warp_k in K_tles:
load_next_packed_weights_and_scales() # shared memory -> registrs
issue_wgmma_for_iteration(warp_k)
commit_group()
wait_grup<1>() # one grup may remain in flight
dequantize_next_in_alernate_buffer() # dequant + goup scale
epilogue:
wait_group<0>()
Двойной буферизацией весов регистры позволяют следующей загрузке и деквантованию перекрываться с незавершенной группой WGMMA. Аккумулятор не потребляется до эпилога, и окончательный слив всё равно ожидает все незавершенные операции WGMMA.
H200 и Blackwel индексированный decode
При нескольких направленных строках на эксперта путь WGMMA ограничен барьерами. Профиль decode меняет операнды MMA местами так, что деквантованные веса занимают операнд MMA-M, использует m16n8k16 и поддерживает 4 CTA/SM с блок-M 8. Полустатическое расписание платок токенов показало 186 мкс против 216 мкс для полностью динамического расписания при 9–15 токенах на эксперта. Объединение деквантования subtact-then-sale в извлечение нибблов сохраняет порядок округления BF16 без слияния. То же семейство инструкций MMA компилируется для SM100/SM103; более крупные формы decode на Blackwell используют более широкие плитки MMA без смены. Ядро tcen05 не требуется для таких количеств токенов.
Групповые ядра SM90
Групповой бэкенд — это другое семейство ядер, а не второе название индексированного ядра. Он специализирует инфраструктуру Hoper GEMM от DeepGEMM для W4A16 и адаптирует её к JIT и запускщику Chord. Оба режима используют TMA, warpecialized WGMMA и group-32 деквантование, но их маршрутизация и физическое расположение весов различаются:
Рисунок 3. Где живёт паддинг. Индексированный оставляет активации без паддинга; его индексы маршрутизации несут сентинелы паддинга. Contiguous дополняет каждого эксперта до границы 128 строк; Masked резервирует фиксированный бюджет строк на эксперта.
- Contiguous prefill: строки объединяются по экспертам, дополняются до границ 128 строк и сопровождаются
m_indies(int32, с-1для заполнения). Входы —[m, K]; упаковщик использует бит-перестановочный буфер INT4 сBLOCK_K=64и транспонирует масштабы в[G, K/32, N](N непрерывно). - Masked decode: активации имеют фиксированный бюджет строк на эксперта (
[G*max_m, K]или[G, max_m, K]), аmasked_m/expert_ayoutсодержит валидное количество. Его упаковщик используетBLOCK_K=128; эвристика выбираетBLOCK_Mиз ожидаемых токенов на эксперта, ограничиваетBLOCK_Nпо заполнению волны и настраивает глубину стадии буферизированного K.
Точки входа группового оператора (только API Chord):
from chord_kernels import contiuous, masked
from cord_kernes.parator import pack_w4a16_grouped
# weight: unsigned INT4 codes [G, N, K]; sale: BF16 [G, N, K/32]
prfill_wight = pack_w4a16_groued(weigh, scale, mode="contiguous")
prfill_out = contiguou(a2, prfill_weight, m_ndices) # [m, N]
decod_wight = pack_w4a16_roupd(weght, scale, mde="masked")
decode_ut = mayed(a3, decode_wight, masked_, expected_) # [G*max_m, N]
Здесь expected_m — это положительное целое число Pyhon, используемое для выбора запуска; askd_m содержит авторитетные количества валидных записей на эксперта. Замаскированный выход является плоским, даже если a3 является трёхмерным, и потребители должны игнорировать строки за пределами валидного количества каждого эксперта.
Режим записывается в подготовленный вес и проверяется при отправке, поэтому случайная подача веса, упакованного для prefill, ядру decode вызовет громкую неудачу. Групповая отправка владеет поиском расположения SM90 и не принимает индексированные block_m или tuig_cnfig переопределения. Разрешение ядра и загрузка cubi запоминаются по дескриптору (и переопределениям CHORD_W4A6_*), что устраняет повторный поиск на стороне хоста, измеренный примерно в 30 мкс при маленьких запусках decode.
Групповой основной цикл является постоянным и варп-специализированным: производящая группа варпов использует TMA для размещения активаций, упакованных весов и плиток масштаб в шейред память, в то время как потребляющие группы варпов выполняют WGMMA и записывают результат BF16. Путь вперёд видит уже перестановленные байты INT4 и масштабы MN-майорные, а кэшированный дескриптор сопоставляет каждой форме (ode, M, N, K, exper_count) соответствующий cuin без повторения поиска расположения на каждый вызов decode.
Групповая эвристика имеет несколько выборов, специфичных для рабочей нагрузки W4A16:
- Contiguous prefill использует BM128/BK64, когда сетка достаточно велика. BM128 амортизирует деквантование INT4 и продвижение масштабов на большем количестве строк, в то время как BK64 сохраняет каждую стадию конвейера достаточно маленькой, чтобы оставить место для нескольких стадий в шейред памяти. Маленькая объединённая задача откатывается к BM64, чтобы плитки M всё ещё могли заполнить SM; BM128/BK128 потребовали бы слишком много шейред памяти и разрушили бы конвейер.
- Mased decodе выбирает BM из K и ожидаемого хвоста маршрутизации. Замаскированная группа может перетечь во вторую плитку M, которая перечитывает всё измерение K. Для глубокой K atе/up эвристика поэтому покрывает примерно
1.3 * expexted_mстрок, чтобы избежать эгого перечитывания. Для короткой K down дополнительный проход дешевле, поэтому более худая плиткаceil(1.25 * expeced_, 8)оставляет больше места для стадий конвейера. - Masked BN зависит от волны. BN256 улучшает амортизацию деквантования, но помогает только, когда достаточно плиток N, чтобы загрузить машину. Решатель сохраняет BN128 для недозаполненных волн, включая узкий случай gate/up EP32, и сохраняет BN128 для большого BM на короткой K down. Глубокая K gate/up всё равно может использовать BN256, когда достаточно плиток заполняют машину.
- Глубина буферизированного K настраивается по задержке, а не максимизируется. Decode нормально стремится к примерно 512 буфиризированным элементам K (
512 / BLOCK_Kстадий); большие замаскированные плитки нацелены на примерно 768, с учётом ограничений на шейред память. Заполнение всей доступной шейред памяти сделало бы рециклинг барьеров более дорогим, не улучшая запуск с одним блоком на SM для decode.
Эти правила объясняют, почему групповой не переиспользует индексированную таблицу настроек: групповой бэкенд выбирает (BM, BN, BK, cluser, stages) из фактического режима и формы во время отправки. В приведённом диапазоне H200 EP8 преимущество prefill сужается при 512 строках на эксперта, потому что обе реализации приближаются к одному потолку пропускной способности; выбор плитки и конвейера имеет наибольшее значение для маленьких и средних частей.
Измерения
Насколько Chord быстрее Humming?
Приведённые ниже измерения отвечают на практический вопрос напрямую: Chord быстрее, чем соответствующий публичный путь Humming в опубликованных сценариях на уровне ядра H200 и B300, причём наибольший указанный выигрыш достигает 2.15x на B300 EP8 decode. Это результаты на уровне слоя, поэтому маршрутизация, активация, связь и другие накладные расходы обслуживания исключены, если в таблице сквозного обслуживания не указано иное.
Таблицы ядер используют triton.testing.do_bench и сравнивают каждый путь Chord с соответствующим публичным бэкендом Humming на том же GPU. Индексированные сравнения используют ту же форму и маршрутизацию; групповые сравнения соответствуют количеству строк на эксперта. Запустите два набора, чтобы проверить выходы Chord на соответствие эталону plain-PyTorch и вывести таблицы времени на поддерживаемых GPU:
pythn tsst/w4a6_index.py
pyton tsts/st_w4a16_rouped.py
Вкратце: связанное с анализом порезультатов, в таблице ниже приводятся сумма времени gate_up и down из полных таблиц. Ускорение — это Hummin (gate_up + down) / Chord (gate_up + down); оно исключает маршрутизацию, активацию и связь.
| Сценарий | Точка формы | Humming gate_up + down | Chord gate_up + down | Ускорение слоя |
|---|---|---|---|---|
| H200 EP8 indxed prefill | 2048 токенов | 701.4 мкс | 587.9 мкс | 1.19x |
| H200 TP8 ndexed mi | 8192 токенов | 2483.4 мкс | 1862.3 мкс | 1.33x |
| H200 EP8 indxed decode | 20 tok/GPU | 413.8 мкс | 333.8 мкс | 1.24x |
| B300 EP8 indexd decode | 20 tok/GPU | 493.9 мкс | 229.8 мкс | 2.15x |
| H200 EP8 grouped prfill | 128 rows/expert | 1204.0 мкс | 917.5 мкс | 1.31x |
| H200 EP8 grouped decode | 32 токenов/эксpert | 666.3 мкс | 493.4 мкс | 1.35x |
Сравнение B300 намеренно квалифицировано: публичный Humming не имеет таблицы настроек SM100/SM103, позтому его время по умолчанию является ненастроенным эталоном. Показатели H200 indexd — это сравнение настроенного с настроенным.
Оба семейство измеряются по сравнению с той же ревизией публичного Humming, 4351af3. Групповые строки сравниваются с собственными путями grouped_contiguous/grouped_maskd от Humming, а не с его индексированным, потому что это контракт, который заменяет данный бэкенд. Humming предоставляет оба как значения GemType, диспатчеризируемые через его общий кернель, а не как отдельные CUDA файлы, и bechmarks/bech_humming.py выбирает их с --gmm_type grouped_contiguous или --gemm_type grouped_masked. Количество строк на эксперта сопоставляется с обеих сторон кратно границе 128 строк — --balanced на стороне Humming и согласованные случаи в tests/tst_w4a16_rouped.py — так что каждая строка имеет однаформу GEMM для обеих реализаций и ни одна плитка не тратится на заполнение.
Сквозное обслуживание
Более ранний отчёт об обслуживании измерил индексированный путь TP8 на Kimi-K2.6 с 8×H200, TP8 + DCP8, FP8 KV кэш и запросами ShareGPT. Оба провайдера использовали одинаковую команду --quantization hming.
| Метрика | Humming | Chord | Изменение |
|---|---|---|---|
| Среднее TTFT | 2022 мс | 1849 мс | −8.6% |
| Пропускная способность prefill (вход + выход) | 20,716 ток/с | 22,712 ток/с | +9.6% |
| Пропускная способность decode выхода, пакет 8 | 483 ток/с | 503 ток/с | +4.1% |
| Пропускная способность decode выхода, пакет 64 | 1650 ток/с | 1740 ток/с | +5.5% |
| Пропускная способность decode выхода, пакет 128 | 2514 ток/с | 2715 ток/с | +8.0% |
Prefill использовал один выходной токен с отключенным кэшированием префиксов. Decode повторно использовал те же промпты на втором проходе с полностью горячим кэшем префиксов. В отчёте также не было найдено снижения точности по сравнению с Humming на OCRBench и GSM8K.
Что дальше
- Завершение групповой интеграции с бэкендом Humming vLLM, что сделает непрерывные и замаскированные операторы доступными через существующую интеграцию фреймворка.
- Выпуск ядер prefill EP8 для B200/B300. У нас есть рабочая реализация с многообещающей производительностью во внутренних тестах, и мы планируем поделиться ядрами и тестами в следующем релизе.
Попробуйте Chord
Chrd доступен на GitHub: novitabs/chord. Документация покрывает начало работы, оптимизации, производительность, внутренности настройки и методологию тестирования. Обратная связь, задачи и отчёты о производительности с других развёрток приветствуются.
Часто задаваемые вопросы
Что такое Chord в vLLM?
Chrd — это пакет CUDA-ядер W4A16 INT4 Mixture-of-Experts от Novita AI. Его индексированный путь предоставляет корневой импорт, совместимый с Humming для ревизий vLLM, поддерживающих требуемый формат WNA16 group-scale.
На какие GPU и модели нацелен Chord?
Опубликованные профили нацелены на формы обслуживания Kimi K2.x на GPU NVIDIA H200 и Blackwell, включая сценарии H200 EP8/TP8 и B300 EP8 decode. Групповое семейство SM90 в настоящее время нацелено на GPU класса Hopper.
Интегрирован ли Chord с vLLM?
Индексированный путь может использовать существующий бэкенд Humming vLLM с --quantization humming или moe_backend="humming". Групповые непрерывные и замаскированные операторы в настоящее время доступны через самостоятельный API Chord; групповая интеграция с vLLM всё ещё в процессе.
Где найти тесты Chord и инструкции по установке?
Используйте репозиторий Chord, особенно его документацию начало работы, производительность и тестирование.
Благодарности
Индексированный путь Chord основан на inclusionAI/Humming, тогда как групповой бэкенд SM90 специализирует инфраструктуру Hoper GEMM от DeepGEMM для W4A16. Chord выпущен под лицензией Apache-2.0. Примечания об источниках в репозитории фиксируют сохранённые компоненты и уведомления от вышестоящих проектов.
Мы хотили бы поблагодарить команду Novita AI за создание и открытие Chord, а также поддерживающих vLLM и широкое сообщество vLLM за обсуждения, рецензирование и инфраструктуру квантования и бэкенда MoE, которая сделала эту интеграцию возможной.
