docs(diarization): спроектирован следующий CPU-эксперимент #40
@@ -0,0 +1,550 @@
|
|||||||
|
# Следующий CPU-эксперимент диаризации
|
||||||
|
|
||||||
|
**Дата:** 2026-08-30
|
||||||
|
|
||||||
|
**Статус:** согласованная постановка эксперимента. Production-конфигурация не
|
||||||
|
менялась.
|
||||||
|
|
||||||
|
## Проблема
|
||||||
|
|
||||||
|
Текущий профиль Pyannote FP32 + WeSpeaker тратит большую часть времени
|
||||||
|
диаризации на эмбеддинги для сильно перекрывающихся окон. Отдельные исследования
|
||||||
|
нашли три независимых рычага: увеличить шаг окна, удешевить эмбеддинги и изменить
|
||||||
|
их исполнение. Полный перебор всех сочетаний слишком дорог и смешивает проверку
|
||||||
|
механизма с выбором итогового профиля.
|
||||||
|
|
||||||
|
Нужен один эксперимент с последовательным отсевом. Он должен показать, есть ли
|
||||||
|
комбинация, которая сокращает время диаризации на Ryzen минимум на 30%, сохраняет
|
||||||
|
принятую проверку качества и остается работоспособной на старом Intel. Ориентир
|
||||||
|
для сильного результата - ускорение примерно в два раза.
|
||||||
|
|
||||||
|
## Сначала прочитать
|
||||||
|
|
||||||
|
- [ADR-007](../adr/007-word-level-speaker-diarization.md) - когда работа касается
|
||||||
|
действующего профиля и проверки качества.
|
||||||
|
- [Предыдущий CPU-тест](../benchmarks/2026-08-30-lightweight-diarization-cpu.md) -
|
||||||
|
при работе с корпусом, метриками и приватными результатами.
|
||||||
|
- [Шаг окна](../research/2026-08-30-sherpa-window-shift.md) - при добавлении
|
||||||
|
`window_shift_ratio` и счетчиков работы.
|
||||||
|
- [Оценка числа говорящих](../research/2026-08-30-diarization-speaker-count.md) -
|
||||||
|
при реализации `Prepare/Finalize`, eigengap и NME.
|
||||||
|
- [Embedding-инференс](../research/2026-08-30-diarization-embedding-inference.md) -
|
||||||
|
при квантизации, конкурентных stream и batch TitaNet.
|
||||||
|
- [Решение об аппаратной матрице](https://git.dementev.space/ddmitry/local-transcriber/issues/35#issuecomment-2243)
|
||||||
|
- при подготовке машин и разборе памяти.
|
||||||
|
|
||||||
|
## Цель и границы
|
||||||
|
|
||||||
|
Эксперимент должен:
|
||||||
|
|
||||||
|
- расширить исследовательский стенд для новых ручек, повторов и счетчиков;
|
||||||
|
- независимо проверить сокращение работы, модель с надежной оценкой числа
|
||||||
|
говорящих и способы ускорить embedding-инференс;
|
||||||
|
- собрать не больше трех комбинаций на Intel, передать их в Ryzen-этап и
|
||||||
|
оставить там не больше двух финалистов после первичного A/B;
|
||||||
|
- выбрать один итоговый вариант либо зафиксировать, почему ни один вариант не
|
||||||
|
прошел;
|
||||||
|
- выпустить публичный обезличенный отчет и сохранить полную переносимую капсулу
|
||||||
|
в закрытой папке Яндекс Диска.
|
||||||
|
|
||||||
|
В эксперимент не входят:
|
||||||
|
|
||||||
|
- изменение CLI, `.transcriber.toml` или модели по умолчанию;
|
||||||
|
- автоматический профиль по ISA или отдельные пользовательские профили;
|
||||||
|
- параллельный запуск ASR и диаризации, GPU, NPU и Mac;
|
||||||
|
- новая полная спектральная кластеризация, NeMo runtime и k-means;
|
||||||
|
- CAMPPlus batch без маски и несколько сессий как самостоятельное направление;
|
||||||
|
- production-переход на победителя по результату одного эксперимента.
|
||||||
|
|
||||||
|
Если каскад не достигает нужной скорости из-за качества, следующий шаг -
|
||||||
|
отдельная карта по end-to-end диаризации. Этот эксперимент ее не начинает.
|
||||||
|
|
||||||
|
## Совпадающий baseline
|
||||||
|
|
||||||
|
Каждое сравнение использует baseline, запущенный на той же машине, в том же
|
||||||
|
режиме питания и на том же стенде:
|
||||||
|
|
||||||
|
- `sherpa-onnx` 1.13.6;
|
||||||
|
- Pyannote Segmentation 3.0 FP32;
|
||||||
|
- WeSpeaker ResNet34 LM FP32;
|
||||||
|
- `window_shift_ratio=0.1`;
|
||||||
|
- `FastClustering` с порогом `0.89` и автоматическим числом кластеров;
|
||||||
|
- последовательный embedding-инференс;
|
||||||
|
- не больше `P` потоков, где `P` - число физических ядер машины.
|
||||||
|
|
||||||
|
Версию `sherpa-onnx`, uv override и `sherpa-onnx-core` обновляют синхронно.
|
||||||
|
Значение `0.1` сохраняет действующее поведение. Изменение зависимости само по
|
||||||
|
себе не считается ускорением. На тех же трех фрагментах W0 сравнивается со
|
||||||
|
свежим запуском 1.13.5 на той же машине. После канонической нумерации кластеров
|
||||||
|
сверяются интервалы, назначение говорящих словам и прежние диагностические
|
||||||
|
метрики. Различия направляются в слуховую проверку отмеченных мест. Baseline
|
||||||
|
1.13.6 принимается только при `3 / 2 / 2` и отсутствии подтвержденной регрессии.
|
||||||
|
|
||||||
|
Время диаризации во всей спецификации означает wall time одного вызова
|
||||||
|
`diarizer.process(samples)`. ASR, загрузка моделей, декодирование и подготовка
|
||||||
|
данных в него не входят.
|
||||||
|
|
||||||
|
Три порога используются во всех этапах:
|
||||||
|
|
||||||
|
- разница до 5% считается равенством по скорости;
|
||||||
|
- 10% - порог продолжения после дешевого отсева;
|
||||||
|
- 30% - итоговый порог `go` на Ryzen.
|
||||||
|
|
||||||
|
## Стенд и данные
|
||||||
|
|
||||||
|
Существующий `scripts/benchmarks/diarization_calibration.py` остается точкой
|
||||||
|
входа, но получает новую версию manifest. Прежний формат жестко закрепляет
|
||||||
|
матрицу FP32/INT8 x WeSpeaker/TitaNet, обязательный свип порогов и
|
||||||
|
`sherpa-onnx` 1.13.5, поэтому старые результаты с новым экспериментом не
|
||||||
|
продолжаются.
|
||||||
|
|
||||||
|
Новая версия manifest и идентификатор ячейки должны учитывать:
|
||||||
|
|
||||||
|
- вариант шага окна, модель, счетчик `N` и способ embedding-инференса;
|
||||||
|
- число outer workers, вид session и бюджеты intra-op/inter-op;
|
||||||
|
- размер batch, где он применим;
|
||||||
|
- машину, число физических ядер, CPUID/ISA и версии библиотек;
|
||||||
|
- номер повтора и позицию в расписании;
|
||||||
|
- этап `intel` или `ryzen`; для Ryzen - исходный commit handoff;
|
||||||
|
- хеш экспериментальной сборки или патча sherpa-onnx;
|
||||||
|
- хеши моделей и приватных входов по прежнему контракту.
|
||||||
|
|
||||||
|
Для QDQ идентичность также включает хеши калибровочных источников,
|
||||||
|
препроцессинг, reader, параметры `quant_pre_process` и `quantize_static`, список
|
||||||
|
исключенных узлов, версии инструментов и хеш готового графа. Для каждого
|
||||||
|
калибровочного элемента manifest хранит идентификатор и SHA-256 исходной записи,
|
||||||
|
а также использованный временной интервал. Вырезанный или перекодированный файл
|
||||||
|
наследует эти данные от исходника. Ни один калибровочный элемент не может
|
||||||
|
происходить из трех контрольных записей, даже из другого интервала.
|
||||||
|
`--validate-only` отклоняет общий исходник; если происхождение нельзя подтвердить
|
||||||
|
или отдельного материала нет, ветвь QDQ пропускается и не блокирует остальные
|
||||||
|
направления. Проверка показывает только хеши и рецепт без приватных путей.
|
||||||
|
|
||||||
|
Каждая измеряемая ячейка выполняется в новом дочернем процессе. Стенд сохраняет
|
||||||
|
сырые результаты каждого повтора и не заменяет их одной агрегированной строкой.
|
||||||
|
При продолжении запуска успешные ячейки пропускаются по стабильному
|
||||||
|
идентификатору, а расписание оставшихся сохраняет заданный A/B-порядок. Режим
|
||||||
|
`--validate-only` показывает полный план без приватных путей и текста.
|
||||||
|
|
||||||
|
### Приватная капсула
|
||||||
|
|
||||||
|
Капсула передается одним ZIP-архивом; `capsule_sha256` означает SHA-256 этого
|
||||||
|
файла. В корне лежит `capsule.json` с идентификатором капсулы, исходным commit,
|
||||||
|
хешем публичного Intel-отчета и SHA-256 каждого файла внутри. Все пути в manifest
|
||||||
|
относительны корня распакованной капсулы.
|
||||||
|
|
||||||
|
Архив содержит:
|
||||||
|
|
||||||
|
- manifest и полный набор входов для трех пятиминутных и трех полных прогонов;
|
||||||
|
- ASR-sidecar, опорные транскрипты и разметку, нужную для метрик и прослушивания;
|
||||||
|
- калибровочный материал и готовый QDQ-граф, если QDQ передается в Ryzen;
|
||||||
|
- сырые Intel-результаты, интервалы, worker requests и журналы, нужные для
|
||||||
|
продолжения и разбора;
|
||||||
|
- локально созданные или измененные модельные артефакты.
|
||||||
|
|
||||||
|
Публично загружаемые базовые модели можно не дублировать в архиве, если manifest
|
||||||
|
фиксирует репозиторий, revision и SHA-256. После распаковки `--validate-only`
|
||||||
|
сверяет внешний хеш архива, `capsule.json`, относительные пути и все внутренние
|
||||||
|
хеши до запуска моделей.
|
||||||
|
|
||||||
|
### Приватность
|
||||||
|
|
||||||
|
За пределами Git остаются manifest, записи, WAV-кеш, ASR-sidecar, опорные
|
||||||
|
транскрипты, сырые интервалы, результаты, worker requests, журналы и материалы
|
||||||
|
слуховой проверки. Рабочий каталог стенда нельзя размещать в обычной
|
||||||
|
`.scratch`: репозиторий игнорирует там только служебный каталог
|
||||||
|
`.scratch/handoffs/`, не связанный с переносом эксперимента между ноутбуками.
|
||||||
|
|
||||||
|
Публичный отчет содержит хеши, агрегаты, конфигурацию и выводы. В него не входят
|
||||||
|
локальные пути, распознанный текст, временные интервалы, имена участников и
|
||||||
|
фрагменты приватных записей. Перед внешним ревью используется только публичный
|
||||||
|
отчет и код стенда.
|
||||||
|
|
||||||
|
## Разделение работы между ноутбуками
|
||||||
|
|
||||||
|
Эксперимент выполняют две зависимые задачи. Один агент не меняет машину в ходе
|
||||||
|
работы:
|
||||||
|
|
||||||
|
| Задача | Машина | Этапы | Результат |
|
||||||
|
|---|---|---|---|
|
||||||
|
| [Intel #41](https://git.dementev.space/ddmitry/local-transcriber/issues/41) | Core i7-6820HQ | 0-4 | стенд, Intel-отчет и handoff |
|
||||||
|
| [Ryzen #42](https://git.dementev.space/ddmitry/local-transcriber/issues/42) | Ryzen 7 8845H | 5-6 | финальный отчет и решение |
|
||||||
|
|
||||||
|
Intel-агент коммитит в обычную ветку своей задачи код стенда и обезличенный
|
||||||
|
отчет. Специальная общая ветка для handoff не создается. Manifest, сырые
|
||||||
|
результаты и другие приватные материалы в Git не попадают. В финальном
|
||||||
|
комментарии к Intel-задаче агент оставляет только индекс:
|
||||||
|
|
||||||
|
- `intel_outcome`: `handoff` или `stop-before-ryzen`;
|
||||||
|
- ветку, точный commit и PR;
|
||||||
|
- путь и SHA-256 публичного Intel-отчета;
|
||||||
|
- число кандидатов и ссылку на их рецепты в отчете;
|
||||||
|
- непрозрачный идентификатор приватной капсулы и ее SHA-256;
|
||||||
|
- ссылку на ограничения в отчете.
|
||||||
|
|
||||||
|
При расхождении источником истины служит файл отчета в указанном commit,
|
||||||
|
комментарий остается указателем. Он не содержит приватных путей, текста или
|
||||||
|
интервалов. Пользователь передает капсулу на второй ноутбук отдельно и сливает
|
||||||
|
Intel-PR обычным merge, без squash или rebase. После этого #41 закрывается и
|
||||||
|
средствами Gitea разблокирует #42. Ryzen-агент сначала читает обе задачи и все
|
||||||
|
комментарии к первой, обновляет `master` и проверяет присутствие handoff-commit
|
||||||
|
в его истории. Затем он сверяет SHA-256 капсулы и запускает `--validate-only`.
|
||||||
|
При наличии кандидатов агент создает обычную ветку #42 от `master`.
|
||||||
|
Несовпадение commit, капсулы или плана переводит задачу в `needs-info`;
|
||||||
|
недостающие данные агент не восстанавливает догадками.
|
||||||
|
|
||||||
|
Штатный путь идет только с Intel на Ryzen. Если на Ryzen обнаружена ошибка
|
||||||
|
стенда, которая делает Intel-результаты недействительными, эксперимент
|
||||||
|
останавливается и требует отдельного исправления. Обычный отсев или проигрыш
|
||||||
|
кандидата не возвращает работу на Intel.
|
||||||
|
|
||||||
|
## Воронка вариантов
|
||||||
|
|
||||||
|
### Этап 0. Проверить механизмы без дорогих замеров
|
||||||
|
|
||||||
|
До CPU-матрицы стенд должен пройти дешевые проверки:
|
||||||
|
|
||||||
|
1. `sherpa-onnx` 1.13.6 импортируется, принимает пять значений шага и сохраняет
|
||||||
|
прежнее поведение при `0.1`.
|
||||||
|
2. Счетчик eigengap и NME проходят синтетические фикстуры из исследования.
|
||||||
|
Затем оба считаются на независимых копиях трех матриц CAMPPlus и трех матриц
|
||||||
|
TitaNet, подготовленных без повторного инференса. Для каждой модели отдельно
|
||||||
|
остается счетчик, который дает точные `3 / 2 / 2`. Если проходят оба, при
|
||||||
|
разнице времени до 10% выбирается более простой eigengap, иначе более
|
||||||
|
быстрый. Модель, для которой не проходит ни один счетчик, выбывает из
|
||||||
|
автоматического режима.
|
||||||
|
3. `Prepare/Finalize` сохраняет пары строк и штатную финализацию. Для известного
|
||||||
|
`N` метки строк и итоговая разметка совпадают с отдельным штатным вызовом на
|
||||||
|
той же матрице.
|
||||||
|
4. WeSpeaker S8S8 QDQ сохраняет входы, выходы, opset, пользовательские метаданные
|
||||||
|
и загружается через `SpeakerEmbeddingExtractor`.
|
||||||
|
5. Shared-session возвращает по одному результату на каждый вход без гонок,
|
||||||
|
пропусков и нечисловых значений. Сравнение ведется с последовательными
|
||||||
|
вызовами на том же наборе входов.
|
||||||
|
|
||||||
|
Числовой дрейф эмбеддингов записывается, но отдельный произвольный порог для него
|
||||||
|
не вводится. Решение принимается по одинаковому числу кластеров, меткам строк и
|
||||||
|
итоговой разметке.
|
||||||
|
|
||||||
|
### Этап 1. Найти безопасный шаг окна на Intel
|
||||||
|
|
||||||
|
На Core i7-6820HQ проверяется текущая связка WeSpeaker с сеткой:
|
||||||
|
|
||||||
|
| Ячейка | `window_shift_ratio` | Роль |
|
||||||
|
|---|---:|---|
|
||||||
|
| W0 | `0.10` | совпадающий baseline |
|
||||||
|
| W1 | `0.15` | осторожное сокращение окон |
|
||||||
|
| W2 | `0.20` | примерно половина исходных окон |
|
||||||
|
| W3 | `0.25` | агрессивный кандидат |
|
||||||
|
| W4 | `0.50` | граничная проверка |
|
||||||
|
|
||||||
|
Для каждой ячейки выполняется один прогон трех пятиминутных фрагментов. Стенд
|
||||||
|
записывает фактический шаг в сэмплах, расчетное число segmentation-окон и число
|
||||||
|
embedding-заданий. Ускорение без соответствующего изменения счетчиков считается
|
||||||
|
необъясненным и не проходит дальше до разбора.
|
||||||
|
|
||||||
|
Все значения, прошедшие обязательные условия, ранжируются по времени
|
||||||
|
диаризации. При равенстве по скорости выбирается меньший шаг: он меньше отходит
|
||||||
|
от принятой разметки. Если лучший по времени шаг ухудшает purity или число слов
|
||||||
|
без говорящего, до сборки комбинаций прослушиваются отмеченные пятиминутные
|
||||||
|
случаи. Рабочим становится лучший шаг, достигший порога продолжения. Если такого
|
||||||
|
нет, рабочим остается `0.1`, а ветвь шага считается проигравшей.
|
||||||
|
|
||||||
|
### Этап 2. Выбрать модель и счетчик говорящих на Intel
|
||||||
|
|
||||||
|
При `window_shift_ratio=0.1` сравниваются:
|
||||||
|
|
||||||
|
| Ячейка | Эмбеддинги | Оценка числа говорящих |
|
||||||
|
|---|---|---|
|
||||||
|
| M0 | WeSpeaker FP32 | текущий `FastClustering`, порог `0.89` |
|
||||||
|
| M2 | CAMPPlus | счетчик, выбранный для CAMPPlus, + `FastClustering(N)` |
|
||||||
|
| M3 | TitaNet small | счетчик, выбранный для TitaNet, + `FastClustering(N)` |
|
||||||
|
|
||||||
|
M1 намеренно отсутствует: отдельный контроль `Prepare/Finalize` перенесен в
|
||||||
|
дешевую проверку этапа 0 и не получает CPU-ячейку.
|
||||||
|
|
||||||
|
M0, M2 и M3 получают по одному прогону трех фрагментов. Быстрая модель проходит
|
||||||
|
дальше, если выдерживает обязательные условия и достигает порога продолжения
|
||||||
|
относительно M0. Малая разница не уточняется дополнительными повторами.
|
||||||
|
Регрессия диагностических метрик требует прослушать отмеченные пятиминутные
|
||||||
|
случаи до сборки комбинации.
|
||||||
|
|
||||||
|
### Этап 3. Проверить исполнение эмбеддингов на Intel
|
||||||
|
|
||||||
|
#### QDQ WeSpeaker
|
||||||
|
|
||||||
|
S8S8 QDQ сравнивается с FP32 на Intel при шаге `0.1`; достаточно одного A/B по
|
||||||
|
трем фрагментам. Если QDQ проходит обязательные условия и проверку памяти, он
|
||||||
|
остается допустимым для C2 даже без порога продолжения на Intel: возможный
|
||||||
|
выигрыш на Ryzen зависит от VNNI/AVX-512. Изолированный Ryzen A/B выполняется
|
||||||
|
уже после handoff, в этапе 5.
|
||||||
|
|
||||||
|
U8U8 допускается как единственный запасной вариант, если S8S8 достигает порога
|
||||||
|
продолжения по времени диаризации, но не проходит качество. Другие форматы
|
||||||
|
квантизации в матрицу не добавляются.
|
||||||
|
|
||||||
|
#### Shared-session streams
|
||||||
|
|
||||||
|
На Intel сравниваются четыре конфигурации при общем бюджете `P`; достаточно
|
||||||
|
одного A/B по трем фрагментам. Лучшая shared-session конфигурация, прошедшая
|
||||||
|
обязательные условия и проверку памяти, остается допустимой для C2 даже без
|
||||||
|
порога продолжения. Изолированный Ryzen A/B выполняется в этапе 5.
|
||||||
|
|
||||||
|
| Ячейка | Outer workers | Intra-op | Session |
|
||||||
|
|---|---:|---:|---|
|
||||||
|
| E0 | `1` | `P` | одна, текущий внутренний параллелизм |
|
||||||
|
| E1 | `2` | общий pool `P` | одна |
|
||||||
|
| E2 | `P` | `1` | одна |
|
||||||
|
| E3 | `P` | `1` на session | отдельные session, отрицательный контроль |
|
||||||
|
|
||||||
|
`inter_op_threads=1` во всех ячейках. Измеряется время полного набора
|
||||||
|
embedding-вызовов. Latency одного удачного stream для решения не используется.
|
||||||
|
E3 не становится кандидатом, если только не опровергает ожидаемый рост RSS и не
|
||||||
|
выигрывает у shared-session по времени диаризации.
|
||||||
|
|
||||||
|
#### Batch TitaNet
|
||||||
|
|
||||||
|
Batch TitaNet открывается только после прохождения M3. Сначала сравниваются batch
|
||||||
|
`1` и `4` на одинаковом наборе переменных длин. Batch проходит к CPU-замеру,
|
||||||
|
если сохраняет число кластеров, метки строк и итоговую разметку на всех трех
|
||||||
|
контрольных матрицах. CAMPPlus batch и подбор размера больше `4` отложены.
|
||||||
|
|
||||||
|
### Этап 4. Собрать комбинации на Intel
|
||||||
|
|
||||||
|
Полного декартова перебора нет. На Intel собираются максимум три явно заданные
|
||||||
|
комбинации:
|
||||||
|
|
||||||
|
| Ячейка | Состав |
|
||||||
|
|---|---|
|
||||||
|
| C0 | рабочий шаг + WeSpeaker FP32 + последовательный инференс |
|
||||||
|
| C1 | рабочий шаг + сильнейшая ветвь по Intel |
|
||||||
|
| C2 | рабочий шаг + заранее определенный ISA-стек |
|
||||||
|
|
||||||
|
Для C1 рассматриваются ветви, достигшие порога продолжения на Intel; сильнейшая
|
||||||
|
определяется по сокращению времени диаризации. C2 начинается с рабочего шага и
|
||||||
|
WeSpeaker FP32. Если QDQ выдержал обязательные условия и память, он заменяет
|
||||||
|
FP32 независимо от скорости на Intel. Затем добавляется лучшая допустимая
|
||||||
|
shared-session конфигурация для WeSpeaker. Если ни QDQ, ни shared-session не
|
||||||
|
допустимы, C2 собирается как совместимый стек прошедших Intel-ветвей. Так
|
||||||
|
ISA-кандидаты доходят до Ryzen без предварительного Ryzen-замера. Batch совместим
|
||||||
|
только с TitaNet. Если C1 и C2 совпадают, дубликат не запускается. C0 совпадает
|
||||||
|
с baseline и тоже не запускается, если рабочим остался шаг `0.1`.
|
||||||
|
|
||||||
|
Каждая существующая комбинация получает один прогон трех фрагментов на Intel.
|
||||||
|
Все комбинации, выдержавшие обязательные условия и память, передаются в handoff;
|
||||||
|
их остается не больше трех. Если прошел только новый шаг окна, передается один
|
||||||
|
C0. Если новых комбинаций нет, Intel-агент фиксирует `stop-before-ryzen`:
|
||||||
|
Ryzen-задача подтверждает итог по handoff и не запускает модели.
|
||||||
|
|
||||||
|
### Этап 5. Принять финалиста на Ryzen
|
||||||
|
|
||||||
|
Ryzen-агент начинает с восстановления handoff. Если передано ноль кандидатов и
|
||||||
|
Intel-итог равен `stop-before-ryzen`, после проверки commit, SHA-256 капсулы и
|
||||||
|
`--validate-only` он фиксирует итог `stop` и закрывает задачу без запуска
|
||||||
|
моделей. При наличии кандидатов агент воспроизводит совпадающий baseline и
|
||||||
|
выполняет изолированные QDQ и shared-session A/B для используемых механизмов.
|
||||||
|
Каждый такой A/B состоит из одного прогона baseline и одного прогона кандидата
|
||||||
|
на трех фрагментах. Порядок baseline и кандидата меняется между парами. Эти A/B
|
||||||
|
проверяют обязательные условия и объясняют вклад механизма. Проигрыш по скорости
|
||||||
|
сам по себе не снимает переданную комбинацию; до первичного A/B она выбывает
|
||||||
|
только при нарушении обязательных условий или правила памяти.
|
||||||
|
|
||||||
|
Затем первичный A/B получают все переданные комбинации, но не больше трех.
|
||||||
|
Каждый A/B состоит из одного прогона baseline и одного прогона кандидата на трех
|
||||||
|
фрагментах. Порядок меняется для следующей пары. Вариант, который нарушает
|
||||||
|
обязательные условия или не достигает порога продолжения, выбывает без
|
||||||
|
дополнительных прогонов.
|
||||||
|
|
||||||
|
Не больше двух лучших вариантов, прошедших первичный A/B, получают по пять
|
||||||
|
чередующихся A/B-циклов. Они выбираются по времени диаризации, при равенстве по
|
||||||
|
скорости - по меньшему RSS, затем по меньшему числу отличий от baseline. При
|
||||||
|
полном равенстве порядок C0, C1, C2 служит последним тай-брейком. Один цикл
|
||||||
|
содержит все три фрагмента; результат цикла - сумма времени диаризации. Итогом
|
||||||
|
служат медиана пяти парных ускорений и MAD. Доверительные интервалы и новые
|
||||||
|
повторы после пяти циклов не требуются.
|
||||||
|
|
||||||
|
Итоговая комбинация проходит условие скорости, если достигает итогового порога
|
||||||
|
на Ryzen. Примерно двукратное ускорение остается ориентиром. На Intel процент
|
||||||
|
допустимого замедления заранее не задается. Если финалист медленнее Intel
|
||||||
|
baseline минимум на порог продолжения, эксперимент возвращает `needs-decision`
|
||||||
|
вместо автоматического `go`: приемлемость фактической регрессии решает владелец
|
||||||
|
после замеров.
|
||||||
|
|
||||||
|
### Этап 6. Проверить полные записи
|
||||||
|
|
||||||
|
Один победитель и совпадающий baseline 1.13.6 однократно обрабатывают три полные
|
||||||
|
записи на Ryzen. Эти прогоны проверяют перенос результата за границы
|
||||||
|
пятиминутных фрагментов; единственное время полного прогона не заменяет
|
||||||
|
итоговый порог скорости.
|
||||||
|
|
||||||
|
В слуховой проверке baseline и кандидат сопоставляются по пяти группам:
|
||||||
|
|
||||||
|
- короткие ответы и перебивки;
|
||||||
|
- смены говорящего;
|
||||||
|
- перекрывающуюся речь;
|
||||||
|
- устойчивость соответствия голоса кластеру;
|
||||||
|
- слова без говорящего и малые остаточные кластеры.
|
||||||
|
|
||||||
|
Вердикт и краткие причины сохраняются в приватной капсуле. Публичный отчет
|
||||||
|
содержит только итог `пройдено` или `не пройдено` по каждой категории.
|
||||||
|
|
||||||
|
## Метрики
|
||||||
|
|
||||||
|
### Работа и скорость
|
||||||
|
|
||||||
|
Для каждой ячейки сохраняются:
|
||||||
|
|
||||||
|
- wall time, user/system/total CPU, средняя загрузка ядер и RTF;
|
||||||
|
- времена segmentation, embeddings, clustering и всего вызова;
|
||||||
|
- фактический шаг, число segmentation-окон и embedding-заданий;
|
||||||
|
- число строк подготовленной матрицы, выбранные `p` и `N`, время счетчика;
|
||||||
|
- число embedding-вызовов, batch, workers, session и бюджеты потоков.
|
||||||
|
|
||||||
|
### Качество
|
||||||
|
|
||||||
|
Обязательные условия:
|
||||||
|
|
||||||
|
- точное число кластеров `3 / 2 / 2` на контрольных фрагментах;
|
||||||
|
- неизменный распознанный текст с точностью до прежней нормализации пробелов;
|
||||||
|
- повторяемые `p`, `N`, метки строк и финализация на одной матрице;
|
||||||
|
- конечные эмбеддинги и отсутствие потерь или дублей входов.
|
||||||
|
|
||||||
|
Диагностика:
|
||||||
|
|
||||||
|
- `mapped speaker purity` на двух записях с опорной разметкой;
|
||||||
|
- число слов без говорящего;
|
||||||
|
- число и длительность малых кластеров;
|
||||||
|
- доля времени речи в кластерах сверх ожидаемых;
|
||||||
|
- доля назначенных слов в тех же кластерах.
|
||||||
|
|
||||||
|
Последние два показателя получают разные имена и единицы. Дополнительными
|
||||||
|
считаются кластеры после `N` крупнейших по времени речи. Доля времени использует
|
||||||
|
общее время речи в знаменателе, доля слов - все слова, назначенные известным
|
||||||
|
кластерам.
|
||||||
|
|
||||||
|
Прокси-метрики не получают произвольных жестких порогов. Ухудшение purity или
|
||||||
|
рост слов без говорящего относительно совпадающего baseline помечает случаи для
|
||||||
|
слуховой проверки. Победитель не принимается, если слуховая проверка
|
||||||
|
подтверждает регрессию коротких реплик, смен говорящего или устойчивости
|
||||||
|
кластеров.
|
||||||
|
|
||||||
|
ASR выполняется один раз при подготовке sidecar и не входит в измеряемые ячейки.
|
||||||
|
Каждая ячейка использует тот же набор слов. Проверка неизменности текста
|
||||||
|
сравнивает сборку слов после назначения говорящих с sidecar и ловит потерю,
|
||||||
|
дубль или перестановку слов; она не запускает ASR повторно.
|
||||||
|
|
||||||
|
### Память и машина
|
||||||
|
|
||||||
|
Для каждого запуска фиксируются точный SKU, физические и логические ядра, RAM,
|
||||||
|
CPUID/ISA, ОС, версии библиотек, питание, power mode, governor, turbo, power
|
||||||
|
limits, температуры, throttling, swap и число потоков.
|
||||||
|
|
||||||
|
Обе машины работают от сети в стабильном `balanced`-режиме. A/B чередуются,
|
||||||
|
чтобы прогрев не давал преимущества одному варианту. Прогон с throttling
|
||||||
|
или сменой режима питания не учитывается и повторяется один раз после
|
||||||
|
стабилизации. Абсолютный температурный порог не задается.
|
||||||
|
|
||||||
|
Peak RSS записывается для каждой ячейки и сравнивается с baseline той же машины.
|
||||||
|
RSS выше 2 ГиБ на машине с 16 ГиБ RAM требует разбора, но сам по себе не
|
||||||
|
отбрасывает вариант. Правило памяти останавливает ячейку при OOM, активной
|
||||||
|
подкачке, росте RSS между повторами без плато или линейном росте памяти с числом
|
||||||
|
workers или session.
|
||||||
|
|
||||||
|
## Правила решения
|
||||||
|
|
||||||
|
Результаты рассматриваются в таком порядке:
|
||||||
|
|
||||||
|
1. обязательные условия качества и корректности;
|
||||||
|
2. медианное сокращение времени диаризации на Ryzen;
|
||||||
|
3. память;
|
||||||
|
4. сложность будущей реализации и сопровождения.
|
||||||
|
|
||||||
|
Практически незначимая разница не получает дополнительных прогонов. При
|
||||||
|
равенстве по скорости выбирается более простой и экономный по памяти вариант.
|
||||||
|
Ни один экспериментальный результат автоматически не меняет production-профиль.
|
||||||
|
|
||||||
|
`stop-before-ryzen` - промежуточный итог Intel-этапа; после проверки handoff он
|
||||||
|
становится итогом `stop`. `needs-info` - состояние заблокированной задачи, а не
|
||||||
|
результат эксперимента.
|
||||||
|
|
||||||
|
Возможны четыре итоговых исхода:
|
||||||
|
|
||||||
|
- `go`: один вариант достигает итогового порога на Ryzen и проходит все
|
||||||
|
проверки;
|
||||||
|
- `needs-decision`: Ryzen проходит итоговый порог, но Intel показывает
|
||||||
|
практически значимую регрессию;
|
||||||
|
- `stop`: baseline 1.13.6 не принят либо ни один вариант не проходит скорость,
|
||||||
|
качество или память; причины сохраняются по каждой ветви;
|
||||||
|
- `new map`: сокращение окон и цены эмбеддинга упирается в качество раньше
|
||||||
|
порога скорости, поэтому отдельно рассматривается end-to-end архитектура.
|
||||||
|
|
||||||
|
## Проверка реализации стенда
|
||||||
|
|
||||||
|
Минимальная автоматическая проверка:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv run pytest -q \
|
||||||
|
tests/test_diarization_calibration.py \
|
||||||
|
tests/test_speaker_diarizer.py \
|
||||||
|
tests/test_diarization.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Тесты должны покрывать новую схему manifest и идентичность ячеек, расписание и
|
||||||
|
повторы, смешанные результаты счетчиков, ветвь только с шагом окна, совместимый
|
||||||
|
стек, наследование происхождения QDQ-материала и запрет общего исходника с
|
||||||
|
контрольными записями, обязательные условия, два показателя остаточных кластеров,
|
||||||
|
контроль общего бюджета потоков, продолжение незавершенного запуска, границу
|
||||||
|
этапов Intel/Ryzen, не больше трех handoff-кандидатов и отсутствие приватного
|
||||||
|
текста в ошибках.
|
||||||
|
|
||||||
|
До моделей выполняются:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv run python scripts/benchmarks/diarization_calibration.py --help
|
||||||
|
|
||||||
|
uv run python scripts/benchmarks/diarization_calibration.py \
|
||||||
|
--manifest /private/path/manifest.json \
|
||||||
|
--validate-only
|
||||||
|
```
|
||||||
|
|
||||||
|
Intel-отчет должен позволять восстановить отсев и точные рецепты переданных
|
||||||
|
комбинаций по агрегатам и хешам. Финальный Ryzen-отчет ссылается на него и
|
||||||
|
добавляет первичный A/B, финальные циклы и решение. Полное воспроизведение
|
||||||
|
использует приватную капсулу из закрытой папки Яндекс Диска.
|
||||||
|
|
||||||
|
## Отклоненные варианты
|
||||||
|
|
||||||
|
- Полный декартов перебор отклонен: большая часть ячеек повторяет уже
|
||||||
|
проигравшие механизмы и не влияет на выбор.
|
||||||
|
- Пять повторов каждой ячейки отклонены: дорогая точность нужна только для
|
||||||
|
финального A/B. Первичный отсев использует порог продолжения.
|
||||||
|
- Только шаг окна отклонен: он не проверяет более дешевые модели и исполнение,
|
||||||
|
которые могут складываться с сокращением работы.
|
||||||
|
- Только современный CPU отклонен: он скрывает регрессии на AVX2 и не дает
|
||||||
|
понять, зависит ли выигрыш от ISA.
|
||||||
|
- Полная матрица на Ryzen отклонена: старый Intel дешевле для первичного отсева.
|
||||||
|
Ryzen получает максимум три комбинации для одного первичного A/B и оставляет
|
||||||
|
максимум две для дорогих циклов.
|
||||||
|
- Сохранение текущего профиля остается допустимым итогом, если практического
|
||||||
|
победителя нет.
|
||||||
|
|
||||||
|
## Критерии завершения задач эксперимента
|
||||||
|
|
||||||
|
- [ ] Стенд и тесты реализуют описанную воронку и не меняют пользовательский
|
||||||
|
контракт диаризации.
|
||||||
|
- [ ] Intel-задача принимает baseline и завершает этапы 0-4 либо фиксирует
|
||||||
|
подтвержденную регрессию как `stop-before-ryzen`; в обоих случаях коммитит
|
||||||
|
обезличенный отчет и публикует полный handoff-комментарий.
|
||||||
|
- [ ] Ryzen-задача начинает с указанного commit и проверенной капсулы, затем
|
||||||
|
воспроизводит свой baseline без возврата к обычным Intel-замерам.
|
||||||
|
- [ ] Все пройденные и остановленные ветви имеют явную причину и ссылку на
|
||||||
|
ячейки результата.
|
||||||
|
- [ ] Финальный A/B завершен либо зафиксировано, почему до него не дошел ни один
|
||||||
|
вариант.
|
||||||
|
- [ ] При наличии победителя выполнена проверка полных записей и слуховая
|
||||||
|
приемка.
|
||||||
|
- [ ] Публичный отчет свободен от приватных данных; полная капсула сохранена
|
||||||
|
только в закрытой папке Яндекс Диска.
|
||||||
|
- [ ] Итог формулирует следующее решение: готовить production-изменение,
|
||||||
|
вынести измеренную регрессию на Intel на решение владельца, сохранить текущий
|
||||||
|
профиль или открыть новую карту end-to-end диаризации.
|
||||||
Reference in new issue
Block a user