Files
local-transcriber/docs/benchmarks/2026-08-31-cpu-diarization-intel.md
T

293 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CPU-диаризация: Intel-этап эксперимента
**Дата:** 2026-08-31
**Статус:** `handoff`; в Ryzen-этап передается один кандидат. Production-профиль не менялся.
## Итог
На Intel Core i7-6820HQ пройдены этапы 0-4 эксперимента из
[спецификации](../specs/2026-08-30-cpu-diarization-experiment.md). Для Ryzen
передается комбинация C2:
- `window_shift_ratio=0.1`;
- Pyannote Segmentation 3.0 FP32;
- WeSpeaker ResNet34 LM FP32;
- текущий `FastClustering` с порогом `0.89`;
- два outer worker, одна общая ONNX Runtime session, общий пул из четырех
intra-op потоков, `inter_op_threads=1`.
C2 сохранила результат baseline по всем обязательным и диагностическим
показателям: `3 / 2 / 2` кластера, та же последовательность слов, те же числа
слов без говорящего `51 / 13 / 9` и та же `mapped speaker purity`. Один прогон
трех фрагментов занял 140,632 с против 146,978 с у соседнего baseline:
ускорение 4,32%. Пиковый RSS вырос с 376,4 до 406,0 МиБ. Порог продолжения на
Intel не достигнут. Разница неотличима от наблюдаемого разброса
одиночных запусков: контрольные baseline в разных сериях лежали в диапазоне
146,978-157,892 с, то есть шире, чем разница между W0 и C2.
Спецификация при этом разрешает передать работоспособный механизм shared-session
как аппаратного кандидата для отдельного A/B на Ryzen. Результат 4,32% остается
диагностическим наблюдением; оценивать по нему ожидаемое ускорение нельзя.
CAMPPlus + NME оказался самым быстрым вариантом: C1 заняла 98,347 с и
сохранила `3 / 2 / 2`. Но на одной записи число слов без говорящего
выросло с 51 до 53. Для такого изменения спецификация требует слуховой проверки
отмеченных мест до сборки комбинации. Материал для нее подготовлен, но в этом
окружении прослушивание недоступно. Поэтому C1 измерена и описана, но в handoff
не включена.
## Зачем понадобился sherpa-onnx 1.13.6
Версия стенда поднята с `1.13.5` до `1.13.6`. В ней публичная Python-конфигурация
сегментации получила `window_shift_ratio`, необходимый для этапа W0-W4. Свежий
контрольный прогон обеих версий дал одинаковые `3 / 2 / 2` кластера, числа слов
без говорящего `51 / 13 / 9` и purity `0,76655 / 0,78742`. Каноническая сверка
интервалов и назначения говорящих словам вынесена в отдельную проверку по сырым
результатам капсулы; расхождений, требующих прослушивания, не обнаружено. Время
одного прогона составило 190,104 с для `1.13.5` и 157,892 с для `1.13.6`; это
диагностическое сравнение без повторов, а не самостоятельное доказательство
ускорения версии.
Экспериментальные `Prepare/Finalize` и общий worker API в `1.13.6` отсутствуют.
Их нет и в проверенном актуальном upstream `master` sherpa-onnx от 2026-08-31.
Для эксперимента собран локальный патч и wheel:
| Артефакт | SHA-256 |
|---|---|
| Патч sherpa-onnx 1.13.6 | `5f12df858cd525c8a0cfe8ff95b647c3b0e915a13d45621acc4ac42660014c49` |
| Wheel CPython 3.13, Linux x86_64 | `306499d8668ee138357f1de43a5c1c88f4dc46c845e8a92e6ad945327bcaa050` |
Проверка патча на реальной модели подтвердила, что worker владеет подготовленным
состоянием. Копирование матрицы и одноразовая финализация работают корректно;
штатный `process()` точно совпадает с цепочкой
`Prepare -> cluster(copy) -> Finalize`. Один и два worker дали одинаковые
строки, метки и итоговые интервалы без пропусков и дублей.
## Условия
- Intel Core i7-6820HQ, 4 физических ядра / 8 логических процессоров;
- 32 181 526 528 байт RAM, x86_64, AVX2; VNNI и AVX-512 отсутствуют;
- Linux 7.0.0-30-generic, Python 3.13.13;
- `sherpa-onnx` 1.13.6, ONNX Runtime 1.28.0, NumPy 2.4.3;
- питание от сети, системный профиль `balanced`, governor `powersave`, turbo
включен;
- первая попытка финального W0 отбракована из-за swap-in; повторная попытка W0
и первая попытка C2 прошли runtime guard. В принятых попытках W0 нагрел CPU
с 80 до 85 C, C2 - с 80 до 82 C; power limits, throttle count и swap I/O
не изменились;
- три контрольных фрагмента по 300 с, ожидаемые кластеры `3 / 2 / 2`;
- один запуск каждой исследовательской ячейки и одна соседняя пара W0/C2 под
runtime guard; ASR-sidecar подготовлены заранее и во время ячейки не учитывались.
Измеряемый интервал включает полную диаризацию фрагмента. Для E3 отдельно
помечена составная оценка, потому что независимые session измерялись на заранее
подготовленных заданиях.
## Идентификаторы прогона
- source commit: `6345cb6449d906767b6ed33e695f2ca4eeaf3008`;
- experiment ID: `457dffbb690516a2b38ee1331a3939664ada3a0c4ade638eab6b7c5270b17f4e`;
- capsule ID: `intel-41-5de5f454`;
- SHA-256 scheduler output:
`14c5aa1d3131f9bd324c77d4c3bf315772e6374835f28863c5db45fc27ab5ce5`.
Manifest оставляет исследовательские ячейки в матрице как уже измеренные и
выключенные, а через scheduler повторяет только финальную соседнюю пару:
| Ячейка | Позиция | Cell ID | Статус в финальном плане |
|---|---:|---|---|
| W0 | 1 | `68360310692540e5df2640e3d653c12b91c6acaedfae56170e6ce74ecea12af2` | сырой результат сохранен |
| W1 | 2 | `e170c9a1808c8e1c6c824381dca39495740ba2526725c280e7a9aed115bc7a36` | сырой результат сохранен |
| W2 | 3 | `8e4283a6ae8bae62e7397e83870afd1d0706816e1e123c012d2b3ae795f4c7d4` | сырой результат сохранен |
| W3 | 4 | `46d81148e1c3eca15e6f8c1eacce41556db90a5e07429acf1ba4292103996845` | сырой результат сохранен |
| W4 | 5 | `eab104a305dc192847c16786de6cfa81f9a90bb9a80dc91627d439af4eb5d39d` | сырой результат сохранен |
| M0 | 10 | `206a1a7821cb29dfe86d19e45ff665ac6f143aad3a1b79419987162097973208` | сырой результат сохранен |
| M2 | 11 | `17559e0b25df2ca77a25d93b2238e9a726ac2ab123d11ec6ddcb9de51b298e9c` | сырой результат сохранен |
| M3 | 12 | `c5a5d9eb45172caeb5a4d476463f0a783d6337312aab6ef7177f2a6dfcca53d2` | сырой результат сохранен |
| Q0 | 20 | `386b2b9ba686466bf4603dda51222e7cdd6324061a68babed339db3e8e6a09dc` | сырой результат сохранен |
| Q1 | 21 | `e1cee039ce5c65ea91004df99eaefff50b02ce1c40a8f53eba34a234522a0e3f` | сырой результат сохранен |
| E1 | 30 | `4175101fcb0abbc6f4f46caa87273c431ce5fab61620493b13df4ed18f05f29d` | сырой результат сохранен |
| E0 для E1 | 31 | `9f59ab52ffd188da28f94233f13a19a297568e7c1e754c2a9e09157bca10ad85` | сырой результат сохранен |
| E0 для E2 | 32 | `c349a249896faeddc06356fd671ff2505bc2a89075ea7b2407964d6afae90232` | сырой результат сохранен |
| E2 | 33 | `1aba4e138f3cdfd675cf411b485cfd5a01c3166d4ae893a779d88c75fa1f53c2` | сырой результат сохранен |
| E3 | 34 | `6d2af928e2270eea37735ab39314b050fd520911cc07ba2303016ab657dd610a` | сырой результат сохранен |
| E0 для E3 | 35 | `c55eac6d19ea7741debb02a1b602782dc0332bafe72323ea54651845416d4b6f` | сырой результат сохранен |
| C1 | 40 | `3898cd41f6dc7d50bed245bfa6ec945c700a7fad67ac3f2e7f950d864a9ac9de` | исключена |
| W0 для C2 | 50 | `44a6ce169f9566088376b0f6139f6823783baff481edd8741e39690534c6c47d` | выполнена, baseline |
| C2 | 51 | `90ad304d332efa4742490f3a4a40cfb7e3422dfa85a22fbf254c7f4900b4a51f` | выполнена, handoff |
TitaNet batch 1/4 остался отдельным mechanism smoke и в финальную A/B-матрицу
не входит.
## Этап 0: механизмы
`Prepare/Finalize`, общий worker и строгая схема manifest v3 прошли smoke-тесты.
Для CAMPPlus и TitaNet на одних и тех же подготовленных матрицах сравнивались
eigengap и NME:
| Модель | Строки матриц | Eigengap, N | NME, N | Выбор |
|---|---|---|---|---|
| CAMPPlus | `531 / 414 / 440` | `6 / 1 / 7` | `3 / 2 / 2` | NME |
| TitaNet small | `531 / 414 / 440` | `7 / 2 / 4` | `3 / 2 / 2` | NME |
Ни одна матрица не потеряла строки. Повторный запуск счетчика и штатная
финализация дали одинаковые параметры и метки.
WeSpeaker S8S8 QDQ построен на 48 интервалах отдельной записи. Manifest хранит
исходный SHA-256 и точный интервал каждого элемента. Граф сохранил интерфейс,
opset и метаданные, прошел ONNX checker, динамические входные длины в ONNX
Runtime и загрузку через sherpa-onnx. SHA-256 графа:
`9a3f8ae64d1083b64a6276f1e1138b17b7511a9a8d731b632945efc84098588b`.
## Этап 1: шаг окна
| Ячейка | Шаг | Время, с | Кластеры | Качество | Решение |
|---|---:|---:|---|:---:|---|
| W0 | 0,10 | 148,220 | `3 / 2 / 2` | да | baseline |
| W1 | 0,15 | 100,799 | `2 / 2 / 2` | нет | исключен |
| W2 | 0,20 | 76,127 | `2 / 2 / 2` | нет | исключен |
| W3 | 0,25 | 61,369 | `2 / 2 / 2` | нет | исключен |
| W4 | 0,50 | 31,291 | `1 / 2 / 2` | нет | исключен |
Сокращение числа окон объясняет ускорение, но все увеличенные шаги потеряли
кластер на первой записи. Рабочим остался `0.1`; C0 совпал бы с baseline и
поэтому не запускался.
## Этапы 2-3: модели и исполнение
| Ветвь | Время, с | Изменение к W0 | Пиковый RSS, МиБ | Кластеры | Решение |
|---|---:|---:|---:|---|---|
| M2, CAMPPlus + NME | 94,550 | -36,21% | 358,6 | `3 / 2 / 2` | самая быстрая; нужна слуховая проверка |
| M3, TitaNet + NME | 107,205 | -27,67% | 511,9 | `3 / 2 / 2` | прошел, но слабее M2 |
| QDQ WeSpeaker | 177,537 | +19,78% | 367,7 | `2 / 2 / 2` | исключен по качеству |
| E1, shared 2 x pool 4 | 139,219 | -6,07% | 398,6 | `3 / 2 / 2` | допущен как аппаратный кандидат |
| E2, shared 4 x 1 | 152,167 | +2,66% | 551,2 | `3 / 2 / 2` | исключен по времени и памяти |
| E3, 4 отдельные session | 159,038 | +7,30% | 732,3 | `3 / 2 / 2` | отрицательный контроль |
Время E3 - составная оценка, а не прямое время штатного `process()`. RSS E3 -
максимум всего проверочного процесса: он включает штатную подготовку,
экспериментальные эмбеддинги и контрольную финализацию. Отдельный RSS только
embedding-этапа не измерялся. Даже эта завышенная оценка, включающая соседние
этапы, подтверждает ожидаемый рост памяти с числом session, поэтому E3 не стал
кандидатом.
У E1 и E2 метки, итоговые интервалы и диагностические показатели побайтово
совпали с последовательным вариантом. E1 выбран для C2 как более быстрый и
экономный режим.
TitaNet batch 1 воспроизвел штатные эмбеддинги с максимальным абсолютным
расхождением не больше `3,4e-6`. Batch 4 сохранил `3 / 2 / 2`, но поменял метки
строк на всех трех матрицах, дал дрейф эмбеддингов `0,277-0,317` и оказался
медленнее batch 1. Ветвь остановлена до CPU-ячейки.
## Этап 4: комбинации
| Комбинация | Рецепт | Время, с | Ускорение | RSS, МиБ | Диагностика | Handoff |
|---|---|---:|---:|---:|---|:---:|
| C1 | `0.1` + CAMPPlus + NME + sequential | 98,347 | 33,65% | 399,5 | purity выросла; `+2` слова без говорящего | нет |
| C2 | `0.1` + WeSpeaker FP32 + shared 2 x pool 4 | 140,632 | 4,32% | 406,0 | точное совпадение с W0 | да |
Процент C1 посчитан относительно одиночного W0 из этапа окна, 148,220 с; это не
соседняя A/B-пара. Процент C2 посчитан относительно соседнего W0 под runtime
guard, 146,978 с.
У C1 `mapped speaker purity` выросла с `0,76655 / 0,78742` до
`0,80137 / 0,91079`. Слова без говорящего изменились с `51 / 13 / 9` на
`53 / 13 / 9`. Без слухового решения это не считается пройденной диагностикой.
## Закрепленные модели
| Идентификатор | SHA-256 |
|---|---|
| Pyannote FP32 | `220ad67ca923bef2fa91f2390c786097bf305bceb5e261d4af67b38e938e1079` |
| WeSpeaker FP32 | `e9848563da86f263117134dfd7ad63c92355b37de492b55e325400c9d9c39012` |
| WeSpeaker S8S8 QDQ | `9a3f8ae64d1083b64a6276f1e1138b17b7511a9a8d731b632945efc84098588b` |
| CAMPPlus | `aa3cfc16963a10586a9393f5035d6d6b57e98d358b347f80c2a30bf4f00ceba2` |
| TitaNet small | `ad4a1802485d8b34c722d2a9d04249662f2ece5d28a7a039063ca22f515a789e` |
## Индекс публичных доказательств
Хеши ниже связывают обезличенные агрегаты с сырыми файлами приватной капсулы,
не публикуя пути, текст или интервалы.
| Результат | SHA-256 | Окна по записям | Embedding-задания по записям |
|---|---|---|---|
| fresh 1.13.5 | `c53c1f970ee4db094779bc32b42f978c37c2cb74d814504ccfac87f09e802ddd` | `291 / 291 / 291` | `531 / 414 / 440` |
| fresh 1.13.6 | `eb7e3d508836e1eefd679a851271eaa6823d688fef39d2ae03978e7fa7006bba` | `291 / 291 / 291` | `531 / 414 / 440` |
| W0 | `32d513cd0e81fdca0e37484f86b5c4312d3573608493972a282302dd891cdf0e` | `291 / 291 / 291` | `531 / 414 / 440` |
| W1 | `be8935b5a81e2aadaeb38540e615c0cd3ae5ac31d6e0949856fd7d16d31a78ea` | `195 / 195 / 195` | `357 / 274 / 302` |
| W2 | `f95433d516772d40c4071da0d0745b981314ee7a7063fb4a43518e94bc17848e` | `146 / 146 / 146` | `264 / 206 / 222` |
| W3 | `14cac4f1d8cd38ed5b4a20189438d2b1e109ba267c5feaa36f0928fbec848580` | `117 / 117 / 117` | `211 / 165 / 175` |
| W4 | `6fafefce00e90590ab2d834fb560413cd7780e20cbd1f631d9954ec8b97a540e` | `59 / 59 / 59` | `105 / 82 / 89` |
| M2, исправленный интервал | `3debc8ae5cf1bd13d806dbfe8e4cfa137d6705622a721f4a42f1a22c030ec277` | `291 / 291 / 291` | `531 / 414 / 440` |
| M3, исправленный интервал | `531a842234e35e29f582ff8a51406fb9dd6211e017b3162d80cca21d4732d316` | `291 / 291 / 291` | `531 / 414 / 440` |
| E1, исправленный интервал | `f5ac41d29eeff1f7cfbb93497a0025aef40de0838e933e0f9baed30a236d6b85` | `291 / 291 / 291` | `531 / 414 / 440` |
| E2, исправленный интервал | `f2664d354ede1e4bf2c42b974513cdc845ff601c73f30ebae51456764fd8dcdc` | `291 / 291 / 291` | `531 / 414 / 440` |
| C1, исправленный интервал | `4f96e6f7363e0edb79d4034a07f4d3b6b0003a820fcf6bceff5426bb3c2caff4` | `291 / 291 / 291` | `531 / 414 / 440` |
| W0 для C2, canonical result | `e572dd057ec87514aca4617465c48ce361677ae19279efcadbbde404afc85b5d` | `291 / 291 / 291` | `531 / 414 / 440` |
| C2, canonical result | `d687074cc582e2ac379ed3375362f9480778feca02c7492a4c4be4fcc1a4f15a` | `291 / 291 / 291` | `531 / 414 / 440` |
Для W0 под runtime guard суммарное user/system CPU time равно
`584,590 / 0,590` с,
средний RTF по трем записям - `0,16331`. Для C1 эти значения равны
`406,230 / 1,050` с и `0,10927`; для C2 под runtime guard -
`667,580 / 0,960` с и
`0,15626`. У C2 повышенное CPU time отражает конкурентную работу двух stream,
а решение принимается по wall time.
Контрольные входы закреплены отдельно от результатов:
| Запись | SHA-256 media | SHA-256 ASR-sidecar | SHA-256 reference |
|---|---|---|---|
| control 1 | `1057616b42e8add00e0eb975b02bdef0ec9f6cdfec6dbf488e0c60423c9b7b87` | `3e190c060b2a9b0f4145249702d66b28c26e9b8518462000d368b431e22902bb` | - |
| control 2 | `51866d247fe3eda134cdd884f707b1f1db8855b492e8bd14d2b56b62476255ed` | `f8ce6e25d0ce7999b2d3c31c7ca9fc5f721b8925334362729eed06552296bdb5` | `9098548743a86f868dfcdd906bcde34ed1ce5a935602cbe399f4bceda8685b3c` |
| control 3 | `4422f04e2771091a0648e5422d14a31dd7ca2c8eef7ed9f4a5c63f43d8ca6400` | `eca10e7b232a211ce53decfc1a449c8ce2ae482dd7bc67c7aa9a267b12a2582d` | `dc2db5925c98ea7029bf52ad9cd7cc332d0084b91118a3d58336058f619d3d9a` |
Для CAMPPlus NME выбрал `p=111 / 54 / 104`; время счетчика составило
`3,536 / 1,488 / 1,148` с. Для TitaNet - `p=90 / 65 / 110` и
`1,084 / 0,780 / 1,112` с. Все шесть результатов дали ожидаемое N,
повторяемые метки и ноль потерянных строк.
## Воспроизведение на Ryzen
После проверки commit и внешнего SHA-256 приватной капсулы:
```bash
uv sync --frozen
uv pip install --python .venv/bin/python --reinstall \
/path/to/capsule/build/sherpa_onnx-1.13.6-cp313-cp313-linux_x86_64.whl
export LOCAL_TRANSCRIBER_EXPERIMENT_BUILD_SHA256=\
306499d8668ee138357f1de43a5c1c88f4dc46c845e8a92e6ad945327bcaa050
uv run python scripts/benchmarks/diarization_calibration.py \
--capsule /path/to/original-capsule.zip \
--capsule-sha256 CAPSULE_SHA256_FROM_HANDOFF \
--manifest /path/to/capsule/manifest.json \
--validate-only
```
`--validate-only` должен вернуть schema v3, этап `intel`, пустой список
предупреждений и `qdq_available=true`. Затем Ryzen-агент создает свой manifest
этапа `ryzen`, указывает Intel commit как `handoff_commit` и выполняет
изолированный E1 A/B перед первичным A/B C2. Экспериментальный wheel совместим
только с CPython 3.13 на Linux x86_64; на другой платформе его нужно пересобрать
из патча с тем же SHA-256.
Приватная капсула содержит manifest, исходные записи, ASR-sidecar, опорную
разметку, калибровочные данные, созданные модельные артефакты, сырые результаты,
worker requests и журналы. Эти файлы не входят в Git и не передаются внешним
ревьюерам.
## Ограничения
- У каждой ячейки один прогон. Проценты не оценивают дисперсию, прогрев и
температурный дрейф.
- Ранние ячейки запускались не чередующимися парами, поэтому полного A/B не
образуют. Финальные механизмы на Ryzen следует проверять только чередующимися
парами из спецификации.
- Сравнение sherpa-onnx 1.13.5 и 1.13.6 показывает равенство качества, но разницу
времени нельзя приписывать одной версии без повторов.
- C1 нельзя возвращать в матрицу без слуховой проверки подготовленных мест.
- Полные записи и приемка пяти слуховых категорий относятся к Ryzen-этапу после
выбора финалиста.
- Вывод относится к одному Intel Core i7-6820HQ без VNNI/AVX-512. Результаты
QDQ и shared-session нельзя переносить на Ryzen без собственного A/B.