Представьте: вы запускаете программу, говорите несколько слов в микрофон, а на экране практически сразу появляется текст.
Всё работает. Никаких серверов, отправки аудиозаписей в облако и ожидания ответа от удалённой модели.
Но есть нюанс.
Короткая демонстрационная фраза и десять минут непрерывной речи — совершенно разные задачи.
Меня заинтересовал именно этот разрыв. Можно ли взять относительно небольшую модель распознавания речи, запустить её локально и получить систему, которая будет успевать обрабатывать живую речь?
Для эксперимента выбрал Moonshine Voice.
Лунный свет?
Меня интересовала возможность потокового распознавания на обычном компьютере.
Moonshine предлагает несколько вариантов моделей, в том числе облегчённые и потоковые архитектуры.
Я выбрал SMALL_STREAMING.
Эксперимент проводили на Windows с Python 3.12 и библиотекой moonshine-voice версии 0.1.5.
Для начала нужно было просто заставить модель работать.
Установили библиотеку:
pip install moonshine-voice==0.1.5
Затем загрузил английскую модель:
ModelArch.SMALL_STREAMING
В процессе загрузки использовалась конфигурация:
small-streaming-en/quantized_26_08_21
В составе модели обнаружил два основных компонента:
Компонент
Размер
Decoder
78,1 МБ
Encoder
42,1 МБ
Сама установка оказалась не самой сложной частью. Основная работа началась после подключения микрофона.
Первый запуск: модель действительно слышит
Для первого теста использовал короткие английские фразы.
Например:
The weather is beautiful today.
Модель вернула правильный текст.
Другой пример:
Tomorrow morning.
Тоже без заметных проблем. Казалось, что всё получилось. Но я понимал: несколько коротких предложений ничего не говорят о поведении модели при продолжительной речи.
Поэтому стал увеличивать продолжительность тестов. И тут появились первые неприятные сюрпризы.
Когда нейросеть начинает слышать то, чего не говорили
На более продолжительных фрагментах стали появляться ошибки.
Вместо ожидаемых слов модель могла выдавать совершенно другие конструкции:
-
guilty to any mistrains; -
minute fork; -
Jabez.
Это уже не просто пропущенная запятая или неправильно распознанное окончание.
Возник вопрос: почему на коротких фразах результат выглядит убедительно, а при увеличении продолжительности речи качество может заметно ухудшаться?
Одного теста для ответа было недостаточно. Я решил разобраться в самом механизме потокового распознавания.
Модель не просто дописывает текст
Одна из интересных особенностей Moonshine обнаружилась при наблюдении за промежуточными результатами.
В потоковом режиме модель не обязательно выдаёт окончательный вариант фразы с первой попытки. Она получает новые аудиоданные и может пересматривать ранее сформированную гипотезу. Например, в одном из тестов я наблюдал такую последовательность:
Этап
Результат
1
Honestly,
2
Honestly, I was absolutely guilty.
3
…When I missed the train this morning, you know,
4
Anyway,, a long study shorted.
5
a long story short, I hate to grab a coffee.
6
…end up being 20 minutes late For work,
Обратите внимание на переход от a long study shorted к a long story short.
Модель сначала сформировала одну гипотезу, а затем изменила её. Для обычного пользователя это означает, что текст на экране может быть не окончательным даже после появления целого предложения.
Для разработчика возникает другая задача: необходимо правильно обрабатывать изменения транскрипции. Если просто дописывать каждое новое обновление в конец строки, получится бессвязный текст.
Нужно сравнивать предыдущую и новую версии, определять изменившуюся часть и корректно обновлять отображение. Это отдельная инженерная задача, которую легко недооценить при первом знакомстве с потоковым распознаванием.
Разделяем микрофон и распознавание
Следующим этапом я решил отделить поступление аудио от обработки нейросетью.
Для этого организовал отдельный worker-поток. Схема выглядела следующим образом:
Микрофон | vАудиоблоки | vОчередь | vWorker | vMoonshine | vОбновление транскрипции
Использовал частоту дискретизации 16 000 Гц, один аудиоканал и блоки размером 1024 сэмпла.
В процессе разработки столкнулся с несколькими проблемами.
Например, первоначально попытался вызвать метод update у объекта Transcriber, но такого метода в используемом интерфейсе не оказалось. Пришлось уточнять фактический API и менять организацию обработки. В одном из ранних тестов время работы worker составило 3,84 секунды при продолжительности аудио 4,48 секунды.
Получилось:
RTF = 1,17.
Что это означает?
RTF (Real Time Factor) показывает отношение времени обработки к продолжительности аудио.
Если RTF меньше единицы, обработка быстрее поступления речи.
Если больше единицы — обработка занимает больше времени, чем длится соответствующий аудиофрагмент. В моём первом измерении производительности не хватало для уверенной работы с непрерывным потоком.
Но я продолжил эксперименты.
Почти реальное время
В одном из следующих прогонов получил значительно более интересный результат.
Продолжительность аудио составила 24,64 секунды. Обработка в worker заняла 24,33 секунды. Итоговый RTF — приблизительно 0,99. То есть в этом конкретном тесте обработка завершилась немного быстрее, чем длился аудиофрагмент.
Очередь достигала максимума в 44 аудиоблока, а зафиксированное максимальное отставание составляло около 0,20 секунды. Это уже совсем другой результат по сравнению с первым прогоном.
Однако важно не делать из одного удачного измерения универсальный вывод о производительности модели. RTF зависит от оборудования, конфигурации, длительности теста и организации обработки аудио.
Тем не менее я получил подтверждение, что выбранная конфигурация способна приблизиться к скорости реального времени.
Почему одного показателя RTF недостаточно
Во время экспериментов я отдельно наблюдал за временем выполнения операций.
В некоторых случаях обновление транскрипции занимало считаные миллисекунды.
В других возникали заметные скачки:
-
обновление транскрипции — до 715 мс;
-
добавление аудиоданных — до 974 мс.
И здесь обнаружилась ещё одна важная особенность.
Даже если средняя скорость обработки достаточна, отдельные операции могут занимать значительно больше времени. Поэтому оценивать потоковое распознавание только по одному показателю нельзя. Нужно смотреть одновременно на скорость обработки, задержки, накопление очереди и стабильность выдаваемого текста.
Что показал эксперимент
Я начинал с простой идеи: запустить небольшую модель на локальном компьютере и проверить, насколько хорошо она справляется с живой речью.
В результате получил несколько практических наблюдений.
Первое. Локальный запуск небольшой модели распознавания речи на Windows вполне реален. Для первого знакомства не требуется самостоятельно строить сложную систему.
Второе. Качество распознавания коротких фраз не гарантирует такого же качества на продолжительной речи. Проверять модель нужно в условиях, приближённых к реальному использованию.
Третье. Потоковое распознавание — это не просто последовательное добавление слов. Модель может пересматривать предыдущие гипотезы, поэтому приложению необходим механизм корректного обновления текста.
Четвёртое. Производительность нельзя оценивать только по времени обработки всего аудиофрагмента. Важны также отдельные задержки и поведение очереди.
Пятое. В одном из своих тестов я получил RTF около 0,99 на аудиофрагменте продолжительностью почти 25 секунд.
Это хороший экспериментальный результат, но пока не доказательство стабильной работы на любой продолжительности речи.
Вместо заключения
В таких экспериментах интересно не то, что нейросеть однажды правильно распознала предложение.
Гораздо интереснее понять, что происходит, когда условия перестают быть идеальными. Когда человек говорит долго, меняет темп, делает паузы, а модель вынуждена постоянно уточнять собственные предположения.
Я увидел, что даже относительно небольшая модель способна приблизиться к обработке речи в реальном времени. Но между успешным распознаванием короткой фразы и полноценным инструментом для повседневной работы остаётся немало инженерных задач.
И, пожалуй, это главный результат моего эксперимента.
Запустить нейросеть — только начало. Настоящая работа начинается тогда, когда проверяешь, как она ведёт себя за пределами демонстрационного примера.
Об авторе
Разработка · ИИ · Исследования
GitHub: Мои Разработки и исследования
Ранее на Хабре
Как я уделал Microsoft, но это никому не нужно (кайфую сам) — история создания Jupiter, программы голосового ввода текста для Windows.
Как ChatGPT помог мне потратить шесть часов на пятиминутную проблему — нашёл баг в Обсидиан и написал об этом разработчикам, но они не смогли его воспроизвести
Источник: habr.com