- Зачем: - локальные оптимизации каскада не достигли 30%-го порога ускорения; - старые закрытые хранилища и капсулы не должны стать будущей зависимостью. - Что: - собран единый реестр результатов задач #41 и #42; - опубликовано разложение Ryzen baseline и выбрана архитектурная гипотеза; - подготовлены самодостаточная спецификация и ready-for-agent задача #46. - Проверка: - пройдены self-review и две независимые линии ревью; - проверены 44 строки реестра, 42 арифметических инварианта и ссылки; - выполнены ai-text-lint, privacy scan и post-lint guard. Refs: #45
437 lines
52 KiB
Markdown
437 lines
52 KiB
Markdown
# Карта end-to-end архитектур CPU-диаризации
|
||
|
||
**Дата:** 2026-09-01
|
||
|
||
**Статус:** выбран один кандидат для свежего минимального A/B - Streaming
|
||
Sortformer 4spk v2 Q8_0 через закрепленный NeMo-Speech.cpp. Это единственная
|
||
ветвь, где полная замена каскада опирается на готовые Q8_0 веса и закрепляемый
|
||
локальный CPU runtime. Production-профиль, CLI, конфигурационный контракт и
|
||
модель по умолчанию не меняются.
|
||
|
||
Документ сохраняет обезличенные агрегаты задач #41 и #42, потому что после
|
||
удаления закрытых хранилищ их нельзя будет получить повторно без нового
|
||
вычисления. Здесь нет локальных путей, идентификаторов записей, текста,
|
||
временных интервалов, manifest-содержимого или сырых строк результата.
|
||
Непрозрачные SHA-256 уже опубликованных результатов оставлены как устойчивые
|
||
ссылки на исторические байты. Они не создают будущую зависимость от этих байтов.
|
||
|
||
## Источники реестра
|
||
|
||
- [Intel-отчет](../benchmarks/2026-08-31-cpu-diarization-intel.md);
|
||
- [Ryzen-отчет](../benchmarks/2026-08-31-cpu-diarization-ryzen.md);
|
||
- [спецификация прежнего эксперимента](../specs/2026-08-30-cpu-diarization-experiment.md);
|
||
- [ADR-007](../adr/007-word-level-speaker-diarization.md).
|
||
|
||
## Как читать реестр
|
||
|
||
`Ускорение` ниже означает сокращение wall time:
|
||
|
||
`100 x (wall_baseline - wall_candidate) / wall_baseline`.
|
||
|
||
Отрицательное значение означает замедление. Intel W/M/Q/E - одиночные
|
||
разведочные прогоны трех 300-секундных фрагментов, если явно не указана соседняя
|
||
пара. Ryzen-строки - принятые соседние A/B. ASR, загрузка моделей и декодирование
|
||
не входят в wall.
|
||
|
||
Обязательный автоматический gate: `3 / 2 / 2` голосовых кластера, неизменный
|
||
текст, повторяемые параметры/метки/финализация, конечные эмбеддинги и отсутствие
|
||
потерянных или продублированных входов. `51 / 13 / 9` слов без говорящего и
|
||
`mapped speaker purity = 0,76655 / 0,78742` - диагностика совпадающего baseline,
|
||
а не ручная истина. Рост диагностического показателя требует прослушивания, но
|
||
сам по себе не превращает вариант в проигравший.
|
||
|
||
## Переносимые рецепты
|
||
|
||
Все Intel-рецепты используют четыре физических ядра; Ryzen-рецепты - восемь.
|
||
Везде `inter_op_threads=1`, batch 1, если строка не говорит обратного.
|
||
Код измерительного стенда закреплен source commit
|
||
`6345cb6449d906767b6ed33e695f2ca4eeaf3008`; sherpa-onnx 1.13.6 - upstream
|
||
commit `1cb484af9b1ab05cc36f89e03dd7d76322f2e911` плюс опубликованный ниже патч.
|
||
Последовательные W0-рецепты используют CPU provider для segmentation и
|
||
embeddings, `debug=True` для обеих конфигураций,
|
||
`min_duration_on=0.3` и `min_duration_off=0.5`. Debug-режим входит в
|
||
измерительный рецепт: из его журнала получены native stage times.
|
||
|
||
| Recipe ID | Точный переносимый рецепт |
|
||
|---|---|
|
||
| `I-B135` | `sherpa-onnx/core 1.13.5`; Pyannote Segmentation 3.0 FP32; WeSpeaker ResNet34 LM FP32; `window_shift_ratio=0.1`; последовательный инференс; один worker/session; `intra_op=4`; `FastClustering`, auto-N, threshold `0.89`. |
|
||
| `I-B136` / `I-W0` / `I-M0` / `I-Q0` / `I-E0` / `I-C0` | Тот же профиль, но `sherpa-onnx/core 1.13.6`; это совпадающий Intel baseline. |
|
||
| `I-W(r)` | `I-B136`, меняется только `window_shift_ratio=r`. |
|
||
| `I-M2` / `I-C1` | `I-B136`, но CAMPPlus вместо WeSpeaker; NME автоматически выбрал `p=111/54/104`, затем N=`3/2/2` и `FastClustering(N)`; sequential. |
|
||
| `I-M3` | `I-B136`, но TitaNet small вместо WeSpeaker; NME автоматически выбрал `p=90/65/110`, затем N=`3/2/2` и `FastClustering(N)`; sequential. |
|
||
| `I-Q1` | `I-B136`, но WeSpeaker S8S8 QDQ вместо FP32; sequential. |
|
||
| `I-E1` / `I-C2` | `I-B136`, но два outer worker используют одну shared ONNX Runtime session и общий `intra_op=4`. |
|
||
| `I-E2` | `I-B136`, но четыре outer worker, одна shared session, `intra_op=1`. |
|
||
| `I-E3` | `I-B136`, но четыре outer worker и четыре отдельные session, у каждой `intra_op=1`; отрицательный контроль. |
|
||
| `R-B` | `sherpa-onnx/core 1.13.6`; Pyannote FP32; WeSpeaker FP32; shift `0.1`; `FastClustering(auto, 0.89)`; sequential; один worker/session; `intra_op=8`. |
|
||
| `R-C2` | `R-B`, но два outer worker, одна shared session, общий `intra_op=8`. |
|
||
|
||
Закрепленные SHA-256 моделей: Pyannote FP32
|
||
`220ad67ca923bef2fa91f2390c786097bf305bceb5e261d4af67b38e938e1079`,
|
||
WeSpeaker FP32
|
||
`e9848563da86f263117134dfd7ad63c92355b37de492b55e325400c9d9c39012`,
|
||
WeSpeaker QDQ
|
||
`9a3f8ae64d1083b64a6276f1e1138b17b7511a9a8d731b632945efc84098588b`,
|
||
CAMPPlus
|
||
`aa3cfc16963a10586a9393f5035d6d6b57e98d358b347f80c2a30bf4f00ceba2`,
|
||
TitaNet small
|
||
`ad4a1802485d8b34c722d2a9d04249662f2ece5d28a7a039063ca22f515a789e`.
|
||
Экспериментальные `Prepare/Finalize` и shared worker требовали патч
|
||
`5f12df858cd525c8a0cfe8ff95b647c3b0e915a13d45621acc4ac42660014c49`:
|
||
API не было ни в 1.13.6, ни в проверенном upstream master. Ryzen-wheel был
|
||
пересобран из того же upstream commit и патча из-за несовместимости GLIBC;
|
||
его опубликованный SHA-256 -
|
||
`baaaa2532606f1e1411e5c84655afa70107ad4b1676420953f5e67233c46a484`.
|
||
|
||
## Реестр: baselines и проверки механизмов
|
||
|
||
| Stable ID | Recipe / измененная ось | Машина / стадия | Wall / ускорение / RSS | Обязательное качество | Решение и точная причина | Публичное доказательство |
|
||
|---|---|---|---|---|---|---|
|
||
| `41-V135` | `I-B135`; version baseline | Intel / version baseline | `190,104 с`; baseline; `365,7 МиБ` в соответствующем сыром агрегате | `3/2/2`, текст и диагностика baseline | Принят как контроль версии; одиночный запуск не доказывает причинное ускорение/замедление версии | `docs/benchmarks/2026-08-31-cpu-diarization-intel.md`, "Зачем понадобился 1.13.6" |
|
||
| `41-V136` | `I-B136`; меняется только runtime 1.13.5->1.13.6 | Intel / version baseline | `157,892 с`; `+16,94%` к `41-V135`; `356,7 МиБ` | `3/2/2`; канонические интервалы, назначения слов и диагностика совпали | Baseline 1.13.6 принят; разница времени диагностическая, без повторов | тот же раздел; SHA `eb7e3d508836e1eefd679a851271eaa6823d688fef39d2ae03978e7fa7006bba` |
|
||
| `41-S-WINDOW` | 1.13.6 принимает shift `0.10/0.15/0.20/0.25/0.50`; `0.10` сохраняет поведение | Intel / smoke | end-to-end wall/RSS: not measured | Smoke пройден | Допустить W0-W4 | `docs/specs/2026-08-30-cpu-diarization-experiment.md`, этап 0 |
|
||
| `41-S-PF` | Локальный `Prepare -> cluster(copy) -> Finalize` против штатного `process()` | Intel / smoke | wall/ускорение/RSS: not measured | Строки, метки и интервалы совпали; пропусков/дублей нет | Использовать патч в стенде | Intel-отчет, этап 0 |
|
||
| `41-S-MANIFEST` | Строгая schema v3 и стабильные ID ячеек | Intel / smoke | не применимо | Валидация капсулы: 199 файлов, QDQ доступен, предупреждений нет | Использовать; это механизм воспроизводимости, не измерительная ячейка | Ryzen-отчет, handoff |
|
||
| `41-S-CEIG` | CAMPPlus prepared-матрицы; eigengap | Intel / counter smoke | counter wall по трем матрицам `0,107 / 1,575 / 0,067 с`; end-to-end ускорение/RSS: not measured | N=`6/1/7`, не `3/2/2` | Исключить счетчик для CAMPPlus: обязательный count gate провален | Новый aggregate задачи #45 из frozen raw; previous result SHA not published |
|
||
| `41-S-CNME` | Те же CAMPPlus-матрицы; NME + `FastClustering(N)` | Intel / counter smoke | counter wall `3,536 / 1,488 / 1,148 с`; end-to-end ускорение/RSS: not measured | N=`3/2/2`, повторяемые метки, 0 потерянных строк | Выбрать для M2/C1 | Intel-отчет, индекс доказательств |
|
||
| `41-S-TEIG` | TitaNet prepared-матрицы; eigengap | Intel / counter smoke | counter wall `0,126 / 0,073 / 0,101 с`; end-to-end ускорение/RSS: not measured | N=`7/2/4`, не `3/2/2` | Исключить счетчик для TitaNet: count gate провален | Новый aggregate задачи #45 из frozen raw; previous result SHA not published |
|
||
| `41-S-TNME` | Те же TitaNet-матрицы; NME + `FastClustering(N)` | Intel / counter smoke | counter wall `1,084 / 0,780 / 1,112 с`; end-to-end ускорение/RSS: not measured | N=`3/2/2`, повторяемые метки, 0 потерянных строк | Выбрать для M3 | Intel-отчет, индекс доказательств |
|
||
| `41-S-QDQ` | WeSpeaker S8S8 QDQ, 48 независимых calibration-интервалов | Intel / artifact smoke | wall/ускорение/RSS: not measured | interface/opset/metadata, checker, dynamic shapes и загрузка sherpa пройдены | Допустить Q1; техническая корректность не означает качество/скорость | Intel-отчет, этап 0; model SHA выше |
|
||
| `41-S-SHARED` | Один и два worker, одна session, одинаковые prepared-входы | Intel / worker smoke | wall/ускорение/RSS: not measured | строки, метки и интервалы совпали; гонок/NaN/потерь нет | Допустить E1/E2 | Ryzen-отчет, этап 0 |
|
||
| `41-S-TB1` | TitaNet batch 1 | Intel / embedding smoke | embedding-only `75,923 с` суммарно; ускорение/RSS: not measured | штатные эмбеддинги воспроизведены, max abs drift <= `3,4e-6` | Контроль batch | Ryzen-отчет, этап 3; batch SHA `f12bfdb5cadf80c62871c0725eac744a99825cb5d06b70fcf11e4e538ff6df72` |
|
||
| `41-S-TB4` | TitaNet batch 4 | Intel / embedding smoke | embedding-only `98,596 с`, на `29,86%` медленнее batch 1; RSS: not measured | `3/2/2`, но метки всех трех матриц изменились; drift `0,277-0,317` | Остановить до CPU-ячейки: медленнее и нарушена идентичность меток | Ryzen-отчет, этап 3; тот же batch SHA |
|
||
|
||
Counter wall в строках `41-S-CEIG` и `41-S-TEIG` впервые опубликован в задаче
|
||
#45 как безопасный aggregate frozen raw evidence. Прежний result SHA не был
|
||
опубликован; после удаления хранилища эти числа нельзя повторно сверить с
|
||
исходными байтами.
|
||
|
||
Примечание к `41-V135`: публичный Intel-индекс печатает SHA
|
||
`c53c1f970ee4db094779bc32b42f978c37c2cb74d814504ccfac87f09e802ddd`,
|
||
но этот хеш связывает другой сырой агрегат (`148,806 с`), а не опубликованные
|
||
`190,104 с`. Сырой результат с `190,104 с` имеет неопубликованный хеш. Поэтому
|
||
для этой строки устойчивым публичным доказательством остается только якорь
|
||
публичного отчета; после удаления хранилища байтовая проверка числа невозможна.
|
||
|
||
## Реестр: Intel W/M/Q/E/C
|
||
|
||
| Stable ID | Recipe / измененная ось | Wall / ускорение / RSS | Обязательное качество и диагностика | Решение и точная причина | Публичное доказательство |
|
||
|---|---|---|---|---|---|
|
||
| `41-W0` | `I-W(0.10)`, совпадающий baseline | `148,220 с`; baseline; `361,2 МиБ` в том же raw result | pass `3/2/2`; слова без говорящего `51/13/9` | Принять shift `0.10` | SHA `32d513cd0e81fdca0e37484f86b5c4312d3573608493972a282302dd891cdf0e` |
|
||
| `41-W1` | `I-W(0.15)`; меняется только shift | `100,799 с`; `+31,99%`; `362,6 МиБ` | fail `2/2/2`; `50/17/9` | Исключить: потерян кластер на первом фрагменте | SHA `be8935b5a81e2aadaeb38540e615c0cd3ae5ac31d6e0949856fd7d16d31a78ea` |
|
||
| `41-W2` | `I-W(0.20)` | `76,127 с`; `+48,64%`; `363,6 МиБ` | fail `2/2/2`; `52/13/9` | Исключить: потерян кластер | SHA `f95433d516772d40c4071da0d0745b981314ee7a7063fb4a43518e94bc17848e` |
|
||
| `41-W3` | `I-W(0.25)` | `61,369 с`; `+58,60%`; `358,4 МиБ` | fail `2/2/2`; `59/16/11` | Исключить: потерян кластер | SHA `14cac4f1d8cd38ed5b4a20189438d2b1e109ba267c5feaa36f0928fbec848580` |
|
||
| `41-W4` | `I-W(0.50)` | `31,291 с`; `+78,89%`; `360,7 МиБ` | fail `1/2/2`; `0/19/10` | Исключить: потеряны два кластера суммарно относительно `3/2/2` | SHA `6fafefce00e90590ab2d834fb560413cd7780e20cbd1f631d9954ec8b97a540e` |
|
||
| `41-M0` | `I-M0`; baseline модельной оси | Переиспользован `41-W0`: `148,220 с`; `361,2 МиБ`; отдельное ускорение: not measured | Качество baseline прошло | Точка сравнения; не новая гипотеза | Ryzen-отчет, этап 2; SHA W0 выше |
|
||
| `41-M2` | `I-M2`; меняются embedding model и estimator N | `94,550 с`; `+36,21%`; `358,6 МиБ` | Обязательный gate пройден: `3/2/2`; `53/13/9` | Самая быстрая модельная ветвь; собрать C1, но диагностический рост требует слухового gate | SHA `3debc8ae5cf1bd13d806dbfe8e4cfa137d6705622a721f4a42f1a22c030ec277` |
|
||
| `41-M3` | `I-M3`; меняются embedding model и estimator N | `107,205 с`; `+27,67%`; `511,9 МиБ` | Обязательный gate пройден: `3/2/2`; `52/13/9` | Не выбирать: медленнее и тяжелее M2; обязательный gate при этом пройден | SHA `531a842234e35e29f582ff8a51406fb9dd6211e017b3162d80cca21d4732d316` |
|
||
| `41-Q0` | `I-Q0`; baseline quantization-оси | Переиспользован `41-W0`; отдельный raw aggregate: not published | Качество baseline прошло | Точка сравнения; не новая гипотеза | Старая спецификация, QDQ |
|
||
| `41-Q1` | `I-Q1`; FP32->S8S8 QDQ | `177,537 с`; `-19,78%` (замедление); `367,7 МиБ` | `fail`: `2/2/2`; `51/13/8` | Исключить: медленнее и потерян кластер | Intel-отчет, этапы 2-3; result SHA not published |
|
||
| `41-Q-U8-SKIP` | Условный U8U8; меняется формат квантизации; Intel / этап 3 | wall/ускорение/RSS: not measured | Качество: not measured | Ветка не открылась: S8S8 не достиг 10%-го порога продолжения и провалил обязательное качество | Старая спецификация, этап 3; result SHA not published |
|
||
| `41-E0a` | `I-E0`; companion baseline для E1 | Отдельные wall/ускорение/RSS: not published; отдельный result blob: not published; сравнительный W0=`148,220 с` | Качество baseline прошло | Служебная baseline-ячейка; самостоятельного решения нет | Intel-отчет, таблица ID ячеек |
|
||
| `41-E1` | `I-E1`; topology 1 worker->2 shared workers | `139,219 с`; `+6,07%`; `398,6 МиБ` | Качество прошло: `3/2/2`; метки/интервалы/диагностика совпали | Ниже Intel-порога продолжения, но допущен как заранее оговоренная ISA-гипотеза для собственного Ryzen A/B | SHA `f5ac41d29eeff1f7cfbb93497a0025aef40de0838e933e0f9baed30a236d6b85` |
|
||
| `41-E0b` | `I-E0`; companion baseline для E2 | Отдельные wall/ускорение/RSS: not published; сравнительный W0=`148,220 с` | Качество baseline прошло | Служебная baseline-ячейка | Intel-отчет, таблица ID ячеек |
|
||
| `41-E2` | `I-E2`; 4 shared workers, `intra_op=1` | `152,167 с`; `-2,66%`; `551,2 МиБ` | pass `3/2/2`, точное совпадение результата | Исключить: медленнее и больше RSS | SHA `f2664d354ede1e4bf2c42b974513cdc845ff601c73f30ebae51456764fd8dcdc` |
|
||
| `41-E0c` | `I-E0`; companion baseline для E3 | Отдельные wall/ускорение/RSS: not published; сравнительный W0=`148,220 с` | Качество baseline прошло | Служебная baseline-ячейка | Intel-отчет, таблица ID ячеек |
|
||
| `41-E3` | `I-E3`; shared->4 separate session | `159,038 с` составная оценка; `-7,30%`; `732,3 МиБ` process-wide | `pass`: `3/2/2`; метки совпали | Исключить: отрицательный контроль подтвердил рост времени и памяти; wall не равноправен штатному `process()` | Intel-отчет, этапы 2-3; result SHA not published |
|
||
| `41-C0` | `I-C0`; рабочий shift + baseline stack | wall/ускорение/RSS: not measured | по определению совпадает с прошедшим W0 | Явно пропущена как дубликат baseline | Intel-отчет, этап 1/4 |
|
||
| `41-C1` | `I-C1`; финальная проверка сильнейшей Intel-ветви | `98,347 с`; `+33,65%` к одиночному W0; `399,5 МиБ` | Обязательный gate пройден: `3/2/2`, purity `0,80137/0,91079`; слова `53/13/9` (`+2` на первом фрагменте) | **Неразрешенный слуховой gate: ни победитель, ни проигравший.** Не передавать до прослушивания подготовленных мест | SHA `4f96e6f7363e0edb79d4034a07f4d3b6b0003a820fcf6bceff5426bb3c2caff4` |
|
||
| `41-W0C2-SWAP` | `I-B136`; первая попытка guarded baseline; Intel / финальная пара | wall/ускорение/RSS: not published | Качество: not published | Отклонить: runtime guard обнаружил swap-in | Intel-отчет, раздел "Условия"; result SHA not published |
|
||
| `41-W0C2` | `I-B136`; соседний guarded baseline | `146,978 с`; baseline; `376,4 МиБ` | Качество прошло; диагностика baseline | Допустимая база сравнения только для `41-C2` | SHA `e572dd057ec87514aca4617465c48ce361677ae19279efcadbbde404afc85b5d` |
|
||
| `41-C2` | `I-C2`; baseline->2 shared workers | `140,632 с`; `+4,32%`; `406,0 МиБ` | Обязательная и диагностическая проверка точно совпала с `41-W0C2` | Intel-порог не достигнут; передать как работоспособную аппаратную ISA-гипотезу по явному правилу спецификации | SHA `d687074cc582e2ac379ed3375362f9480778feca02c7492a4c4be4fcc1a4f15a` |
|
||
|
||
`M1` не был ячейкой согласованной матрицы: нумерация spec - M0, M2, M3.
|
||
|
||
В публичной сводке для W0/M0 указан RSS `362,6 МиБ`, однако опубликованный
|
||
SHA W0 связывает wall `148,220 с` с RSS `361,2 МиБ`. В реестре выше сохранена
|
||
согласованная пара из одного raw result; публичные `362,6 МиБ` нельзя привязать
|
||
к тому же опубликованному SHA.
|
||
|
||
## Реестр: Ryzen, этапы 5-6
|
||
|
||
Для каждой A/B-строки recipe baseline - `R-B`, candidate - `R-C2`; меняется
|
||
только topology embedding-инференса. Все ячейки прошли обязательный gate и
|
||
сохранили baseline-диагностику (`3/2/2`, `51/13/9`, та же purity, те же числа
|
||
окон/embedding jobs, без потерь или дублей).
|
||
|
||
| Stable ID | Машина / стадия / порядок | Wall baseline -> candidate / ускорение | RSS baseline -> candidate | Решение и точная причина | Published result SHA-256 |
|
||
|---|---|---|---|---|---|
|
||
| `42-W0` | Ryzen / matching baseline | `110,998 с`; candidate: not measured | `370,4 МиБ`; candidate: not measured | Baseline принят | `f50684784392cacc2d99c8aee51d01f0a67dfee3da6ea3ba5f3db749a3d5287a` |
|
||
| `42-E1-AB` | Ryzen / isolated mechanism / W0->E1 | `111,557 -> 84,723 с`; `24,05%` | `367,3 -> 412,2 МиБ` | Механизм прошел качество, память и 10%-й порог продолжения | `24d5edae117e0619e432ef3f3019e8c66cf3516b87b80b64b8591390db25bf48` |
|
||
| `42-C2-P` | Ryzen / primary / C2->W0 | `111,423 -> 85,909 с`; `22,90%` | `369,6 -> 410,3 МиБ` | Прошел primary-порог; допустить пять циклов | `142db6d06efc8d558b38e18f47f47e3e35e7df00751da2583339f99add8d75c4` |
|
||
| `42-C2-F1` | Ryzen / final 1 / W0->C2 | `111,354 -> 83,529 с`; `24,99%` | `369,2 -> 413,4 МиБ` | Принятый цикл; качество pass | `4b5095c9e64ff0ef75bbc58516c662bedbbdb0bedf131f66cc1031c9a0ad8c7f` |
|
||
| `42-C2-F2` | Ryzen / final 2 / C2->W0 | `108,899 -> 83,907 с`; `22,95%` | `373,0 -> 418,1 МиБ` | Принятый цикл; качество pass | `256a17b2d08510aad03d43f5c626c1a4269c9a25271ce492dc3305c4afca1888` |
|
||
| `42-C2-F3` | Ryzen / final 3 / W0->C2 | `110,928 -> 84,968 с`; `23,40%` | `373,8 -> 410,9 МиБ` | Принятый цикл; качество pass | `b5d37c7a8b05b065c61bc9d5f1c0ab639a80a821730e505179388d90c4239caa` |
|
||
| `42-C2-F4` | Ryzen / final 4 / C2->W0 | `114,985 -> 83,342 с`; `27,52%` | `376,6 -> 411,1 МиБ` | Принятый цикл; качество pass | `639cc9f13511a59c7240c6fb6ec6bf1c31ec26350330e3ca0c64fb721b768736` |
|
||
| `42-C2-F5` | Ryzen / final 5 / W0->C2 | `113,233 -> 86,548 с`; `23,57%` | `358,6 -> 413,4 МиБ` | Принятый цикл; качество pass | `4ff2863a93fc22a037de5c292391b6b46de1b539cf397026b349ea5134cf1051` |
|
||
| `42-STAGE6-SKIP` | Ryzen / этап 6 / `R-B` и `R-C2` на трех полных записях | wall/ускорение: not measured | RSS: not measured | Этап пропущен: медиана финальных циклов `23,57%` ниже порога `30%`; качество: not measured | Ryzen-отчет, "Итог"; result SHA not published |
|
||
|
||
Итог C2: медиана сокращения `23,57%`, MAD `0,62 п. п.`; до порога `go`
|
||
`30%` не хватило `6,43 п. п.`. Качество и память прошли, скорость - нет;
|
||
решение всей воронки `new map`. Stage 6 (полные записи и пятичастная слуховая
|
||
приемка) не запускался, потому что победителя нет.
|
||
|
||
## Измеренное разложение текущего Ryzen baseline
|
||
|
||
### Семантика полей
|
||
|
||
В непатченном последовательном baseline outer `wall_seconds` измеряется вокруг
|
||
одного `diarizer.process(samples)`. Native debug отдельно дает
|
||
`segmentation_seconds`, `embedding_seconds`, `clustering_seconds` и
|
||
`engine_total_seconds`. Поэтому для каждого из трех фрагментов, а затем для их
|
||
суммы, допустимо вычислить:
|
||
|
||
`orchestration = measured outer wall - native engine total`.
|
||
|
||
Это остаток границы Python/native плюс progress callback и измерительный
|
||
обвес; схема не позволяет разложить его дальше и не доказывает, что весь остаток
|
||
принадлежит production-коду. Native stage и native total напечатаны с точностью
|
||
до `0,001 с`; таблица округляет итоговые суммы до `0,001 с`. Разность использует
|
||
сохраненные числа, до отображения не округляется.
|
||
|
||
У патченного shared-session runner `engine_total_seconds` намеренно записан
|
||
равным outer wall всего `Prepare + counter + clustering + Finalize`. Это не
|
||
отдельный native total. Поэтому для E1/C2 нельзя честно вычислить orchestration
|
||
как `outer - native`: соответствующая величина **недоступна**, а ноль был бы
|
||
артефактом схемы.
|
||
|
||
### Сумма трех записей в каждой принятой baseline-ячейке
|
||
|
||
| Baseline ID | Outer wall, с | Segmentation, с | Embeddings, с | Clustering, с | Native engine total, с | Orchestration, с |
|
||
|---|---:|---:|---:|---:|---:|---:|
|
||
| `42-W0` | 110,998 | 18,233 | 82,172 | 0,015 | 100,444 | 10,554 |
|
||
| `42-E1-AB/W0` | 111,557 | 17,888 | 82,952 | 0,015 | 100,871 | 10,686 |
|
||
| `42-C2-P/W0` | 111,423 | 19,685 | 83,635 | 0,014 | 103,357 | 8,066 |
|
||
| `42-C2-F1/W0` | 111,354 | 18,614 | 84,596 | 0,015 | 103,240 | 8,114 |
|
||
| `42-C2-F2/W0` | 108,899 | 21,071 | 79,911 | 0,012 | 101,010 | 7,889 |
|
||
| `42-C2-F3/W0` | 110,928 | 21,204 | 81,722 | 0,016 | 102,960 | 7,968 |
|
||
| `42-C2-F4/W0` | 114,985 | 19,594 | 84,715 | 0,013 | 104,342 | 10,643 |
|
||
| `42-C2-F5/W0` | 113,233 | 21,625 | 82,884 | 0,013 | 104,540 | 8,693 |
|
||
| **Суммарно: 8 ячеек / 24 записи** | **893,377** | **157,914** | **662,587** | **0,113** | **820,764** | **72,613** |
|
||
|
||
Stage-суммы отличаются от native total pooled на `0,150 с` (`0,017%` outer
|
||
wall): это ожидаемый остаток тысячного округления native debug, а не оцененная
|
||
пятая стадия.
|
||
|
||
Медианы по восьми matching baselines, рассчитанные из показанных значений без
|
||
промежуточного округления: outer `111,388 с`, segmentation `19,6395 с`,
|
||
embeddings `82,918 с`, clustering `0,0145 с`, native total
|
||
`103,100 с`, orchestration `8,404 с`.
|
||
|
||
Наблюдаемый spread (max-min, процент относительно min):
|
||
|
||
| Величина | Диапазон, с | Spread |
|
||
|---|---:|---:|
|
||
| Outer wall | `108,899-114,985` | `6,087 с` / `5,59%` |
|
||
| Segmentation | `17,888-21,625` | `3,737 с` / `20,89%` |
|
||
| Embeddings | `79,911-84,715` | `4,804 с` / `6,01%` |
|
||
| Clustering | `0,012-0,016` | `0,004 с`; относительный процент неинформативен при гранулярности `0,001 с` |
|
||
| Native total | `100,444-104,540` | `4,096 с` / `4,08%` |
|
||
| Orchestration residual | `7,889-10,686` | `2,797 с` / `35,45%` |
|
||
|
||
Это объясняет, почему Intel-разница W0/C2 `4,32%` неотличима от наблюдавшегося
|
||
там разброса, а Ryzen-финал опирался на парные циклы, а не на один baseline.
|
||
|
||
## Доли, проверенные механизмы и Amdahl ceiling
|
||
|
||
Доли ниже - pooled stage time / pooled outer wall восьми matching Ryzen
|
||
baseline. Amdahl ceiling предполагает невозможное идеальное удаление ровно
|
||
одного компонента при неизменности остальных:
|
||
|
||
`max speedup = 1 / (1 - share)`.
|
||
|
||
| Компонент | Измеренная доля current Ryzen wall | Уже проверенные сокращения | Что осталось после эксперимента | Теоретический ceiling |
|
||
|---|---:|---|---|---:|
|
||
| Segmentation | `17,676%` | W1-W4 уменьшали число окон `291->195/146/117/59` на каждом фрагменте и вместе число embedding jobs; wall падал до `31,291 с`, но уже W1 потерял обязательный кластер | Без новой segmentation-модели/логики окон дальнейшее увеличение shift закрыто quality gate | максимум `1,2147x` (`17,676%` сокращения wall) при полном устранении стадии |
|
||
| Embeddings | `74,167%` | CAMPPlus+NME (`36,21%` Intel, слуховой gate C1 открыт), TitaNet+NME (`27,67%`, тяжелее M2), QDQ (медленнее и fail), shared session (Ryzen median `23,57%`), 4 workers/separate sessions (хуже), TitaNet batch 4 (медленнее и другие метки) | Это доминирующая измеренная стадия; локальные замены прежнего каскада не дали принятого 30%-победителя | максимум `3,8709x` (`74,167%` wall) при полном устранении стадии |
|
||
| Clustering | `0,013%` | Eigengap быстро, но неверный N; NME дал правильный N для CAMPPlus/TitaNet, однако его отдельный counter wall измеряется секундами и не является baseline native clustering time | Ускорять baseline `FastClustering` бессмысленно по Amdahl; менять алгоритм можно только ради качества/архитектуры | максимум `1,00013x` (`0,013%` wall) |
|
||
| Orchestration residual | `8,128%` | `Prepare/Finalize` и shared worker прошли correctness smoke; отдельного эксперимента на сокращение остатка не было | Нельзя отделить project orchestration от callback/RSS/harness; candidate-side доля недоступна из текущей схемы | максимум `1,0885x` (`8,128%` wall) при полном устранении остатка |
|
||
|
||
Сумма четырех долей `99,983%`; недостающие `0,017%` - только эффект
|
||
округления native stage logs. Нельзя складывать наблюденные ускорения разных
|
||
ячеек как независимые: W-ветвь одновременно сокращала segmentation и число
|
||
embedding jobs, а shared-session меняла исполнение embedding внутри патченного
|
||
runner.
|
||
|
||
## Открытые gates и неизмеренные факты
|
||
|
||
1. **C1 остается неразрешенным слуховым gate - ни победитель, ни проигравший.**
|
||
Обязательная автоматическая проверка прошла, скорость на Intel превысила
|
||
30%, purity выросла, но два
|
||
дополнительных слова без говорящего требуют человеческого прослушивания.
|
||
Автоматические метрики не разрешают этот выбор.
|
||
2. Полные записи не измерялись ни для C1, ни для C2. C1 не дошла до Ryzen, C2
|
||
не прошла финальный порог скорости.
|
||
3. Ryzen C1 wall/RSS/quality неизвестны полностью; переносить Intel `33,65%` на
|
||
другую ISA нельзя.
|
||
4. Для shared-session E1/C2 нет schema-compatible native total и, следовательно,
|
||
нет candidate-side orchestration share. Доступные segmentation/embedding/
|
||
clustering поля не закрывают остаток `counter + Finalize + Python` отдельными
|
||
сопоставимыми стадиями.
|
||
5. Orchestration baseline - измеренный residual, но его production/harness
|
||
состав не измерен.
|
||
6. Температура Ryzen во время ячеек недоступна. Внешний power/throttle
|
||
guard прошел, но не заменяет сенсор внутри WSL.
|
||
7. Intel W/M/Q/E разведка - по одному прогону, ранние ячейки не чередовались;
|
||
их проценты не являются оценкой дисперсии.
|
||
8. End-to-end архитектуры не входили в матрицу. Измерены только локальные
|
||
изменения прежнего каскада.
|
||
9. `M1` отсутствует по дизайну, C0 пропущена как точный baseline-дубликат,
|
||
stage 6 пропущен по правилу "нет победителя"; это известные пропуски, а не
|
||
потерянные результаты.
|
||
10. Отдельные агрегаты Intel companion-ячеек M0/Q0/E0 не опубликованы. Их можно
|
||
использовать только как recipe-alias W0, а не выдавать за новые замеры.
|
||
|
||
## Что станет невосстановимым после удаления замороженных хранилищ
|
||
|
||
Долговечная карта должна сохранить все таблицы и формулы выше. После удаления
|
||
обоих хранилищ останутся публичные рецепты, агрегаты, решения и непрозрачные
|
||
хеши, но сами хеши уже нельзя будет повторно сверить с исходными байтами.
|
||
|
||
Без нового model run или повторной подготовки будут потеряны:
|
||
|
||
- все raw per-recording outer/stage/CPU/RSS значения за пределами опубликованных
|
||
агрегатов, включая точное восьмиклеточное Ryzen-разложение;
|
||
- сырые интервалы разметки говорящих, назначения слов, диагностические records,
|
||
ASR-sidecars и опорные материалы;
|
||
- prepared embedding-матрицы, row mappings, промежуточные результаты счетчиков,
|
||
worker requests и native logs, которыми проверялись строки/метки/финализация;
|
||
- runtime-guard свидетельства и полное состояние планировщика/manifest, включая
|
||
непубличные идентификаторы ячеек и порядок внутренних повторов;
|
||
- подготовленные C1 listening excerpts и plan. Если gate не закрыть до удаления,
|
||
для его будущего решения придется заново построить минимальный baseline/C1
|
||
diff и новые excerpts из исходных записей;
|
||
- calibration provenance и байты QDQ-графа, локальные wheel/patch artifacts,
|
||
если они отдельно не сохранены; опубликованный SHA доказывает идентичность
|
||
только при наличии байтов;
|
||
- возможность расследовать расхождения публичного 1.13.5 hash/wall и W0 RSS по
|
||
исходным файлам.
|
||
|
||
Исходные записи, по условию задачи #45, останутся лишь удобными входами для нового
|
||
минимального среза. Они не восстанавливают старые sidecars, prepared matrices,
|
||
слуховой plan, environment state или старые timing samples без повторного
|
||
вычисления.
|
||
|
||
## Граница выводов
|
||
|
||
Исторические строки выше описывают прежний каскад и прежние контрольные
|
||
фрагменты. Они отвечают на вопрос, какие локальные изменения уже проверены.
|
||
Новый эксперимент создает из сохраненных исходных записей собственные
|
||
фрагменты, ASR-sidecar, опорную разметку, baseline-диагностику и закрытое
|
||
хранилище результата. Числа `3 / 2 / 2`, `51 / 13 / 9` и прежняя purity
|
||
остаются характеристиками старых контролей. В новый gate переходят правила
|
||
точного совпадения с заново проверенным числом голосовых кластеров,
|
||
неизменности текста и безопасной памяти.
|
||
|
||
C1 после удаления старого слухового материала остается исторически
|
||
неразрешенной. Для ее повторного открытия требуется свежая минимальная пара
|
||
W0/C1 и заново подготовленный материал для прослушивания. Карта и следующий
|
||
эксперимент эту работу не выполняют.
|
||
|
||
## Класс архитектур и формула полной замены
|
||
|
||
Текущий путь строит разметку говорящих каскадом `segmentation -> embeddings ->
|
||
clustering`. В sherpa-onnx 1.13.6 отдельный эмбеддинг вычисляется для каждой
|
||
пары локального говорящего и окна; это подтверждает
|
||
[upstream-реализация](https://github.com/k2-fsa/sherpa-onnx/blob/v1.13.6/sherpa-onnx/csrc/offline-speaker-diarization-pyannote-impl.h).
|
||
Суммарное разложение выше показывает, что локальные изменения embeddings имеют
|
||
большой доступный бюджет, однако принятый 30%-й результат на Ryzen не получен.
|
||
|
||
Для сравнения архитектур используется одна формула:
|
||
|
||
```text
|
||
B = S + E + C + O
|
||
T_candidate = B - R + A
|
||
speedup = (R - A) / B
|
||
идеальный предел при A = 0: R / B
|
||
```
|
||
|
||
`B` - measured outer wall текущего W0; `S`, `E` и `C` - измеренные native
|
||
стадии; `O` - derived residual `outer wall - native engine total`; `R` - работа
|
||
старого пути, которую удаляет гипотеза; `A` - измеряемая работа новой
|
||
архитектуры. Для полной замены `R = B`, поэтому фактическое сокращение равно
|
||
`1 - A / B`. Upstream не публикует переносимый CPU RTF для выбранной модели;
|
||
числовой прогноз `A` отсутствует. Его определит свежий A/B.
|
||
|
||
## Реестр архитектурных гипотез
|
||
|
||
### A1. Streaming Sortformer v2 Q8_0 через NeMo-Speech.cpp - выбран
|
||
|
||
**Механизм и затронутые стадии.** NEST/Fast-Conformer encoder и следующий за
|
||
ним Transformer выдают четыре sigmoid-потока активности. Arrival-Order Speaker
|
||
Cache связывает говорящих между streaming-чанками; порядок меток задается
|
||
первым появлением голоса. Модель возвращает `T x 4` вероятностей с шагом 80 мс
|
||
и заменяет текущие segmentation, embeddings, подсчет/кластеризацию и
|
||
финализацию. Архитектура описана в
|
||
[карточке модели NVIDIA](https://huggingface.co/nvidia/diar_streaming_sortformer_4spk-v2)
|
||
и [первичной статье](https://arxiv.org/abs/2507.18446).
|
||
|
||
**Поведение quality gate.** Потери W1-W4 возникли после прореживания
|
||
10-секундных окон перед независимыми эмбеддингами. Sortformer оценивает
|
||
перекрывающиеся активности общей сетью и не использует эту сетку или порог AHC.
|
||
Ошибки могут перейти в границы 80-мс кадров, рождение канала и сохранение метки
|
||
в speaker cache, поэтому точное число кластеров и слуховая проверка остаются
|
||
обязательными.
|
||
|
||
**Предел и риск.** Полная замена дает идеальный предел 100% вызова, а
|
||
фактическое сокращение `1 - A_sortformer / B`. Опубликованный RTF `0,002`
|
||
измерен на RTX 6000 Ada, batch 1, и не является CPU-прогнозом
|
||
([model card](https://huggingface.co/nvidia/diar_streaming_sortformer_4spk-v2#setting-up-streaming-configuration)).
|
||
Модель имеет четыре выходных канала говорящих; NVIDIA предупреждает о
|
||
деградации на пяти и более слышимых голосах, неанглийской речи, другом домене и
|
||
очень длинных записях
|
||
([technical limitations](https://huggingface.co/nvidia/diar_streaming_sortformer_4spk-v2#technical-limitations)).
|
||
|
||
**Самая дешевая фальсификация.** На Ryzen выполнить один свежий W0 и одну
|
||
соседнюю пару W0/Sortformer на трех заново определенных пятиминутных
|
||
фрагментах. Остановить ветвь при несовпадении с новыми ожидаемыми числами
|
||
кластеров, нарушении текстовой инвариантности, OOM/swap/росте RSS без плато или
|
||
ускорении меньше 10%. Точный контракт находится в
|
||
[спецификации следующего эксперимента](../specs/2026-09-01-streaming-sortformer-cpu-experiment.md).
|
||
|
||
**Повторное использование.** Переносятся рецепт Ryzen W0, правила gate,
|
||
каноническое сведение `Word` с `SpeakerInterval`, безопасные агрегаты и
|
||
сохраненные исходные записи. Sidecar, опорная разметка, фрагменты и закрытое
|
||
хранилище создаются заново. Prepared matrices, старые интервалы, патч и wheel
|
||
не используются.
|
||
|
||
**Исполнимость.** NVIDIA публикует готовый Q8_0 GGUF, нативный Apache-2.0
|
||
runtime с CPU backend и отдельным API диаризации
|
||
([NeMo-Speech.cpp](https://github.com/NVIDIA/NeMo-Speech.cpp),
|
||
[C ABI](https://github.com/NVIDIA/NeMo-Speech.cpp/blob/4f9676226f667d14608487df744f375db87127f8/include/nemo_speech/diar.h)).
|
||
Веса имеют CC BY 4.0. Runtime и модель закреплены в следующей спецификации.
|
||
Выбор разрешает только изолированный исследовательский стенд.
|
||
|
||
### A2-A6. Фальсифицируемые альтернативы
|
||
|
||
| ID | Механизм и отличие quality gate | Предел скорости | Главный риск | Самый дешевый тест | Что можно использовать повторно | Решение |
|
||
|---|---|---|---|---|---|---|
|
||
| `A2` LS-EEND | Causal encoder, online attractors и retention полностью заменяют `B`; нет окон Pyannote, отдельных voice embeddings и AHC. [Официальный код](https://github.com/Audio-WestlakeU/FS-EEND), [статья](https://doi.org/10.1109/TASLPRO.2025.3597446). | `1 - A_ls-eend / B`; CPU `A` не опубликована. | Публичные checkpoints привязаны к 8 кГц и доменам; готовой ONNX/GGUF CPU-поставки нет; возможен дрейф attractor. | До контрольного аудио проверить официальный checkpoint, лицензию, CPU device и однозначный 16-кГц/resampling contract; затем синтетический 60-секундный smoke. | Свежие входы, sidecar и общие gate; prepared embeddings неприменимы. | Отложить: A1 проверяет полную streaming-замену с готовым CPU runtime дешевле. |
|
||
| `A3` EEND-EDA | Self-attentive encoder и LSTM attractors выдают одновременные активности и собственный stop condition вместо AHC-N. [Статья](https://arxiv.org/abs/2005.09921), [официальная реализация](https://github.com/hitachi-speech/EEND). | `1 - A_eend-eda / B`; full-context attention может расти квадратично по длине. | Нет закрепленного универсального checkpoint и документированного CPU deployment; ошибка stop condition меняет N. | Сначала найти официальный checkpoint с лицензией, 16-кГц контрактом и CPU inference. До этого аудио не запускать. | Только свежие входы и общие gate. | Отложить до появления измеримого CPU artifact. |
|
||
| `A4` EEND-VC / DiariZen | Local EEND совместно строит активности и vectors, constrained clustering связывает чанки; старые пороговые отказы не обязаны повториться. [EEND-VC](https://arxiv.org/abs/2105.09040), [DiariZen](https://github.com/BUTSpeechFIT/DiariZen), [pruning](https://arxiv.org/abs/2506.18623). | Удаляются `S+E+C`, добавляются WavLM/Conformer и новый clustering; CPU `A` не опубликована. | Даже pruned-модель требует 3,8 GMAC/s; официальный рецепт ориентирован на CUDA/Python 3.10; веса CC BY-NC 4.0. | В изолированной среде проверить импорт CPU и 30-секундный публичный sample; закрыть при несовместимости или RTF хуже W0. | Свежие входы и общие gate. | Отклонить для короткого списка: CPU path и лицензия не подходят следующему дешевому срезу. |
|
||
| `A5` pyannote Community-1 | Powerset segmentation, WeSpeaker, VBx и exclusive diarization меняют границы и оценку N, сохраняя embedding cascade. [Исходник pipeline](https://github.com/pyannote/pyannote-audio/blob/main/src/pyannote/audio/pipelines/speaker_diarization.py), [model card](https://huggingface.co/pyannote/speaker-diarization-community-1), [powerset loss](https://arxiv.org/abs/2310.13025). | Гарантированно удаляется лишь старая clustering/часть сведения; ее measured ceiling близок к нулю. Batching остается неизмеренной реализационной гипотезой. | Тяжелый PyTorch runtime, предварительная авторизованная загрузка; dense segmentation и embedding cost сохраняются. | 60-секундный публичный CPU stage-profile с RSS; закрыть, если total не лучше W0 минимум на 10%. | Свежие слова, assignment-диагностика и категории прослушивания. | Отклонить: не атакует полную доминирующую работу каскада. |
|
||
| `A6` NeMo MSDD | MarbleNet VAD, multi-scale TitaNet embeddings, clustering и neural decoder меняют все стадии и восстанавливают overlap. [Статья](https://arxiv.org/abs/2203.15974), [официальный код](https://github.com/NVIDIA-NeMo/Speech/tree/main/examples/speaker_tasks/diarization). | Знак ускорения неизвестен: VAD сокращает тишину, несколько embedding scales и decoder добавляют работу. | Штатный pretrained MSDD ориентирован на телефонию; готового meeting GGUF/ONNX CPU path нет; начальная ошибка N переходит в decoder. | До аудио потребовать подходящий meeting checkpoint и CPU contract; затем публичный 30-секундный stage smoke. | Свежие входы и общие gate. | Отклонить: добавляет embedding work без готового целевого CPU runtime. |
|
||
|
||
Реестр оставляет A2-A6 проверяемыми: для каждой ветви записан факт, который
|
||
может изменить решение. Второй кандидат в короткий список не добавлен, потому
|
||
что для него сначала пришлось бы создавать runtime или выбирать новые веса.
|
||
|
||
## Решение и владение соседними задачами
|
||
|
||
Следующее измерение проверяет ровно A1. Причины выбора: полная замена старого
|
||
вызова, готовые Q8_0 веса, закрепляемый нативный CPU runtime и standalone
|
||
разметка говорящих без изменения ASR. Контракт исполняет
|
||
[задача #46](https://git.dementev.space/ddmitry/local-transcriber/issues/46).
|
||
В задаче #45 модель и аудио не запускались.
|
||
|
||
Параллельное планирование ASR и диаризации целиком принадлежит
|
||
[задаче #22](https://git.dementev.space/ddmitry/local-transcriber/issues/22).
|
||
Автоматическое включение принадлежит
|
||
[задаче #23](https://git.dementev.space/ddmitry/local-transcriber/issues/23).
|
||
Joint ASR+diarization и shared-ASR-encoder меняют путь распознавания и исключены
|
||
из этой карты. ASR-sidecar используется только как свежий quality input.
|
||
|
||
Принятие A1 после эксперимента означает право подготовить отдельное
|
||
production-решение. Оно не меняет [ADR-007](../adr/007-word-level-speaker-diarization.md)
|
||
и не разрешает поставку NeMo-Speech.cpp в основном dependency graph.
|