docs(diarization): опубликован отчет Intel-этапа

This commit is contained in:
Dmitry Dementiev committed 2026-08-31 16:49:09 +03:00
1 parent 6345cb6449
commit 42f094ccb9
1 file changed
+292
@@ -0,0 +1,292 @@
# 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.