Files
local-transcriber/docs/benchmarks/2026-08-12-diarization-feasibility.md
Dmitry Dementiev 99ddf77af3 perf(diarization): добавлен замер на старом Intel
- Зачем:
  - требовалось оценить стоимость опциональной диаризации на доступном слабом Intel baseline.
- Что:
  - зафиксированы ASR, RTFx и peak RSS на трёх контрольных записях.
  - замер peak RSS адаптирован для Linux и macOS.
  - недоступный Core i5 явно заменён Core i7-6820HQ с сохранением ограничения применимости.
- Проверка:
  - uv run ruff check .scratch/diarization/common.py.
  - uv run pytest -q: 243 passed, 1 skipped.
2026-08-14 13:37:07 +03:00

200 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Разведочный замер диаризации sherpa-onnx
**Дата:** 2026-08-12
**Статус:** разведка на одной записи и одной нецелевой машине. Не приёмка.
## Цель
Ответить на два вопроса перед проектированием диаризации:
1. Сколько времени диаризация добавляет к транскрипции.
2. Достаточно ли приписывать спикера целому ASR-сегменту по мажоритарному
перекрытию — то есть допустима ли схема из
[бэклога](../backlog.md#диаризация--разделение-говорящих) без пословной
привязки.
Ни модель по умолчанию, ни код проекта в рамках замера не менялись. Все скрипты
выполнялись вне репозитория.
## Ограничения замера
Результаты ниже — разведка, а не основание для решения:
- **одна запись** вместо трёх, принятых в [ADR-006](../adr/006-onnx-asr-backend.md);
- **нецелевая машина**: AMD Ryzen 7 8845H, тогда как приёмка производительности
по бэклогу требует Intel Core i5 11-го поколения;
- **границы диаризации не проверены на слух** — сверялось только число
говорящих и косвенный текстовый признак;
- **порог кластеризации подобран по этой же записи**, то есть на ней же и
проверен.
## Оборудование и условия
- ноутбук Lenovo 83D5 (та же машина, что в
[сравнении turbo](2026-08-12-openvino-large-v3-turbo-comparison.md#повторный-прогон-на-amd-ryzen-7-8845h));
- AMD Ryzen 7 8845H, 8 ядер / 16 логических процессоров;
- 29,8 ГиБ LPDDR5X;
- Windows 11 Корпоративная, сборка 26200, схема питания «Сбалансированная»;
- Python 3.13.13, `onnx-asr` 0.12.0, `onnxruntime` 1.28.0,
`faster-whisper` 1.2.1, `sherpa-onnx` 1.13.5;
- прогоны последовательные, без конкурирующей нагрузки;
- модели предварительно скачаны; время загрузки моделей в замер не входит.
## Контрольная запись
| Файл | Длительность | Размер | SHA-256 |
|---|---|---|---|
| `2026-07-10 Data Test внутренний статус.mp4` | 26:00 | 34 217 769 | `1057616B42E8ADD00E0EB975B02BDEF0EC9F6CDFEC6DBF488E0C60423C9B7B87` |
Запись выбрана потому, что рядом лежит согласованный MoM, из которого известен
состав: **три участника** — Маша, Дима, Роман. Это даёт независимую опорную
точку для проверки числа говорящих.
## Модели диаризации
| Роль | Модель | Размер | Источник |
|---|---|---|---|
| Сегментация | `sherpa-onnx-pyannote-segmentation-3-0` | 6,9 МБ | релизы `k2-fsa/sherpa-onnx` |
| Эмбеддинги | `wespeaker_en_voxceleb_resnet34_LM.onnx` | 26,5 МБ | релизы `k2-fsa/sherpa-onnx` |
Обе загружаются в `onnxruntime`, torch и токен Hugging Face не требуются.
Эмбеддинги обучены на англоязычном VoxCeleb; их пригодность для русской речи в
этом замере не проверялась.
## Стоимость по времени
Параметры ASR — модель по умолчанию ONNX-пути, `gigaam-v3-e2e-rnnt` INT8,
язык задан явно.
| Стадия | Время | RTFx |
|---|---:|---:|
| Декодирование аудио | 1,6 с | ~990× |
| ASR `gigaam-v3-e2e-rnnt` INT8 | 95,3 с | 16,4× |
| Диаризация, 8 потоков | 140,7 с | 11,1× |
| **Последовательно, итого** | **236 с** | **6,6×** |
Диаризация дороже самой транскрипции и занимает около 60% общего времени. При
последовательном исполнении 26-минутная запись обрабатывается 3,9 минуты вместо
1,6; часовая — примерно 9 минут вместо 3,7.
Масштабирование по потокам слабое: 4 потока дают 154 с, 8 потоков — 141 с,
выигрыш 9%. Закладываться на увеличение числа потоков не следует.
Проходы ASR и диаризации независимы по данным, поэтому их можно совместить во
времени; тогда общее время стремится к максимуму из двух, а не к сумме. Прямой
замер параллельного режима не проводился.
Пиковую память процесса снять не удалось из-за ошибки в измерительном скрипте.
## Порог кластеризации
Число говорящих подбиралось автоматически (`num_clusters=-1`); варьировался
порог `FastClusteringConfig.threshold`.
| Конфигурация | Найдено спикеров | Из них с речью ≥30 с | Речь по спикерам, мин |
|---|---:|---:|---|
| порог 0,5 | 29 | 11 | 7,4 / 5,5 / 1,6 / 1,2 |
| порог 0,7 | 12 | 7 | 7,4 / 7,0 / 2,2 / 2,2 |
| **порог 0,9** | **4** | **3** | **9,6 / 8,1 / 5,7 / 0,3** |
| явное `k=5`, порог 0,5 | 4 | 3 | 9,6 / 8,1 / 5,7 / 0,3 |
На пороге 0,9 число содержательных кластеров совпало с составом из MoM: три
говорящих с 9,6, 8,1 и 5,7 минуты речи плюс остаточный кластер на 0,3 минуты.
На пороге 0,5 получилось 29 говорящих вместо трёх — десятикратное
переразбиение.
Время от порога не зависит (153–157 с во всех конфигурациях): кластеризация
стоит доли секунды, платится за сегментацию и эмбеддинги.
Два следствия. Первое: порог кластеризации — основная ручка качества, и
значение по умолчанию из примеров `sherpa-onnx` для этого материала непригодно.
Второе: одного удачного совпадения на одной записи недостаточно, чтобы принять
0,9 за дефолт, а явное указание числа участников нужно как страховка.
## Чистота ASR-сегментов
Основной вопрос замера. Для каждого из 274 ASR-сегментов посчитано перекрытие
с интервалами каждого говорящего (диаризация на пороге 0,9, 340 интервалов).
Чистота — доля мажоритарного говорящего в суммарном перекрытии сегмента.
| Категория | Сегментов | Доля | Времени |
|---|---:|---:|---:|
| Чистых, один говорящий | 164 | 59,9% | 8,3 мин |
| С поддакиванием, <1 с чужой речи | 30 | 10,9% | 2,4 мин |
| **С чужой репликой, ≥1 с** | **74** | **27,0%** | **11,2 мин** |
| Без спикера вообще | 6 | 2,2% | 0,0 мин |
| Порог чистоты | Сегментов ниже порога | Доля | Времени |
|---|---:|---:|---:|
| < 0,95 | 100 | 36,5% | 13,0 мин |
| < 0,90 | 91 | 33,2% | 11,6 мин |
| < 0,80 | 72 | 26,3% | 9,1 мин |
| < 0,70 | 56 | 20,4% | 7,1 мин |
**27% сегментов содержат не менее секунды чужой речи, и на них приходится
11,2 минуты из 21,9 — больше половины транскрипта.** У 20% сегментов
мажоритарный говорящий занимает менее двух третей сегмента.
### Подтверждение из текста ASR
Загрязнённые сегменты содержат диалог, и это видно независимо от диаризации —
`gigaam-v3-e2e` обучена с диалоговой пунктуацией и сама ставит тире на смене
реплики:
```
[533,8-551,1] 17,3 с, мажоритарный spk3, чистота 0,67
«— В нашем, по-моему.— В нашем?— В нашем.— А, отлично.— Ну, у нас просто
есть некий дата-тест, который на самом деле...— Мы же у них не
разворачиваем.—»
[432,9-448,6] 15,7 с, мажоритарный spk2, чистота 0,58
«Дим, а вот то, что ты из образа вытаскивал, там есть чё-то на что
посмотреть?— Бэг, бэг там есть, пи»
[694,2-706,5] 12,3 с, мажоритарный spk2, чистота 0,37
spk2 = 5,4 с, spk1 = 4,9 с, spk3 = 4,3 с — три человека в одном сегменте
```
Акустическая диаризация и пунктуация ASR указывают на одно и то же, поэтому
доля 27% вряд ли объясняется только ошибками кластеризации.
Причина загрязнения — в способе нарезки: границы сегментов на ONNX-пути даёт
Silero VAD, то есть они проходят по тишине. В разговоре по ВКС участники
отвечают встык, паузы длиной с порог VAD не возникает, и диалог попадает в один
сегмент. Предположение о том, что задержка канала связи сама создаёт паузу на
смене говорящего, этими данными не подтверждается.
Приведённые сегменты — сырой выход ASR. `formatter.py` объединяет их в абзацы
длиной до 60 секунд, поэтому в готовом транскрипте загрязнение будет выше.
## Выводы
- Диаризация через `sherpa-onnx` работает на целевой платформе без torch и без
токена Hugging Face; связка сегментация + эмбеддинги весит около 33 МБ.
- Стоимость — 11,1× RTFx, примерно 1,5 длительности ASR. Последовательный
запуск даёт 2,5-кратное замедление, совмещение проходов может сократить
накладные расходы, но отдельно не измерялось.
- Автоматическая оценка числа говорящих с порогом из примеров даёт 29 спикеров
вместо трёх. Порог требует калибровки, а явное указание числа участников —
отдельной ручки.
- Привязка спикера к целому ASR-сегменту по мажоритарному перекрытию
огрубляет результат существенно: 27% сегментов и больше половины времени
транскрипта содержат чужую речь длиннее секунды. Схема из бэклога в этом виде
непригодна.
- `onnx-asr` отдаёт потокенные таймкоды (`TimestampedResult`), поэтому
пословная привязка на ONNX-пути достижима. У OpenVINO GenAI такого выхода
нет, что ограничивает диаризацию на `--device openvino-*`.
## Что нужно проверить дальше
- Повторить измерение чистоты сегментов ещё на двух-трёх записях, включая
разговор на двоих, и убедиться, что 27% — не свойство именно этой встречи.
- Проверить границы диаризации на слух или сверкой с внешним транскриптом:
совпадение числа говорящих не доказывает правильность интервалов.
- Сравнить эмбеддинги, обученные не только на английском, на русской речи.
- Измерить производительность на доступном слабом Intel baseline — выполнено в
[отдельном отчёте](2026-08-14-diarization-intel-i7.md); конкретный Core i5
11-го поколения недоступен.
- Измерить параллельный режим ASR и диаризации.