docs(diarization): добавлен разведочный замер и пересмотрен бэклог

- Зачем:
  - схема из бэклога приписывала спикера целому ASR-сегменту, и до замера
    было неизвестно, насколько сильно это огрубляет результат.
- Что:
  - добавлен разведочный замер sherpa-onnx на одной записи: 11,1x RTFx против
    16,4x у ASR, свип порога кластеризации и доля загрязнённых сегментов.
  - пункт бэклога переписан: движок описан как практически закрытый вопрос,
    главной развилкой названа единица привязки спикера к тексту.
  - зафиксировано, что 27% сегментов содержат не менее секунды чужой речи и на
    них приходится больше половины времени транскрипта.
- Проверка:
  - методика и условия замера воспроизводятся по разделам «Оборудование и
    условия» и «Контрольная запись» в docs/benchmarks/2026-08-12-diarization-feasibility.md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dmitriy Dementiev
2026-08-12 15:22:51 +03:00
co-authored by Claude Opus 5
parent 3378aac474
commit 7e348e400f
2 changed files with 240 additions and 14 deletions
+43 -14
View File
@@ -181,27 +181,56 @@ LLM для чистки текста, сопоставление Speaker N с и
### Диаризация — разделение говорящих
**Что:** Опциональный пост-процессинг (не четвёртый бэкенд): сегменты
уже несут таймкоды; диаризация даёт интервалы «кто когда говорил»;
merge по перекрытию интервалов; formatter ломает абзац на смене спикера
и подписывает `Speaker 1:`. Ставится как extra:
`uv sync --extra diarization`.
**Что:** Опциональный пост-процессинг (не четвёртый бэкенд): диаризация
даёт интервалы «кто когда говорил», результат сводится с сегментами ASR,
formatter ломает абзац на смене спикера и подписывает `Speaker 1:`.
Ставится как extra: `uv sync --extra diarization`.
**Почему:** Без спикеров MoM не собрать — это ключевой разрыв с облаком
по внешнему ревью, и никакое качество распознавания его не компенсирует.
Заодно естественно решает «разбивку на реплики» (приоритет №4).
**Варианты реализации (ключевое решение, нужен ADR):**
**Промежуточный статус 2026-08-12:** проведена разведка, описанная в
[разведочном замере диаризации](benchmarks/2026-08-12-diarization-feasibility.md).
Она закрыла вопрос о движке и открыла более важный вопрос о единице привязки.
- **sherpa-onnx** — диаризация целиком на onnxruntime (сегментация
pyannote в ONNX + спикер-эмбеддинги), без torch, в духе нашего
onnx-стека и «no cloud, no API keys».
- **pyannote.audio** — стандарт качества, но тянет torch и требует
HF-токен с принятием лицензии моделей — трение с духом проекта.
**Движок — вопрос практически закрыт.** `sherpa-onnx` ставится на Windows с
Python 3.13, содержит готовый `OfflineSpeakerDiarization`, не тянет torch и не
требует токена Hugging Face; модели сегментации и эмбеддингов весят около 33 МБ.
Скорость — 11,1× RTFx, то есть примерно полторы длительности ASR. Вариант
`pyannote.audio` остаётся отклонённым по прежней причине: torch и HF-токен с
принятием лицензии. Отдельный ADR имеет смысл заводить вместе с решением о
единице привязки, а не только про движок.
**Уточнить перед запуском:** качество обоих вариантов на русской речи
и перекрывающихся репликах; скорость на CPU (диаризация — второй проход
по всему аудио); лицензии моделей сегментации/эмбеддингов.
Замечание для будущих заходов: обе ML-части диаризации уже лежат в
`onnx-asr` 0.12 — `PyAnnoteVad` содержит полную локальную сегментацию pyannote
(powerset на трёх спикеров, склейка окон), а `WespeakerEmbeddings` даёт
эмбеддинги. Публичный API схлопывает сегментацию до речь/не-речь, `load_se` не
экспортирован, кластеризации нет. Собирать диаризацию самим на этих деталях —
экономия 33 МБ ценой опоры на приватный API; при разведке этот путь не
выбирался.
**Единица привязки — настоящая развилка, решения нет.** Схема «мажоритарный
спикер на весь ASR-сегмент», записанная здесь раньше, замером не подтвердилась:
27% сегментов содержат не менее секунды чужой речи, и на них приходится больше
половины времени транскрипта. Причина — границы сегментов идут по тишине
(Silero VAD), а в ВКС собеседники отвечают встык. Варианты:
- **пословная привязка** — `onnx-asr` отдаёт потокенные таймкоды
(`TimestampedResult`), сегмент режется на границе токена при смене
говорящего; ASR по-прежнему видит длинное аудио, контекст RNN-T и пунктуация
не страдают. Недоступно на OpenVINO GenAI — там потокенных таймкодов нет;
- **диаризация первым проходом**, ASR по интервалам говорящего — чистота
гарантирована, но короткие куски лишают RNN-T контекста и портят пунктуацию;
- **привязка к сегменту с честной пометкой** — оставить огрубление, но считать
чистоту и предупреждать в шапке, как уже делается для повторов и потери
хвоста.
**Уточнить перед запуском:** воспроизводится ли доля 27% на других записях,
включая разговор на двоих; правильность границ диаризации на слух, а не только
совпадение числа говорящих; калибровка порога кластеризации (на пороге из
примеров получилось 29 спикеров вместо трёх); эмбеддинги, обученные не только
на английском; производительность на целевом Intel Core i5.
---