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