Files
local-transcriber/docs/specs/2026-08-11-onnx-model-catalog.md
T
Dmitriy Dementiev 7f58a56913 feat(onnx): изменена модель по умолчанию на GigaAM RNN-T
- Зачем:
  - пользователям нужен читаемый транскрипт без обязательной LLM-обработки.
- Что:
  - моделью ONNX по умолчанию выбрана `gigaam-v3-e2e-rnnt`.
  - сохранён явный профиль `gigaam-v3` для более точного сырого текста.
  - обновлены тест, README, спецификация, ADR и benchmark.
- Проверка:
  - `uv run pytest -q` — 226 passed, 1 skipped.
  - `git diff --check`.
2026-08-11 16:47:09 +03:00

14 KiB
Raw Blame History

Onnx-каталог, Python 3.13 и границы версий

Проблема

Смешанная русско-английская речь и отсутствие пунктуации у gigaam-v3-ctc — известные ограничения onnx-пути (ADR-006). В onnx-asr 0.12 появились модели, которые их адресуют, но обновление заблокировано ограничением onnx-asr[cpu,hub]>=0.11.0,<0.12.0 в pyproject.toml.

Состояние движков и первичные источники — исследование обновлений.

Что делаем

Снимаем ограничение версии, поднимаем onnx-asr до 0.12 и делаем поддерживаемыми четыре модели:

  • gigaam-multilingual-ctc и gigaam-multilingual-large-ctc — смешанная речь с англоязычными терминами; large добавлена после сравнительного benchmark по явному решению пользователя;
  • gigaam-v3-e2e-ctc и gigaam-v3-e2e-rnnt — пунктуация и нормализация текста.

Каталог моделей в бэкенде хранит, помимо имени, опубликованные для модели квантизации — сейчас такого места нет, потому что алиасы отображают имя в имя. Расширять существующую таблицу или заводить рядом отдельную структуру — решается при реализации. Passthrough сырых имён onnx-asr сохраняется: он не мешает и оставляет дверь для экспериментов.

Заодно поднимаем минимальную версию Python до 3.13 и ONNX Runtime до последней доступной (1.28 на момент написания). Python 3.10 в режиме security-only и снимается с поддержки в октябре 2026, а ORT 1.28 требует минимум 3.11 — так что подъём floor и обновление рантайма идут вместе. Следствие: зависимость tomli и условный импорт в config.py становятся мёртвым кодом и убираются — начиная с 3.11 есть tomllib.

Floor берётся сразу 3.13, а не минимально достаточный 3.11: любой подъём версии всё равно требует прогона на всех трёх платформах, и дорого именно тестирование, а не строка в pyproject.toml. Один переезд вместо двух. Проект ставится там, где доступны uv и PyPI, поэтому uv сам поднимет нужный интерпретатор; закрытых контуров и оффлайн-зеркал среди пользователей нет.

Рабочая версия фиксируется файлом .python-version (сейчас его в репозитории нет). Floor разрешает любой интерпретатор от 3.13 и выше, а пин делает окружение одинаковым на разных машинах — иначе расхождение вылезает именно тогда, когда что-то отлаживаешь.

Колёса cp313 проверены для всех нативных зависимостей и всех трёх целевых платформ — Windows, Linux, macOS: openvino-genai 2026.0.0.0, ctranslate2 4.7.1, onnxruntime 1.28.0. На macOS openvino-genai не ставится по существующему маркеру sys_platform != 'darwin', так что там остаются faster-whisper на CPU и onnx-путь — это не меняется этой работой, но стоит помнить, раз появились пользователи на Mac.

GPU-пакеты ORT с их требованием CUDA 13 нас не касаются: CUDA идёт через CTranslate2, а onnx-путь ставится в CPU-варианте.

Границы версий

Каждая прямая зависимость получает верхнюю границу по мажорной версии. Причина не в осторожности вообще, а в канале установки: README предлагает uv tool install git+…, а этот путь резолвит зависимости заново из метаданных пакета — uv.lock в колесо не попадает и не участвует. Диапазоны в [project.dependencies] — единственное, что ограничивает версии на машине пользователя. Установки в разные месяцы иначе дают разные наборы библиотек при одном и том же коде, и такие расхождения дороже разбирать, чем поднимать границы вручную.

Три случая, которые сами собой не решаются:

  • onnxruntime объявляется прямой зависимостью с границей, хотя проект его не импортирует. [tool.uv] constraint-dependencies для этого не годится: по документации uv он действует только когда uv резолвит сам проект, и игнорируется, когда пакет ставят как зависимость.
  • nvidia-cublas-cu12 получает границу по мажорной версии. _cuda_bootstrap.py преднагружает libcublas.so.12 по точному soname (ADR-001); мажорный апгрейд даёт другой soname и ломает bootstrap при неизменном коде.
  • openvino-genai фиксируется на проверенной линии 2026.0, а не просто «до следующего года». Иначе свежая установка подтянет 2026.3 и незаметно поменяет ту самую точку отсчёта, которую мы договорились не трогать. Границу снимает отдельная работа по обновлению OpenVINO — осознанно.

Конкретные номера берутся из uv.lock при реализации.

Последующее решение о модели по умолчанию

После сравнительного прогона на трёх реальных записях и обсуждения двух основных потребителей транскрипта модель gigaam-v3-e2e-rnnt выбрана моделью по умолчанию для явного --device onnx. Она всего на 2% медленнее сырого gigaam-v3, но выдаёт пунктуацию для чтения человеком; gigaam-v3 остаётся явным профилем с приоритетом дословной точности и последующей обработки LLM. Это решение не включает ONNX в auto-detect.

Чего не делаем

  • Не меняем auto-detect: ONNX остаётся только явным выбором пользователя.
  • Не обновляем OpenVINO, OpenVINO GenAI и CTranslate2. Whisper medium на OpenVINO — то, с чем сравниваются новые модели; менять его движок одновременно значит потерять точку отсчёта. Верхние границы версий им при этом проставляются — см. «Границы версий»; это фиксация текущего состояния, а не обновление.
  • Не добавляем алиасы large-v3-turbo, диаризацию, чанкование по паузам и словарь замен терминов — отдельные пункты backlog.

Ловушки

  • compute_type разрешается по устройству, а не по модели. DEVICE_DEFAULTS["onnx"] даёт int8 независимо от модели, а int8 опубликован не для всех. Для модели без запрошенной квантизации проект должен взять доступную и сказать об этом; явно заданное пользователем значение остаётся ошибкой, а не тихой подменой. Явным считается и значение из .transcriber.toml, не только флаг CLI — подстановка допустима лишь там, где квантизацию выбрал сам проект. Это единственное изменение в каскаде конфигурации.
  • Язык у multilingual-модели. Проект по умолчанию форсирует ru, а интерес — как раз смешанная речь. Надо посмотреть, принимает ли модель подсказку языка или определяет сама, и описать правило в README.
  • E2E меняет форму текста. Пунктуация и нормализация могут повлиять на группировку абзацев в formatter.py и на предупреждения quality.py, написанные под поведение Whisper.
  • VAD. В 0.12 исправлены сегменты нулевой длины после VAD — проект оборачивает модель в .with_vad(), так что изменение касается нас напрямую.

Как проверяем

Работа идёт в отдельной ветке (по конвенции репозитория — feature/…), в master вливается только после ручной проверки. Причина не в процессе ради процесса: переезд на 3.13 пересобирает окружение целиком, и откатывать это на основной ветке неприятно. Ветка позволяет держать рабочий master под рукой, пока новое окружение не подтвердилось.

Внутри ветки смена окружения и смена библиотеки проверяются раздельно: сначала Python и зависимости при неизменных моделях — поведение обязано остаться прежним, — и только потом onnx-asr 0.12 с новыми моделями. Иначе при первой же странности подозреваемых окажется десяток и разделить их будет нечем, CI тут не поможет.

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

  • существующие тесты замоканы (AGENTS.md) и подтверждают CLI, конфиг и форматирование, но не работоспособность движка: поломку ORT или onnx-asr видно только на реальной записи;
  • ручные прогоны делаются на Windows и Linux, по всем трём путям — onnx, openvino, cuda;
  • macOS не проверяется вовсе. Колёса cp313 там опубликованы, но это наличие, а не работоспособность; при жалобе с Mac исходить из того, что путь не валидировался;
  • скорость на Intel Core i5 не измерялась. Замеры делаются на Ryzen 7 8845H и записываются как наблюдение с указанием CPU — для решения о CPU-дефолте этого недостаточно;
  • качество моделей измерено предварительно на трёх 14–15-минутных записях. Результат фиксирует WER, скорость и ручное чтение, но не заменяет приёмку на целевом Intel Core i5 и длинных записях; см. benchmark.

Пошаговый чеклист и практика прогона нужны только на время работ и живут в задаче трекера (#1), а не в этом документе.

Документация

README: поддерживаемые модели добавляются в таблицу ONNX-моделей. Для готового читаемого русского текста и как модель по умолчанию используется E2E RNN-T, для русского без пунктуации и LLM-пайплайнов остаётся явный gigaam-v3, для смешанной речи с приоритетом качества — multilingual large. Скорость на слабых CPU не измерялась. Требование Python правится в docs/PRD.md — раздел «Требования» и таблица технологий; в README версии Python не упоминаются.