Files
local-transcriber/docs/backlog.md
T
Dmitriy DementievandClaude Opus 5 7e348e400f 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>
2026-08-12 15:22:51 +03:00

25 KiB
Raw Blame History

Backlog — будущие эксперименты и направления

Список открытых направлений, которые имеют смысл, но не реализованы. Каждый пункт содержит обоснование и ссылку на источник (ADR / статья), чтобы при возврате не пришлось воспроизводить контекст с нуля.

Когда направление становится в работу — переносится в spec/план или соответствующий ADR. Когда отклоняется — остаётся в backlog с пометкой «отклонено» и причиной (для истории решений).


ASR-бэкенды и модели

Переоценка CPU-дефолта после обновления onnx-asr 0.12

Промежуточный статус 2026-08-11: короткая матрица на трёх записях завершена и описана в benchmark GigaAM и Whisper. Multilingual Large добавлена как явный качественный профиль; решение о default по-прежнему ждёт целевого Intel Core i5 и длинных негативных примеров.

Проблема: текущий CPU-путь через OpenVINO Whisper medium нестабилен на длинных записях с тихими участками: модель генерирует правдоподобные повторы и несуществующий текст. На файле 2026-07-29 13-58-39.mp4 разговор заканчивается примерно на 02:28, после чего OpenVINO создаёт десятки повторяющихся блоков до конца 59-минутной записи. Изолированный тест окна 02:00–03:30 дал одинаковую серию из 14 повторов на openvino-genai 2026.0 и 2026.3; обновление движка само по себе проблему не устраняет. Подробнее — в пункте «Whisper medium галлюцинации».

Порядок работы:

  1. Сначала обновить совместимый стек по исследованию обновлений: снять ограничение onnx-asr<0.12.0, проверить VAD и квантованные модели; OpenVINO и OpenVINO GenAI обновлять согласованно. Не фиксировать ONNX Runtime 1.28 для Python 3.10. Шаг 1 в части onnx-пути вынесен в отдельную работу — спека «Onnx-каталог, Python 3.13 и границы версий»: движок обновляется, четыре модели становятся поддерживаемыми, дефолт и OpenVINO не трогаются намеренно, чтобы сохранить точку отсчёта для будущего сравнения.
  2. После интеграционных тестов провести сравнительный бенчмарк моделей. Не менять CPU-дефолт только по model card или результату на одном файле.
  3. Решение зафиксировать в ADR-007, обновить рекомендации README и только затем менять auto-detect/defaults.

Кандидаты:

  • gigaam-v3-ctc — текущий baseline для русского CPU.
  • gigaam-v3-rnnt — контекстный декодер без пунктуации.
  • gigaam-v3-e2e-ctc и gigaam-v3-e2e-rnnt — варианты с пунктуацией и нормализацией текста.
  • gigaam-multilingual-ctc и gigaam-multilingual-large-ctc, добавленные в onnx-asr 0.12 — кандидаты для смешанной речи, но не априори для русского дефолта.
  • OpenVINO medium + VAD — альтернатива смене модели, сохраняющая Whisper и пунктуацию.
  • Parakeet v3 — контрольный multilingual-вариант, но не кандидат на русский дефолт без новых данных, опровергающих ADR-005/006.

Матрица качества:

  • те же три полные записи и четыре критерия agent-judge из ADR-006: completeness, term accuracy, fluency, summary utility;
  • новый негативный пример 2026-07-29 13-58-39.mp4 с длинной тишиной;
  • небольшой вручную проверенный набор сложных фрагментов для WER/CER и разбора критичных смысловых ошибок: тихие реплики, имена компаний, латиница и IT-термины, числа, русско-английское переключение;
  • автоматические проверки потери хвоста, повторов, пустых/нулевых VAD-сегментов и выдуманного текста на тишине.

Матрица производительности:

  • обязательный прогон на реальном Intel Core i5 11-го поколения; точный SKU, число ядер, объём RAM, power mode и число потоков записать вместе с результатом;
  • Ryzen 7 8845H разработчика и ограничение числа потоков использовать только для предварительного smoke-теста, не как приёмку производительности i5;
  • измерять отдельно cold start/загрузку модели и warm transcription, медиану трёх прогонов, RTFx, peak RSS и размер скачиваемой модели;
  • короткий 15-минутный фрагмент нужен для итераций, полные записи 22–81 мин — для итогового решения и проверки устойчивости.

Почему интересно:

  • WER 2.6% vs 13.2% для CTC на сложных текстах — в 5 раз ниже на разговорной речи и доменной лексике (источник: SberDevices / Хабр-публикация GigaAM-v3).
  • Контекстный декодер — структурно решает основную проблему GigaAM-CTC из ADR-006: кириллизация латиницы и искажения имён компаний (ЗапромбанкГазпромбанк, яндекс тим под яндекс тимЯндекс ТимКод). RNN-T видит контекст уже сгенерированных токенов и может «дотянуть» имена.
  • v3_e2e_rnnt с пунктуацией и нормализацией — закрывает главное ограничение GigaAM-CTC, ради которого в README сейчас стоит fallback на openvino-cpu medium (с задокументированными в ADR-006 галлюцинациями на длинных файлах).
  • 70:30 vs Whisper-large-v3 — GigaAM-v3 (CTC и RNN-T) выигрывает у large-v3 по LLM-as-Judge (Gemini 2.5 Pro). Если переносится на наш use case — RNN-T на CPU становится сильнее GPU faster-whisper large-v3.
  • 30% лучше на «новых доменах» (callcenter-like речь, нестандартные характеристики) — это и есть домен установочных встреч.

Tradeoff:

  • Скорость ниже CTC (RNN-T декодинг последовательный). Реалистичная оценка: 10-15× RTF на CPU вместо 17-29× у CTC. Всё ещё в 1.5-2× быстрее Whisper medium.
  • Размер модели больше (~500 MB int8 против ~300 MB у CTC) — оценка, нужна верификация.

Если подтвердится бенчмарком:

  • Если E2E RNN-T сохраняет качество и приемлемую скорость на i5 — сделать его русским CPU-дефолтом, OpenVINO оставить явной опцией.
  • Если лучший вариант зависит от языка — выбрать language-aware default: GigaAM v3 для русского, multilingual-модель для смешанной речи.
  • Если модели GigaAM проигрывают по пунктуации/смыслу — сохранить текущий model default и лечить OpenVINO через VAD/качественный pipeline.
  • Если ни один вариант не проходит порог качества и скорости — не менять дефолт, оставить предупреждения и явный выбор backend.

Canary 1B — multilingual + пунктуация на CPU

Что: Протестировать nemo-canary-1b-v2 через onnx-asr на тех же 3 файлах.

Почему: Multilingual + пунктуация в одной модели. Кандидат на «лучшее качество за разумную скорость» для пользователей, которым нужны и не-русский контент, и пунктуация одновременно. Упомянут в ADR-006.

Tradeoff: Тяжелее GigaAM (~1 GB vs ~300 MB), скорость на CPU ожидаемо ниже. Если RNN-T закроет потребность в пунктуации — Canary становится менее приоритетным.


Качество и устойчивость

Whisper medium галлюцинации на длинных файлах с тихими фрагментами

Статус: воспроизведено 2026-08-10. Помимо примеров из ADR-006, на записи 2026-07-29 13-58-39.mp4 минимальный тест 02:00–03:30 стабильно получает 14 одинаковых сегментов после окончания речи. На 30-секундном окне только с речью повторов нет. openvino-genai 2026.3 и no_repeat_ngram_size=3 результат не меняют. Корень проблемы — длинные безречевые участки, которые текущий OpenVINO backend целиком передаёт в WhisperPipeline без VAD.

Возможные направления:

  • Добавить VAD перед OpenVINO WhisperPipeline и сохранить исходные таймкоды — наиболее прямое лечение подтверждённой причины.
  • Ограничить длину чанка для openvino-medium (chunk_length параметр в WhisperPipeline).
  • Внедрить compression_ratio_threshold / log_prob_threshold фильтры через переписывание pipeline (как у CTranslate2). Уже частично описано в docs/gpu.md «Качественный pipeline для OpenVINO».
  • Переключить русский CPU-дефолт на победителя сравнительного GigaAM-бенчмарка.
  • Предупреждать пользователя при --device openvino-cpu для файлов >30 мин.

Приоритет: высокий — проблема затрагивает текущий OpenVINO CPU-путь, а целевая аудитория включает ноутбуки с Intel Core i5 11-го поколения. GigaAM v3 остаётся рабочей явной альтернативой для русского, но выбор безопасного auto/default требует сравнительного бенчмарка.


Интеллектуальное чанкование длинных файлов по паузам

Что: Резать длинные файлы на чанки (~90 с) не по фиксированной сетке, а по ближайшей тишине: ffmpeg -af silencedetect=noise=-40dB:d=0.5 → парсинг stderr → выбор точки разреза в окне ±30 с вокруг целевой границы (с минимальным зазором между разрезами, чтобы не получить нулевые чанки).

Почему: Разрез посреди слова/фразы портит распознавание на границах чанков; разрез по паузе — нет. Потенциально смягчает класс ошибок Whisper medium на длинных файлах (потеря хвоста, блоки повторов — см. пункт выше): короткие чанки не дают декодеру «уплыть».

Источник: референсная реализация Parakeet-сервера (Flask, OpenAI-совместимый API), лежавшая в репо как app.py в период эксперимента ADR-005/006 (апрель 2026); удалена при чистке 2026-07-09 — рабочие константы: порог -40dB, мин. тишина 0.5 с, окно поиска 30 с, мин. зазор 5 с.

Tradeoff: дополнительный проход ffmpeg по всему файлу (silencedetect) перед транскрипцией; для часового файла — десятки секунд.


Качественный pipeline для OpenVINO (temperature fallback + фильтры)

Что: Реализовать temperature fallback, compression_ratio и log_prob фильтры поверх OpenVINO GenAI WhisperPipeline. Эвристики — логика на Python (~50-100 строк), не зависящая от inference engine.

Почему: Дать Intel Arc / AMD GPU и AMD CPU то же качество, что сейчас есть только у CUDA-пользователей через CTranslate2. Полностью описано в docs/gpu.md.


Структура транскрипта (конспекты и MoM)

Источник раздела: внешнее сравнение локального транскрипта (medium, openvino-cpu, запись 25:59) с облачным сервисом Hypescribe, критерий — пригодность как сырья для конспекта и протокола встречи (GPT-ревью, 2026-07-10). Итог: по смыслу локальная модель почти равна облаку (6.5/10 против 7/10), главный разрыв — не качество распознавания, а структура: разделение говорящих (2/10 против 8/10) и нарезка на реплики. Приоритеты ревьюера: 1) смысл, 2) спикеры, 3) техтермины, 4) разбивка на фразы, 5) таймкоды. Вывод: локальная диаризация + словарь терминов закрывают потребность в облачном сервисе для внутренних встреч.

Сознательно вне ядра CLI (максимум — рецепт в README): второй проход LLM для чистки текста, сопоставление Speaker N с именами — это работа поверх готового транскрипта.

Диаризация — разделение говорящих

Что: Опциональный пост-процессинг (не четвёртый бэкенд): диаризация даёт интервалы «кто когда говорил», результат сводится с сегментами ASR, formatter ломает абзац на смене спикера и подписывает Speaker 1:. Ставится как extra: uv sync --extra diarization.

Почему: Без спикеров MoM не собрать — это ключевой разрыв с облаком по внешнему ревью, и никакое качество распознавания его не компенсирует. Заодно естественно решает «разбивку на реплики» (приоритет №4).

Промежуточный статус 2026-08-12: проведена разведка, описанная в разведочном замере диаризации. Она закрыла вопрос о движке и открыла более важный вопрос о единице привязки.

Движок — вопрос практически закрыт. sherpa-onnx ставится на Windows с Python 3.13, содержит готовый OfflineSpeakerDiarization, не тянет torch и не требует токена Hugging Face; модели сегментации и эмбеддингов весят около 33 МБ. Скорость — 11,1× RTFx, то есть примерно полторы длительности ASR. Вариант pyannote.audio остаётся отклонённым по прежней причине: torch и HF-токен с принятием лицензии. Отдельный ADR имеет смысл заводить вместе с решением о единице привязки, а не только про движок.

Замечание для будущих заходов: обе 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.


Ручка нарезки абзацев в formatter

Что: «Минутные простыни» в транскрипте — не свойство модели, а наши константы группировки _PAUSE_THRESHOLD_S = 2.0 / _MAX_PARAGRAPH_S = 60.0 в formatter.py (сырых сегментов много: 23-минутная запись — 360 сегментов, ~4 с на реплику). Вынести в опцию/конфиг или уменьшить дефолт.

Почему откладывается: при диаризации абзацы будут ломаться по смене спикера естественно — сначала решить с диаризацией, чтобы не делать ручку, которая устареет.


Словарь замен технических терминов — запасной план

Что: Пост-обработка текста сегментов словарём замен по границам слов (CSW → CSV, софтп → SFTP, ямлик → YAML, Spark и Scale → Spark SQL), словарь пользовательский в .transcriber.toml.

Почему запасной: это тот же класс ошибок, что «кириллизация латиницы и искажение имён» из ADR-006, и первым его должен попробовать закрыть контекстный декодер GigaAM v3 RNN-T (первый пункт бэклога). Заводить словарь — только если бенчмарк RNN-T термины не вытянет.


Авто-детект и UX

Профили намерения вместо выбора модели

Что: Вместо --model gigaam-v3-e2e-rnnt пользователь выбирает намерение — условные ru-fast, ru-readable, mixed, — а проект разворачивает его в пару модель + квантизация с учётом устройства.

Почему: Имена onnx-моделей ничего не говорят о том, что получит пользователь, и различие «поддерживаемая модель ≠ рекомендуемая» через них не выражается.

Почему откладывается: профиль осмыслен, когда известно, какой профиль чем закрывается — то есть после сравнительной оценки. Введение понятия раньше данных закрепит догадку в интерфейсе. Источник: спека «Onnx-каталог, Python 3.13 и границы версий».


large-v3-turbo для faster-whisper

Что: Добавить large-v3-turbo в каталог faster-whisper, чтобы модель была доступна с --device cuda и --device cpu, а не только через OpenVINO.

Почему: На CPU turbo INT8 оказался быстрее medium и точнее по WER (сравнение от 2026-08-12), и владельцам NVIDIA этот профиль сейчас недоступен без ручного указания репозитория HuggingFace.

Почему откладывается: каталог faster-whisper в проекте собран из репозиториев Systran, и для turbo нужно сначала выяснить, какая CT2-сборка годится, проверить её происхождение и качество, и только потом вносить в код.


Отклонённые направления

(пока пусто — добавлять сюда то, что попробовали и решили не делать, с причиной)