docs(diarization): спроектирована end-to-end карта
- Зачем: - локальные оптимизации каскада не достигли 30%-го порога ускорения; - старые закрытые хранилища и капсулы не должны стать будущей зависимостью. - Что: - собран единый реестр результатов задач #41 и #42; - опубликовано разложение Ryzen baseline и выбрана архитектурная гипотеза; - подготовлены самодостаточная спецификация и ready-for-agent задача #46. - Проверка: - пройдены self-review и две независимые линии ревью; - проверены 44 строки реестра, 42 арифметических инварианта и ссылки; - выполнены ai-text-lint, privacy scan и post-lint guard. Refs: #45
This commit is contained in:
1 parent
312153f4bc
commit
89475b9b97
3 files changed
+927
-11
No files matched your search
@@ -202,7 +202,7 @@ Ryzen-manifest отдельно связывается с handoff и входа
|
||||
NumPy 2.4.3, ONNX 1.22.0, kaldi-native-fbank 1.22.3, psutil 7.2.2;
|
||||
- питание от сети, стабильный Windows-профиль `balanced`, EPP AC 25%,
|
||||
максимальное состояние процессора 100%, boost mode `aggressive`;
|
||||
- WSL не предоставляет governor, а доступные интерфейсы не показывают
|
||||
- WSL не предоставляет governor; доступные интерфейсы также не показывают
|
||||
температурный датчик или аппаратные лимиты мощности. Температура
|
||||
записана как недоступная; это ограничивает тепловой guard;
|
||||
- нативные WSL-интерфейсы не отдали supply, platform profile и throttle count,
|
||||
@@ -248,8 +248,11 @@ E1 и C2 сохранили все обязательные и диагност
|
||||
|
||||
## Что уже не нужно прогонять заново
|
||||
|
||||
Полный replay этапов 0-5 для следующей гипотезы не нужен. Результаты закреплены
|
||||
публичными агрегатами, хешами и закрытой капсулой.
|
||||
Полный replay этапов 0-5 для следующей гипотезы не нужен. Долговечное
|
||||
доказательство составляют публичные агрегаты, хеши и
|
||||
[карта архитектур](../research/2026-09-01-end-to-end-cpu-diarization-map.md).
|
||||
Закрытые хранилища задач #41/#42 и старый материал для прослушивания C1
|
||||
подлежат удалению и не являются будущей зависимостью.
|
||||
|
||||
| Результат | Что можно переиспользовать | Когда повтор действительно нужен |
|
||||
|---|---|---|
|
||||
@@ -258,7 +261,7 @@ E1 и C2 сохранили все обязательные и диагност
|
||||
| Q1 | Этот S8S8 QDQ-граф на Intel медленнее FP32 и дает `2 / 2 / 2` | Новая калибровка, формат квантизации, модель или runtime |
|
||||
| E2/E3 | Больше worker и отдельные session не окупились при прежнем бюджете потоков | Изменилась топология session, runtime или бюджет ядер |
|
||||
| E1/C2 на Ryzen | Для точного рецепта shared-session медиана равна 23,57%, качество и память проходят | Изменилась реализация механизма, runtime, машина или режим питания |
|
||||
| C1 | Замер скорости уже есть; открыт только диагностический слуховой gate | Сначала прослушать подготовленные места; новый CPU-замер нужен лишь после положительного решения |
|
||||
| C1 | Исторический замер скорости остается доказательством незакрытого gate; старый материал для прослушивания не сохраняется | Для повторного открытия заново выполнить минимальную пару W0/C1 и подготовить новый материал для прослушивания |
|
||||
|
||||
Есть три разных вида проверки, и они не заменяют друг друга:
|
||||
|
||||
@@ -274,10 +277,12 @@ E1 и C2 сохранили все обязательные и диагност
|
||||
|
||||
- C1 не получила слухового решения. Из автоматических метрик нельзя вывести,
|
||||
допустимы ли два дополнительных слова без говорящего.
|
||||
- На Ryzen не опубликовано разложение wall time на segmentation, embeddings,
|
||||
clustering и orchestration. По общему времени нельзя надежно назвать следующий
|
||||
доминирующий компонент.
|
||||
- Полные записи не запускались: C2 не достигла порога, а C1 не дошла до Ryzen.
|
||||
- Для восьми принятых последовательных W0 опубликовано
|
||||
[суммарное разложение](../research/2026-09-01-end-to-end-cpu-diarization-map.md#измеренное-разложение-текущего-ryzen-baseline)
|
||||
на segmentation, embeddings, clustering и orchestration residual. Для
|
||||
shared-session C2 schema-compatible native total и orchestration residual
|
||||
остаются недоступны.
|
||||
- Полные записи не запускались: C2 не достигла порога; C1 не дошла до Ryzen.
|
||||
- Температурный датчик в WSL и Windows недоступен. Внешняя проверка питания и
|
||||
throttling снижает риск дрейфа, но не заменяет измерение температуры во время
|
||||
каждой ячейки.
|
||||
@@ -310,9 +315,12 @@ E1 и C2 сохранили все обязательные и диагност
|
||||
диагностическим слуховым gate: сокращение окон и цены эмбеддинга уперлось в
|
||||
качество раньше итогового порога.
|
||||
4. По правилу спецификации следующий шаг - отдельная карта end-to-end
|
||||
диаризации, заведенная как
|
||||
[задача #45](https://git.dementev.space/ddmitry/local-transcriber/issues/45).
|
||||
Ее гипотезы и замеры относятся к отдельному эксперименту.
|
||||
диаризации: [карта архитектур](../research/2026-09-01-end-to-end-cpu-diarization-map.md)
|
||||
и [контракт Streaming Sortformer](../specs/2026-09-01-streaming-sortformer-cpu-experiment.md).
|
||||
Карта подготовлена в
|
||||
[задаче #45](https://git.dementev.space/ddmitry/local-transcriber/issues/45),
|
||||
а контракт исполняет
|
||||
[задача #46](https://git.dementev.space/ddmitry/local-transcriber/issues/46).
|
||||
5. Полные записи и Ryzen-слуховая приемка не требуются без победителя.
|
||||
6. Production-профиль, CLI, конфигурационный контракт и модель по умолчанию
|
||||
остаются без изменений.
|
||||
@@ -0,0 +1,436 @@
|
||||
# Карта 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.
|
||||
@@ -0,0 +1,472 @@
|
||||
# Эксперимент Streaming Sortformer v2 Q8_0 на Ryzen CPU
|
||||
|
||||
**Дата:** 2026-09-01
|
||||
|
||||
**Статус:** готовый контракт следующего эксперимента, исполняемый в
|
||||
[задаче #46](https://git.dementev.space/ddmitry/local-transcriber/issues/46).
|
||||
Запуск модели и аудио начинается после подготовки свежей закрытой основы.
|
||||
|
||||
## Цель и исходы
|
||||
|
||||
Эксперимент отвечает на один вопрос: сокращает ли Streaming Sortformer v2
|
||||
Q8_0 через NeMo-Speech.cpp время построения разметки говорящих на целевом Ryzen
|
||||
минимум на 30% относительно свежего последовательного W0 при приемлемом
|
||||
качестве и памяти.
|
||||
|
||||
Допустимы три исхода:
|
||||
|
||||
- `go`: медиана пяти финальных парных ускорений не ниже 30%, автоматические и
|
||||
слуховые gates пройдены;
|
||||
- `stop`: нарушен обязательный gate, первичное ускорение ниже 10%, финальная
|
||||
медиана ниже 30% или слуховая проверка подтвердила регрессию;
|
||||
- `needs-user`: отсутствует подтверждение свежей опоры или требуемое решение
|
||||
по прослушиванию. Это состояние ожидания, его нельзя публиковать как результат
|
||||
кандидата.
|
||||
|
||||
`go` разрешает подготовку отдельного production-решения. Экспериментальный
|
||||
runtime остается изолированным, а production-профиль, CLI, config и модель по
|
||||
умолчанию сохраняются.
|
||||
|
||||
## Сначала прочитать
|
||||
|
||||
1. Прочитать [карту архитектур](../research/2026-09-01-end-to-end-cpu-diarization-map.md),
|
||||
особенно разделы "Граница выводов", A1 и формулу полной замены.
|
||||
Критерий завершения: агент может объяснить, почему старые значения
|
||||
`3 / 2 / 2`, unmatched words и purity не являются порогами нового опыта.
|
||||
2. Прочитать [ADR-007](../adr/007-word-level-speaker-diarization.md) и
|
||||
[старую спецификацию](2026-08-30-cpu-diarization-experiment.md). Критерий
|
||||
завершения: сохранены каноническое сведение слов, правила 5%/10%/30% и
|
||||
memory gate.
|
||||
3. Прочитать `src/local_transcriber/benchmark_experiment.py` и
|
||||
`tests/test_benchmark_experiment.py` перед реализацией. Критерий завершения:
|
||||
новый стенд использует отдельный модуль и schema, не принимает старый
|
||||
manifest или закрытые хранилища задач #41/#42.
|
||||
|
||||
## Границы
|
||||
|
||||
В scope входят свежая закрытая основа, точный W0/Sortformer A/B на Ryzen,
|
||||
проверка трех полных записей после прохождения 30%-го порога на фрагментах и
|
||||
слуховая приемка.
|
||||
|
||||
За пределами scope остаются:
|
||||
|
||||
- replay W/M/Q/E/C и восстановление старых patch/wheel;
|
||||
- C1; ее повторное открытие требует отдельной свежей W0/C1 пары и нового
|
||||
слухового материала;
|
||||
- Intel и другие CPU;
|
||||
- production integration, dependency lock, упаковка runtime и изменение ADR;
|
||||
- параллельное планирование 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 создает только quality
|
||||
sidecar до измерений.
|
||||
|
||||
## Закрепленные реализации
|
||||
|
||||
### W0
|
||||
|
||||
W0 использует действующий последовательный путь на восьми физических ядрах:
|
||||
|
||||
- `sherpa-onnx/core 1.13.6`;
|
||||
- Pyannote Segmentation 3.0 FP32, SHA-256
|
||||
`220ad67ca923bef2fa91f2390c786097bf305bceb5e261d4af67b38e938e1079`;
|
||||
- WeSpeaker ResNet34 LM FP32, SHA-256
|
||||
`e9848563da86f263117134dfd7ad63c92355b37de492b55e325400c9d9c39012`;
|
||||
- `window_shift_ratio=0.1`;
|
||||
- `FastClustering(auto, 0.89)`;
|
||||
- `provider=cpu` для segmentation и embeddings;
|
||||
- `debug=True` для обеих model configs: stage times читаются из штатного
|
||||
debug-журнала и входят в измерительный рецепт;
|
||||
- `min_duration_on=0.3`, `min_duration_off=0.5`;
|
||||
- один worker, одна session, `intra_op_threads=8`, `inter_op_threads=1`, batch 1;
|
||||
- штатный непатченный `diarizer.process(samples)`.
|
||||
|
||||
Старые experimental patch/wheel не загружаются и не восстанавливаются. До
|
||||
первого запуска стенд проверяет версии, хеши и все effective values рецепта.
|
||||
Критерий завершения: `--validate-only` показывает рецепт `W0-FRESH` и
|
||||
останавливается при любом несовпадении.
|
||||
|
||||
### Sortformer
|
||||
|
||||
Runtime:
|
||||
|
||||
- репозиторий [NVIDIA/NeMo-Speech.cpp](https://github.com/NVIDIA/NeMo-Speech.cpp);
|
||||
- commit `4f9676226f667d14608487df744f375db87127f8`;
|
||||
- license Apache-2.0;
|
||||
- source build штатным CPU-only preset:
|
||||
`git submodule update --init ggml`, затем `scripts/configure.sh cpu-diar` и
|
||||
`cmake --build --preset cpu-diar`
|
||||
([инструкция build](https://github.com/NVIDIA/NeMo-Speech.cpp/blob/4f9676226f667d14608487df744f375db87127f8/docs/build.md),
|
||||
[точный preset](https://github.com/NVIDIA/NeMo-Speech.cpp/blob/4f9676226f667d14608487df744f375db87127f8/CMakePresets.json));
|
||||
- preset использует Release/Ninja, включает только diarization и отключает
|
||||
patched GGML; runtime запускается с `gpu=-1`, одним процессом и одним stream;
|
||||
- CPU graph использует закрепленные в этом commit четыре внутренних потока;
|
||||
runtime knob для их изменения отсутствует
|
||||
([вызов scheduler](https://github.com/NVIDIA/NeMo-Speech.cpp/blob/4f9676226f667d14608487df744f375db87127f8/src/runtime/ggml/session.cpp#L903));
|
||||
- submodule commits, compiler, CMake options и SHA-256 готового executable и
|
||||
shared library сохраняются в новом manifest.
|
||||
|
||||
Модель:
|
||||
|
||||
- repo `nvidia/diar_streaming_sortformer_4spk-v2`;
|
||||
- revision `5240a64075176943f677d30fa2171c780229f341`;
|
||||
- файл `diar_streaming_sortformer_4spk-v2.q8_0.gguf`;
|
||||
- размер `147075776` байт;
|
||||
- SHA-256 `0679cfeb1ce356d0dea9470b31274f4bfc7eb927497d82005483770666da998a`;
|
||||
- license CC BY 4.0.
|
||||
|
||||
Эти revision, размер и хеш также закреплены в
|
||||
[официальном model index выбранного runtime](https://github.com/NVIDIA/NeMo-Speech.cpp/blob/4f9676226f667d14608487df744f375db87127f8/models/index.json#L75-L88).
|
||||
После подготовки байтов стенд работает без сети.
|
||||
|
||||
Кандидат вызывается через
|
||||
[standalone C ABI](https://github.com/NVIDIA/NeMo-Speech.cpp/blob/4f9676226f667d14608487df744f375db87127f8/include/nemo_speech/diar.h),
|
||||
чтобы сохранить effective config и покадровую диагностику. Stateful streaming
|
||||
получает точную геометрию NVIDIA в 80-мс кадрах:
|
||||
|
||||
| Поле | Значение |
|
||||
|---|---:|
|
||||
| `chunk_frames` | `340` |
|
||||
| `right_context_frames` | `40` |
|
||||
| `left_context_frames` | `0` |
|
||||
| `fifo_frames` | `40` |
|
||||
| `spkcache_frames` | `188` |
|
||||
| `update_period_frames` | `300` |
|
||||
|
||||
Сумма chunk и right context дает input buffer latency 30,4 с. Опубликованный
|
||||
RTF этой конфигурации измерен на RTX 6000 Ada и в CPU-гипотезу не переносится
|
||||
([model card](https://huggingface.co/nvidia/diar_streaming_sortformer_4spk-v2#setting-up-streaming-configuration)).
|
||||
Full-attention `--offline` не используется.
|
||||
|
||||
Post-processing передается явно при каждом запросе:
|
||||
|
||||
| Поле | Значение |
|
||||
|---|---:|
|
||||
| `onset` | `0.641` |
|
||||
| `offset` | `0.561` |
|
||||
| `pad_onset_sec` | `0.229` |
|
||||
| `pad_offset_sec` | `0.079` |
|
||||
| `min_duration_sec` | `0.511` |
|
||||
| `min_gap_sec` | `0.296` |
|
||||
|
||||
Это callhome-tuned конфигурация закрепленного runtime. Она остается quality
|
||||
риском для русских рабочих встреч и не настраивается по трем контрольным
|
||||
фрагментам. Любое изменение геометрии, post-processing, quantization или
|
||||
runtime commit создает другую гипотезу и требует новой спецификации.
|
||||
|
||||
Критерий завершения подготовки кандидата: сборка выполняет синтетический
|
||||
ABI-тест без аудио, `nemo_speech_diar_num_speakers()` возвращает 4,
|
||||
`nemo_speech_diar_seconds_per_frame()` возвращает 0,08, а manifest содержит все
|
||||
закрепленные значения и хеши. Синтетический тест не заменяет smoke-проверку с
|
||||
аудио.
|
||||
|
||||
## Свежая закрытая основа
|
||||
|
||||
### Шаг 1. Выбрать источники и фрагменты
|
||||
|
||||
Владелец выбирает три сохраненные исходные записи и по одной 300-секундной
|
||||
области в каждой. Набор должен включать русскую рабочую речь, смену говорящего,
|
||||
короткий ответ и перекрытие хотя бы где-то в совокупности. В каждой области и
|
||||
каждой полной записи должно быть от двух до четырех слышимых голосов. Запись с
|
||||
пятью голосами закрывает кандидат до измерения: модель выдает не более четырех
|
||||
выходных голосовых кластеров
|
||||
([technical limitations](https://huggingface.co/nvidia/diar_streaming_sortformer_4spk-v2#technical-limitations)).
|
||||
|
||||
В закрытом manifest сохраняются source hash, точные границы и recipe
|
||||
mono/16 kHz float32. Публичные документы получают только число фрагментов,
|
||||
длительность и агрегаты.
|
||||
|
||||
Критерий завершения: три source hash уникальны, три WAV имеют ровно 300 секунд
|
||||
после единственного закрепленного преобразования, а ни один путь, ID или
|
||||
интервал не попадает в stdout режима `--validate-only`.
|
||||
|
||||
### Шаг 2. Создать ASR-sidecar и опорную разметку
|
||||
|
||||
Действующий ASR выполняется один раз для каждой полной записи до измерений.
|
||||
Sidecar хранит канонические слова с временной привязкой и нормализованный текст;
|
||||
fragment-sidecar получается детерминированным срезом той же версии. Затем
|
||||
человек прослушивает каждый фрагмент целиком, фиксирует ожидаемое число
|
||||
голосовых кластеров для фрагментов и полных записей и создает опорную разметку,
|
||||
достаточную для mapped purity и выбора мест прослушивания. Опорная разметка
|
||||
остается приближенной и не объявляется истиной границ.
|
||||
|
||||
Критерий завершения: для каждого фрагмента и каждой полной записи есть
|
||||
подтвержденное человеком `expected_cluster_count` в диапазоне `2..4`, один
|
||||
неизменяемый sidecar и SHA-256; для фрагментов также есть опорная разметка.
|
||||
Числа старых контролей не копируются.
|
||||
|
||||
### Шаг 3. Пройти пользовательский gate
|
||||
|
||||
До первого модельного запуска владелец подтверждает:
|
||||
|
||||
- право использовать выбранные записи в закрытом локальном опыте;
|
||||
- пригодность трех областей и полных записей, а также
|
||||
`expected_cluster_count` каждого фрагмента и каждой полной записи;
|
||||
- доступность исходных полных записей для этапа после 30%-го порога на
|
||||
фрагментах;
|
||||
- готовность выполнить безусловный финальный слуховой gate, если медиана
|
||||
достигнет 30%. Diagnostics только добавляют обязательные места прослушивания.
|
||||
|
||||
Критерий завершения: в закрытом manifest есть timestamped decision `approved`.
|
||||
Без него исход `needs-user`; стенд не загружает модели.
|
||||
|
||||
## Измеряемая величина и A/B
|
||||
|
||||
Время W0 - wall вокруг одного `diarizer.process(samples)`. Время кандидата -
|
||||
wall вокруг `stream_open -> push all prepared samples -> finish -> segment
|
||||
post-processing`. Для обеих ветвей модель уже загружена, WAV уже декодирован в
|
||||
один и тот же mono/16 kHz float32 buffer. ASR, скачивание, build, model load,
|
||||
декодирование, чтение sidecar, запись artifacts и расчет метрик находятся вне
|
||||
таймера.
|
||||
|
||||
Полная замена оценивается только измерением:
|
||||
|
||||
```text
|
||||
B = measured W0 wall
|
||||
A = measured Sortformer wall
|
||||
speedup_percent = 100 * (B - A) / B
|
||||
```
|
||||
|
||||
Восьмиклеточное историческое Ryzen-разложение не подставляется вместо свежего
|
||||
`B`. CPU prediction для `A` отсутствует.
|
||||
|
||||
Каждая ячейка запускается новым дочерним процессом на одной машине, от сети, в
|
||||
стабильном power mode. Process affinity разрешает те же восемь физических ядер
|
||||
обеим ветвям. W0 получает `intra_op_threads=8`; закрепленный candidate runtime
|
||||
исполняет CPU graph четырьмя внутренними потоками. Это часть сравниваемого
|
||||
runtime recipe. Изменение hardcoded числа потоков образует новую гипотезу.
|
||||
Фиксируются logical/physical cores, CPUID/ISA, RAM, ОС, compiler/runtime
|
||||
versions, affinity, effective threads, power mode, governor, turbo, throttling
|
||||
и swap. Прогон со сменой режима или throttling не учитывается и повторяется
|
||||
один раз после стабилизации.
|
||||
|
||||
### Шаг 4. Принять свежий W0
|
||||
|
||||
Один `W0-FRESH` обрабатывает три фрагмента последовательно. Для каждого
|
||||
сохраняются raw wall/CPU/RSS и stage times; публично выводится сумма. W0 должен
|
||||
дать ровно подтвержденные `expected_cluster_count`, сохранить sidecar-текст и
|
||||
пройти memory gate.
|
||||
|
||||
Критерий завершения: W0 прошел все обязательные gates и его закрытый result
|
||||
имеет SHA-256. При провале итог `stop`: база сравнения непригодна.
|
||||
|
||||
### Шаг 5. Выполнить первичный A/B
|
||||
|
||||
Сразу после принятого W0 запускается одна ячейка кандидата на тех же buffers и в
|
||||
том же порядке фрагментов. Primary order закреплен как `W0 -> candidate`; пять
|
||||
дорогих циклов ниже устраняют постоянный порядок чередованием. Один primary
|
||||
cycle равен сумме трех wall times каждой ветви.
|
||||
|
||||
Критерий завершения: обе ячейки имеют raw result, одинаковый список input
|
||||
hashes и один pair ID; рассчитаны ускорение, CPU и RSS delta.
|
||||
|
||||
Решение после primary:
|
||||
|
||||
- `abs(speedup) <= 5%` - результат фиксируется как равенство по скорости;
|
||||
- `speedup < 10%` - `stop`: причина `equal-speed` для равенства по скорости,
|
||||
иначе `below-continuation`;
|
||||
- `speedup >= 10%` при всех gates - перейти к пяти финальным циклам;
|
||||
- любой обязательный quality/memory/Sortformer gate - немедленный `stop`.
|
||||
|
||||
### Шаг 6. Выполнить пять финальных циклов
|
||||
|
||||
Каждый цикл содержит свежую ячейку W0 и свежую ячейку кандидата на всех трех
|
||||
фрагментах. Primary pair в пять финальных циклов не входит. Порядок закреплен
|
||||
заранее и чередуется так:
|
||||
|
||||
1. final 1: `candidate -> W0`;
|
||||
2. final 2: `W0 -> candidate`;
|
||||
3. final 3: `candidate -> W0`;
|
||||
4. final 4: `W0 -> candidate`;
|
||||
5. final 5: `candidate -> W0`.
|
||||
|
||||
Вместе с primary `W0 -> candidate` это исключает выбор порядка по уже видимому
|
||||
результату. Дополнительные варианты, модели и настройки не добавляются.
|
||||
|
||||
Критерий завершения: получены пять парных ускорений, их медиана и MAD; все
|
||||
десять ячеек прошли gates. Медиана не ниже 30% открывает проверку полных записей.
|
||||
Медиана ниже 30% дает `stop`. Дополнительные повторы не назначаются.
|
||||
|
||||
### Шаг 7. Проверить полные записи и пройти слуховой gate
|
||||
|
||||
После медианы не ниже 30% W0 и candidate однократно обрабатывают три полные
|
||||
исходные записи. Скорость полных прогонов остается диагностикой и не заменяет
|
||||
пятипарную медиану.
|
||||
|
||||
Владелец получает blinded A/B материал по пяти категориям:
|
||||
|
||||
- короткие ответы и перебивки;
|
||||
- смены говорящего;
|
||||
- перекрывающаяся речь;
|
||||
- устойчивость соответствия голоса кластеру;
|
||||
- слова без говорящего и малые остаточные кластеры.
|
||||
|
||||
Материал включает все места, отмеченные сравнительными diagnostics, и
|
||||
фиксированную случайную выборку совпадающих мест. Порядок A/B и имя кандидата
|
||||
раскрываются после вердикта. По каждой категории владелец записывает `pass` или
|
||||
`fail` и короткую причину в закрытом хранилище; публично остается только
|
||||
вердикт.
|
||||
|
||||
Критерий завершения: три пары на полных записях прошли автоматические gates,
|
||||
все пять слуховых категорий имеют решение. Любой подтвержденный `fail` дает
|
||||
`stop`; полный `pass` завершает эксперимент как `go`.
|
||||
|
||||
## Gates и диагностика
|
||||
|
||||
### Обязательное качество и корректность
|
||||
|
||||
Каждая ячейка W0 и кандидата обязана выполнить все условия:
|
||||
|
||||
- число голосовых кластеров каждого обрабатываемого контрольного объекта -
|
||||
фрагмента или полной записи - точно равно свежему, подтвержденному человеком
|
||||
`expected_cluster_count`;
|
||||
- нормализованный текст и порядок слов побайтно совпадают с одним sidecar;
|
||||
- нет потерянных, продублированных или переставленных слов;
|
||||
- интервалы конечны, имеют положительную длительность, лежат в пределах audio
|
||||
duration с учетом явно заданного padding и отсортированы по началу;
|
||||
- каноническая нумерация меток детерминирована на повторном расчете метрик;
|
||||
- все inputs, параметры и output artifacts имеют SHA-256.
|
||||
|
||||
Purity и число слов без говорящего сравниваются с новым `W0-FRESH`. Ухудшение
|
||||
не дает автоматического `fail`, но обязательно добавляет все затронутые места в
|
||||
слуховой gate. Старые абсолютные значения не участвуют.
|
||||
|
||||
Открытый диагностикой слуховой gate не прерывает шаги 5-6. Стенд накапливает
|
||||
затронутые места и добавляет их в материал шага 7. Состояние `needs-user` из-за
|
||||
прослушивания возможно только после достижения 30%-го порога и подготовки
|
||||
полного blinded-материала.
|
||||
|
||||
### Sortformer-specific gate
|
||||
|
||||
Для каждой ячейки кандидата сохраняются и проверяются:
|
||||
|
||||
- `num_speakers=4`, `seconds_per_frame=0.08` и точная geometry/post-processing
|
||||
из этой спецификации;
|
||||
- `frame_count`, `frame_probs_start` и размер доступной матрицы `T x 4`;
|
||||
- каждое сохраненное probability конечно и принадлежит `[0, 1]`;
|
||||
- каждая итоговая speaker label принадлежит `1..4`;
|
||||
- число и суммарная длительность интервалов по каждому каналу;
|
||||
- число коротких интервалов, overlap ratio, unmatched words, малые/остаточные
|
||||
кластеры и mapped purity относительно свежей опорной разметки;
|
||||
- wall отдельно для model inference и segment post-processing.
|
||||
|
||||
Любой неверный shape/value/label или эффективная конфигурация, отличная от
|
||||
закрепленной, дает `stop`. Появление лишнего/пропажа ожидаемого кластера дает
|
||||
`stop`. Изменение channel stability, short-turn, overlap, unmatched-word или
|
||||
purity diagnostics открывает слуховую проверку; числовой порог для этих proxy
|
||||
не вводится.
|
||||
|
||||
Жесткий предел четырех выходных голосовых кластеров, риск записей с пятью и
|
||||
более слышимыми голосами и риск non-English/out-of-domain сохраняются в
|
||||
публичном решении даже после `go`; опыт не доказывает применимость к другим
|
||||
встречам.
|
||||
|
||||
### Память
|
||||
|
||||
Peak RSS измеряется process-wide для каждой ячейки. Также сохраняются swap до и
|
||||
после, page faults и RSS после каждого фрагмента.
|
||||
|
||||
Memory gate дает `stop` при OOM, активной подкачке во время ячейки, RSS без плато
|
||||
между повторами или линейном росте RSS с числом обработанных фрагментов. Peak
|
||||
RSS выше 2 ГиБ на машине с 16 ГиБ требует отдельного разбора владельца и
|
||||
состояния `needs-user`; одно превышение не является автоматическим `fail`.
|
||||
|
||||
## Артефакты и приватность
|
||||
|
||||
Checkout и дерево сборки NeMo-Speech.cpp, скачанные веса и новое закрытое
|
||||
хранилище размещаются вне рабочей копии local-transcriber. Обычная `.scratch`
|
||||
внутри репозитория не подходит: `.gitignore` покрывает там только
|
||||
`.scratch/handoffs/`. Ни один runtime/model/build artifact или закрытый вход не
|
||||
попадает в Git.
|
||||
|
||||
Новое закрытое хранилище содержит:
|
||||
|
||||
- versioned manifest со schema, clean local-transcriber source commit,
|
||||
source/model/runtime/build hashes и расписанием;
|
||||
- исходные ссылки, подготовленные WAV и recipe преобразования;
|
||||
- ASR-sidecar и опорную разметку;
|
||||
- raw per-fragment results, intervals, word assignments и probability
|
||||
diagnostics;
|
||||
- machine/power/runtime guards и stderr/stdout logs;
|
||||
- материал и решения слуховой проверки;
|
||||
- байты runtime/model либо проверяемый download recipe с revision, size и hash.
|
||||
|
||||
Хранилище не ссылается на закрытые хранилища задач #41/#42 и остается
|
||||
достаточным для разбора собственного результата. Удаление старых хранилищ не
|
||||
блокирует ни один шаг.
|
||||
|
||||
Публичный отчет содержит `clean local-transcriber source commit`, точные
|
||||
рецепты, хеши, агрегаты, вердикты gates и итоговое решение. В Git, комментарии
|
||||
Gitea, задания на ревью и вывод `--validate-only` не попадают пути,
|
||||
`source/recording IDs`, текст, временные интервалы, сырые строки, содержимое
|
||||
manifest, логи, имена участников или аудио.
|
||||
|
||||
При нарушении приватности стенд останавливается до публикации. Уже
|
||||
сформированный публичный артефакт удаляется из рабочей ветки и создается заново
|
||||
из безопасных агрегатов.
|
||||
|
||||
## Реализация стенда и тесты
|
||||
|
||||
Новый стенд реализуется отдельным модулем
|
||||
`src/local_transcriber/streaming_sortformer_experiment.py`; существующий
|
||||
`benchmark_experiment.py` остается источником общих проверенных механизмов.
|
||||
Стенд получает отдельную schema и только две recipe: `W0-FRESH` и
|
||||
`SORTFORMER-V2-Q8`. Manifest validation выполняется до загрузки моделей.
|
||||
`--validate-only` проверяет:
|
||||
|
||||
- три уникальных source hashes, 300-секундные фрагменты и fresh-basis marker;
|
||||
- human approval и `expected_cluster_count` каждого фрагмента и каждой полной
|
||||
записи в диапазоне `2..4`;
|
||||
- W0 model/runtime hashes и effective values: CPU provider, `debug=True`,
|
||||
`min_duration_on=0.3`, `min_duration_off=0.5`, threads и clustering;
|
||||
- clean local-transcriber worktree и source commit из manifest;
|
||||
- Sortformer revision, size, SHA-256, runtime commit, submodules, build hashes,
|
||||
CPU backend, geometry и post-processing;
|
||||
- одинаковые input/sidecar hashes обеих ветвей;
|
||||
- заранее созданные primary/final schedules;
|
||||
- отсутствие корней старых хранилищ и legacy ID ячеек.
|
||||
|
||||
Минимальные детерминированные тесты выполняются без модели и аудио:
|
||||
|
||||
```bash
|
||||
uv run pytest -q \
|
||||
tests/test_streaming_sortformer_experiment.py \
|
||||
tests/test_benchmark_experiment.py \
|
||||
tests/test_speaker_diarizer.py \
|
||||
tests/test_diarization.py
|
||||
```
|
||||
|
||||
Новый модуль тестов покрывает отклонение `schema`, несовпадение пинов и хешей,
|
||||
требование свежей опоры, обезличенный вывод `--validate-only`, правило
|
||||
`expected_cluster_count`, точное расписание A/B, границы 5%/10%/30%, gates
|
||||
качества, памяти и Sortformer, переход к прослушиванию, безопасную сериализацию
|
||||
и остановку при первом отказе. Стенд C ABI имеет отдельный синтетический тест
|
||||
размеров структур, выбора CPU и эффективной конфигурации; модель в модульных
|
||||
тестах не загружается.
|
||||
|
||||
Критерий завершения реализации стенда: все детерминированные тесты проходят,
|
||||
`--validate-only` проходит на закрытом manifest и публичный вывод проходит
|
||||
privacy scan. Реализация стенда фиксируется чистым коммитом исходников,
|
||||
совпадающим с manifest. Только после этого разрешен первый запуск модели W0.
|
||||
|
||||
## Критерии завершения эксперимента
|
||||
|
||||
- [ ] Свежая опора подтверждена владельцем и не наследует старые контрольные
|
||||
значения.
|
||||
- [ ] Runtime, модель, сборка и оба рецепта закреплены и проверены до моделей.
|
||||
- [ ] Clean local-transcriber source commit сохранен в закрытом хранилище и
|
||||
публичном отчете, а `--validate-only` проверяет его до моделей.
|
||||
- [ ] Свежий W0 принят либо итог `stop` объясняет провал базы сравнения.
|
||||
- [ ] Первичный A/B завершен; решение 10% применено без дополнительных ветвей.
|
||||
- [ ] При продолжении завершены ровно пять финальных циклов, медиана и MAD.
|
||||
- [ ] Каждая выполненная ячейка имеет вердикты качества, текста, памяти и
|
||||
Sortformer.
|
||||
- [ ] При медиане 30% выполнены три пары на полных записях и пять слуховых
|
||||
решений.
|
||||
- [ ] Все остановленные шаги имеют первую точную причину и хеш результата.
|
||||
- [ ] Закрытое хранилище самодостаточно; публичный отчет содержит только безопасные
|
||||
агрегаты и SHA-256.
|
||||
- [ ] Итог равен `go` или `stop`; `needs-user` остается открытым до решения.
|
||||
- [ ] Ни один результат автоматически не меняет production-зависимости,
|
||||
профиль, CLI, config или модель по умолчанию.
|
||||
Reference in new issue
Block a user