Почему одного Whisper оказалось недостаточно и как мы создали полноценный сервис распознавания речи. speech-to-text.. speech-to-text. vad.. speech-to-text. vad. whisper.. speech-to-text. vad. whisper. аудиообработка.. speech-to-text. vad. whisper. аудиообработка. диаризация.. speech-to-text. vad. whisper. аудиообработка. диаризация. Машинное обучение.. speech-to-text. vad. whisper. аудиообработка. диаризация. Машинное обучение. распознавание речи.. speech-to-text. vad. whisper. аудиообработка. диаризация. Машинное обучение. распознавание речи. речевая аналитика.
Почему одного Whisper оказалось недостаточно и как мы создали полноценный сервис распознавания речи - 1

Всем привет! Меня зовут Наталья, я инженер машинного обучения в ЮMoney. Мы уже писали о том, как транскрибируем аудио с внутренних созвонов в текст. Прошёл год, и задача выросла: помимо созвонов мы решили транскрибировать все звонки службы поддержки, а также создать удобный интерфейс для работы с аудио и текстом. В этой статье расскажу, как нам удалось реализовать всё это, и при этом повысить качество распознавания и сохранить процесс внутри корпоративного контура. Мы протестировали различные решения и теперь делимся опытом, чтобы другие команды могли быстрее внедрять проверенные подходы и избегать распространённых ошибок.

Зачем нам понадобилось дорабатывать сервис транскрибации?

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

Текст решает сразу несколько задач: быстрый просмотр, поиск по ключевым словам, более глубокая аналитика (отчёты, резюме звонков, поиск повторяющихся проблем). Но возможностей текущей модели оказалось недостаточно.

Что было раньше?

В прошлой статье мой коллега подробно описал первую версию рабочего процесса: 

  • аудио разбивается на фрагменты (чанки) по 25-30 секунд;

  • каждый фрагмент переводится в текст с помощью модели Whisper от OpenAI, сохранённой локально;

  • выполняется разделение аудио (диаризация) по спикерам с помощью голосовых векторных представлений (voice‑эмбеддингов), полученных через wespeaker-voxceleb-resnet34-LM, и их кластеризация;

  • формируется резюме всего текста с помощью языковой модели.   ​

Для коротких внутренних созвонов, где каждый спикер говорит понятно и связано, этого было достаточно. Но на более длинных аудио, проявились проблемы:

  • некорректное распознавание корпоративных терминов;

  • разрывы фраз из-за фиксированного фрагментирования по 25-30 секунд;

  • низкое качество распознавания коротких/шумных сегментов;

  • долгое время обработки;

  • отсутствие удобного интерфейса.

Зачем нужен алгоритм определения речевой активности (VAD)?

Основной проблемой первой версии сервиса была наивная фрагментация (чанкинг). Мы делили аудио на равные по длине куски, и, несмотря на то, что разделение происходило в моменты затухания звука, фраза всё равно могла оборваться посередине — начало предложения попадало в один фрагмент, а конец — в другой. Модель теряла контекст.

В телефонных звонках много тишины: паузы, ожидание ответа, переключение между сотрудниками, удержание на линии, и мы тратили ресурсы на её распознавание. Нам нужно было делить аудио по смыслу.

Здесь на помощь пришёл алгоритм определения речевой активности (Voice Activity Detection, Silero VAD). Он прекрасно справляется с распознаванием речи и определяет, в какие моменты в аудио присутствует речь, а в какие — тишина или шум. 

Silero VAD — публичный речевой детектор, который можно установить локально (https://github.com/snakers4/silero-vad/tree/master и https://habr.com/ru/articles/940750/). На Хабре есть несколько статей, в которых подробно описан принцип его работы, поэтому на архитектуре я не останавливаюсь. Лишь скажу, что, судя по метрикам (https://github.com/snakers4/silero-vad/wiki/Quality-Metrics), которые приводятся в самой свежей статье на Github, он обгоняет существующие решения.

(https://github.com/snakers4/silero-vad/wiki/Quality-Metrics)

Для нас ключевым было то, что модель можно развернуть полностью локально. Мы установили её внутри корпоративного контура — без внешних API и без отправки аудио в сторонние сервисы. Все звонки клиентов и внутренние записи обрабатываются на нашей стороне.

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

  • min_speech_duration_ms — ограничивает максимальную длину речевого сегмента.
    Причина изменения: Whisper поддерживает сегменты до 30 секунд. Мы ограничили этот параметр значением в 20 секунд, чтобы позже добавить небольшую тишину по краям сегмента.

  • min_silence_duration_ms — определяет границу фразы.
    Причина изменения: в двухканальной записи (именно так записываются звонки) при обработке каждого канала по отдельности между фразами одного и того же спикера появляются длительные промежутки тишины — в это время говорит второй участник, но в текущем канале это воспринимается как пауза. Если в таких условиях оставить значение min_silence_duration_ms по умолчанию (100 мс), модель начинает слишком агрессивно сегментировать речь: даже небольшие паузы интерпретируются как границы, и фразы одного спикера дробятся на множество коротких фрагментов. Поэтому мы увеличили min_silence_duration_ms, чтобы склеивать близкие по смыслу фразы одного спикера в более крупные сегменты и уменьшить избыточную фрагментацию.

  • speech_pad_ms — добавляет небольшой отступ по краям речевого сегмента.
    Причина изменения: избежать обрезания начала или конца слова и сохранить естественность звучания. Без дополнительного отступа (паддинга) иногда съедались первые миллисекунды слова, и Whisper хуже распознавал такие куски.

Новый процесс транскрибации

Старая схема строилась вокруг Whisper, а всё остальное служило вспомогательным инструментом. После внедрения алгоритма определения речевой активности (VAD) стало понятно, что итоговое качество определяется не только самой моделью, но и всей цепочкой обработки аудио. Поэтому мы решили пересмотреть весь процесс.

Приём и подготовка аудио

На вход сервис получает одноканальные или двухканальные записи. Далее происходит нормализация: проверка формата аудио, приведение к нужной частоте дискретизации (16 кГц), конвертация в моно при необходимости или разделение каналов для двухканальных записей звонков.

Фрагментация (чанкинг) и предобработка перед транскрибацией

Затем каждый аудиопоток передаётся в сервис разбиения на фрагменты. На этом этапе работает алгоритм определения речевой активности (Silero VAD). В результате удаляются длинные паузы, исключаются участки без речи, отсекаются шумовые фрагменты и формируются первичные сегменты.

Здесь мы столкнулись с неожиданной проблемой: не вся «речь» действительно полезная и настоящая. В двухканальных телефонных записях часто происходит утечка аудио между каналами — нежелательное попадание звукового сигнала из одного канала в другой. Когда говорит клиент, в канале оператора может появляться слабое эхо его голоса, и наоборот. Формально это выглядит как тихий речевой сигнал, и Silero VAD определяет его как речь.

Если не фильтровать такие сегменты, Whisper либо начинает дублировать реплики, либо из-за недостаточной громкости и чёткости аудио появляются странные фразы. Поэтому мы добавили дополнительный этап фильтрации сегментов по энергии сигнала.

Для каждого временного сегмента мы вырезаем соответствующий отрывок аудио и вычисляем среднеквадратичное значение (Root Mean Square, RMS) — это метод измерения средней мощности или громкости аудиосигнала в децибелах. Сохраняем значение энергии сегмента и вычисляем медиану RMS по всем сегментам канала.

Если RMS сегмента ниже медианы более чем на 25%, мы его подавляем. Все значения рассчитываются для каждого канала и не задаются фиксированным числом. Это позволяет системе корректно работать как с громкими, так и с тихими записями.

После фильтрации сегментов формируем финальные фрагменты, к которым добавляем тишину по краям: с помощью ffmpeg cоздаём секунду тишины перед сегментом и после него, а затем объединяем их.

Зачем? Опытным путём мы выяснили: если подать аудио, которое стартует прямо с первого звука слова, модель иногда «съедает» начало и теряет контекст. Поэтому мы делали фрагменты по 20 секунд — с запасом на встроенное дополнение (паддинг) и на искусственное добавление тишины.

К этому моменту процесс уже значительно изменился: мы убрали наивную фрагментацию, внедрили VAD, добавили фильтрацию по энергии и подготовили аудио для перевода в текст. Осталось доработать корректное распознавание корпоративных терминов.

Пример тестового отрывка, переведённого в текст с помощью T-one

Пример тестового отрывка, переведённого в текст с помощью T-one

Мы протестировали другие аналогичные модели, но Whisper оказался более гибким не столько по базовому качеству, сколько по возможности подстроить модель под свои задачи. Мы остались на Whisper, но сменили реализацию на ускоренную версию (faster‑whisper). Это дало ощутимый прирост скорости обработки аудио, а качество осталось на уровне оригинального Whisper large-v3.

В Whisper есть набор параметров, которые позволяют научить модель работать в контексте разных данных. Вот основные, которые мы используем:

  • Начальная подсказка (initial_prompt) — текстовая подсказка, в которой заранее задаём контекст: какая тематика разговора, какие термины могут встречаться.

  • Ключевые слова (hotwords) — список слов или выражений, которые модель должна учитывать с повышенным приоритетом. У нас это корпоративные термины: названия внутренних сервисов, аббревиатуры и специфическая терминологии.

  • Язык (language) — явное указание языка. Мы фиксируем язык, чтобы уменьшить время обработки.

Разделение голосов (диаризация)

Мы осознанно отказались от полноценного разделения, чтобы не усложнять архитектуру и не увеличивать время обработки звонков. Вместо этого каждый канал обрабатывается отдельно, а затем мы собираем диалог обратно по временным меткам.

Дополнительная обработка (постобработка)

Её задача — очистка от ошибочных распознаваний, обработка пересечения реплик спикеров и формирование структурированного диалога.

Каждый текстовый сегмент сопоставляется с разметкой спикеров: берём временной диапазон текста и вычисляем пересечение с каждым сегментом, затем суммируем наложение (overlap) по каждому спикеру, после отбрасываем тех, чья доля пересечения ниже порога, и назначаем отрывку одного или нескольких спикеров. Если текстовый сегмент существенно пересекается с двумя спикерами — это может быть перебивание, и тогда мы просто сохраняем список спикеров.

Также мы объединяем соседние сегменты, если спикер совпадает и пауза между ними меньше заданного порога. Это делает диалог более естественным и читабельным.

Пример тестового отрывка, транскрибированного нашей моделью

Пример тестового отрывка, транскрибированного нашей моделью

Заключение

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


А как вы подходите к выбору моделей распознавания речи для корпоративных задач? С какими сложностями сталкиваетесь?

Автор: taaliexx

Источник

Rambler's Top100