Хотел сделать конкурс на Новый год
К Новому году мы с друзьями договорились, что каждый подготовит по конкурсу. Мне хотелось сделать что-нибудь музыкальное, а идеи нашлись в воспоминаниях о двух корпоративах: с одного я принёс желание сочинить песню для нашей компании, с другого позаимствовал механику конкурса. Так появилась игра What The Track, в которой нужно угадать последнее слово оборванной строки песни.
Первую версию с вопросами, нарезанными вручную, мы довольно быстро опробовали на друзьях. Когда захотелось сыграть ещё, я решил автоматизировать подготовку, чтобы самому не знать все ответы заранее. Оказалось, что между «нейросеть умеет распознавать речь» и «ей можно доверить музыкальный конкурс» помещается отдельный проект по сравнению систем автоматического распознавания речи. А главным результатом этого проекта в итоге стал не выбор одной лучшей модели: для игры оказалось важнее научиться находить хотя бы один достаточно надёжный фрагмент песни и отказываться от вопроса, если такого фрагмента нет.
Сначала была песня
На новогоднем корпоративе диджей собрал фразы гостей и превратил их в песню. Мне такая активность понравилась настолько, что дома я полез разбираться, как сделать что-нибудь похожее для друзей. Так я нашёл Suno, собрал у друзей по одной фразе и сделал собственный новогодний гимн с мощным припевом:
Мы вместе, мы живы! И на том спасибо!
Гимн у нас теперь был, но договорённость про конкурс никуда не делась. Тут я вспомнил другой корпоратив, летний, где ведущая включала с телефона треки из нижнего интернета, а нам предлагала выбрать, какой текст прозвучит дальше. Для такого конкурса необязательно знать песню: можно попытаться угадать продолжение по рифме, а можно придумать что-нибудь смешное и потом сравнить с тем, что написал автор.
Эту механику я и решил забрать для нашей встречи, немного переделав под привычный нам формат. Мы с друзьями любим Jackbox, где все играют со своих телефонов, поэтому хотелось обойтись без возни с телефоном ведущего: пусть музыка звучит для всех, а каждый вводит ответ в собственном браузере. Я нарезал треки, подготовил вопросы, навайбкодил веб-интерфейс и выложил его на домашний сервер. Готовые варианты ответа убрал, чтобы каждый мог написать своё продолжение. После отрывка ведущий включает правильный ответ и показывает, кто что придумал, а за угаданное слово игрок получает два балла. В таком виде мы и сыграли первую партию.
Я тоже хочу играть
Друзьям понравилось, и они попросили ещё. Это означало, что для следующей партии мне снова придётся прослушать песни, найти подходящие строки и нарезать вопросы с продолжениями. Больше всего меня не устраивало, что после такой подготовки я сам уже не мог нормально участвовать: все ответы были известны заранее. Хотелось добавлять музыку в игру и садиться угадывать вместе с остальными, поэтому я взялся за автоматизацию.
Я работаю DevOps-инженером в GS-Labs, и AI-лихорадка не обошла нас стороной. Одной из моих задач была разработка сервиса для подготовки отчётов по конференциям с помощью LLM, так что с распознаванием речи я уже успел познакомиться и решил попробовать тот же подход на песнях. К нынешней версии я пришёл не сразу. Чтобы дальше было проще следить за изменениями, сначала покажу два пути, по которым генератор обрабатывает песню сегодня.
Два пути подготовки вопроса

Если у песни есть готовый текст, генератор использует его как источник правильных слов, а распознавание — прежде всего для привязки этих слов ко времени в аудио. Если текста нет, выбирать приходится прямо из расшифровки, поэтому требования становятся строже: вопрос создаётся только на участке, где согласились несколько распознавателей и совпал контекст перед словом-ответом.
До такой схемы я дошёл не сразу. Первая версия была гораздо прямолинейнее: распознать песню WhisperX, передать текст в LLM и попросить выбрать хороший вопрос.
WhisperX на песнях
В сервисе для конференций я использовал WhisperX: FFmpeg подготавливает запись, Whisper распознаёт речь, отдельная модель уточняет таймкоды слов, а pyannote разделяет реплики по спикерам. Получившуюся расшифровку уже можно передавать дальше для подготовки отчёта. С песней задача поначалу казалась даже проще, ведь обычно поёт один человек и делить реплики по спикерам не нужно. Зато вместо обычной речи распознаватель получает музыку с бэк-вокалом, растянутыми гласными и проглоченными согласными. Для моей игры ошибка в одном слове могла испортить весь вопрос, если именно это слово предстояло угадывать.
В ранней версии я отдавал текст расшифровки локальной LLM — gpt-oss-20b — и просил выбрать интересное слово, но вместе с настоящими словами она выбирала и ошибки распознавателя. Так в игру попадали ответы, которых в песне вообще не было, хотя по тексту расшифровки вопрос мог выглядеть вполне разумно. Текст подсказки тоже мог разъехаться со звуком: например, слова перед проигрышем оставались, а после него пропадали. К этому добавлялось ожидание ответа локальной LLM на каждом треке, и подготовка новой партии получалась одновременно долгой и ненадёжной.
Сначала я попробовал помочь распознавателю подготовкой звука: отделил вокал через Mel-Band RoFormer, добавил фильтрацию низких частот, нормализацию и компрессию. Распознавание стало лучше, но ошибок всё ещё хватало, чтобы регулярно получать неудачные вопросы. Следующим шагом подключил тексты из Яндекс Музыки, откуда мы уже брали сами треки. С готовым текстом можно восстановить строки и правильное написание слов, а распознавание использовать для поиска нужного места в аудио. Такой вариант работал заметно лучше, однако у части песен, которые хотелось взять в игру, текста не было.
Для некоторых песен Яндекс отдавал и метки времени, но для нарезки вопросов их оказалось недостаточно: в сохранённых LRC отмечено начало строки, а мне нужно остановить музыку перед последним словом внутри неё. Вычислить этот момент по длине строки не получится: певец может растянуть один слог, быстро проговорить несколько слов или сделать паузу. К тому же в тестах метки строк расходились с таймкодами распознавания, иногда больше чем на секунду. Например, в «Выходи гулять» Касты начало строки «Собираемся свободно и гуляем где угодно» отмечено в LRC на 24,68 с, а WhisperX и обе GigaAM находят её первое слово на 25,80–25,92 секунды. Текст этой строки все три модели распознали без ошибок. Для обрыва перед словом такая разница существенна: можно оборвать предыдущую фразу или успеть выдать часть ответа. Поэтому готовый текст я использую для выбора и проверки слов, а точку обрыва определяю по пословным таймкодам, полученным из самого аудио.
Выбор слова я переписал на правила
Пока я разбирался с качеством распознавания, стало понятнее, по каким признакам вообще выбираю вопрос вручную. Обычно это длинное, содержательное слово в конце строки, перед которым достаточно текста, чтобы игрок успел предположить продолжение. При этом хочется пропустить самый старт трека, не брать бесконечно повторяющийся припев и убедиться, что ответ не прозвучал в том же отрывке несколькими секундами раньше. Всё это можно описать обычными правилами.
Если готовый текст есть, алгоритм перебирает последние слова строк, в основном в диапазоне от 25 до 85 процентов текста, и оценивает длину слова, повторы и окончания соседних строк. Затем он ищет выбранное слово в распознанном аудио и проверяет конкретное вхождение, поскольку одно и то же слово может встречаться в песне несколько раз. Без готового текста выбирать приходится прямо из расшифровки, поэтому к отбору добавляются проверки времени: сколько длится слово, не пересекается ли оно с соседними и хватает ли контекста перед ним. Через pymorphy3 определяю части речи, чтобы чаще выбирать существительные и отбрасывать служебные слова, а если первый кандидат не проходит проверки, алгоритм переходит к следующему.
После этого LLM для выбора вопроса больше не понадобилась, но проблема с ошибками распознавания осталась. Несколько удачных песен ничего не говорили о том, какие настройки действительно помогают, поэтому сравнивать варианты пришлось более последовательно.
Пришлось собрать лабу
Для этого я собрал отдельную ASR-лабу, где результаты моделей можно посмотреть рядом, строка к строке, и сразу послушать соответствующее место в исходном треке или отделённом вокале. Так стало гораздо удобнее разбирать конкретные промахи и понимать, на каком этапе они появляются. Начал с WhisperX large-v3 с подсказкой и без неё, GigaAM v3, GigaAM Multilingual и Qwen3-ASR, а затем добавил Parakeet, Canary, Voxtral, Vosk и русские дообучения Whisper. Каждой модели давал разные варианты звука: исходный микс, вокал после Mel-Band RoFormer, тот же вокал с фильтрами и компрессором, а также результат BS-RoFormer.
Для основного сравнения собрал 100 треков 86 исполнителей, не больше четырёх песен на одного. Распознаватели получали только звук, а для проверки результата использовал референсные тексты: 92 из Яндекс Музыки и восемь из LRCLIB. Кроме этих 100 песен, в лабе были и треки без референсного текста: их я сравнивал на слух, а в таблицу WER они не вошли.
«Атомная романтика»
Хорошо видно, с чем приходится иметь дело, на примере «Атомной романтики» хардкор-панк-группы «Пурген». Здесь хриплый, почти кричащий вокал, а в припеве сильно растянута первая гласная. Для сравнения я взял фрагмент с 01:03 до 01:10 со строкой:
И ядерные взрывы освещают пути нам.
Следом идёт «А-а-а-а-атомная романтика!». Вот несколько расшифровок этого места:
Модель | Что ей дали послушать | Что она написала |
|---|---|---|
WhisperX large-v3 с подсказкой | Исходный трек | «ядерных взрывов посвящают пути нам. Водопная романтика» |
WhisperX large-v3 с подсказкой | Вокал Mel-Band RoFormer | «ядерный взрыв. Освещают Путина. Атомная романтика» |
WhisperX large-v3 без подсказки | Вокал Mel-Band RoFormer | «ядерный взрыв освещает Путина. Вот такая романтика!» |
Qwen3-ASR 1.7B | Исходный трек | «она» |
Qwen3-ASR 1.7B | Вокал Mel-Band RoFormer | «ядерный взрыв освещает пути нам Вот она и романтика» |
GigaAM v3 e2e RNN-T | Исходный трек | «ядерный взрывы освещают путь и нам! О-о-о! Вода проигратика!» |
GigaAM v3 e2e RNN-T | Вокал Mel-Band RoFormer | «ядерные взрывы посвящают Путина! О-о-о! Вот моя романтика!» |
GigaAM Multilingual | Вокал Mel-Band RoFormer | «ядерные взрывы посвящают путина адомная романтика» |
GigaAM v3 CTC | Исходный трек | «и ядерные взрывы освещают пути и нам водовая роматикано» |
GigaAM v3 CTC | Вокал Mel-Band RoFormer | «не ядерные взрывы освещают путина вот она роматика» |
На исходном миксе WhisperX сохраняет «пути нам», хотя ошибается в соседних словах, а после отделения вокала превращает их в «Путина». Ту же склейку на вокале выдают все три показанные GigaAM. Для CTC я отдельно повторил распознавание полного трека на исходном миксе и сохранённом вокале Mel-Band: на миксе получилось «пути и нам», а после разделения тоже «путина». В финальную тройку CTC вошла по результатам сравнения на 100 песнях и проверки совместного отбора вопросов, о которых расскажу ниже. Этот пример показывает ограничение такой проверки: несколько моделей могут согласиться и на ошибке, поэтому само по себе совпадение слова ещё не гарантирует правильного ответа.
С припевом получается ещё веселее: «Водопная романтика», «Вот моя романтика», «Вода проигратика». У Qwen на миксе от всего фрагмента остаётся одно «она», зато на отделённом вокале модель восстанавливает гораздо больше текста и правильно распознаёт «пути нам», хотя с самим припевом всё равно не справляется. Хрип, растянутая гласная, инструменты поверх голоса: что именно мешает сильнее, по этому примеру не выяснить. Видно только, что отделение вокала помогло Qwen восстановить строку, а от общей ошибки остальных моделей не спасло. Синхронизированного текста «Атомной романтики» в Яндексе не нашлось, поэтому слова я сверил отдельно, а сам трек оставил за пределами таблицы точности на 100 песнях.
Михаил Круг и «двери»
Другой характерный промах встретился в «Девочке-пай» Михаила Круга: на отрезке с 01:08.27 до 01:14.98 несколько моделей споткнулись о слова «В нашей Твери». В этом случае текст для сверки есть в Яндекс Музыке.
Модель на исходном миксе | Во что превратилось «Твери» |
|---|---|
WhisperX large-v3 без подсказки | Твери |
GigaAM v3 CTC и e2e RNN-T | Твери |
Parakeet TDT v3 | двери |
Vosk Zipformer2 | двери |
Voxtral Realtime | твире |
Qwen3-ASR, фрагменты до 30 секунд | тюрьи |
Parakeet и Vosk превратили «Твери» в «двери», причём отделение вокала через BS-RoFormer эту ошибку не исправило. В соседних словах тоже было на что посмотреть: у Parakeet появились «штурцы дровых», а у Qwen — «шкурцем травык». WhisperX без подсказки и две GigaAM распознали строку правильно на обоих вариантах звука, так что для этого фрагмента им хватило исходного микса.
Б.А.У. и пицца
Ещё один пример из «угарного метала» Б.А.У. В «Венском конвертике» на 01:52.76 поют:
Зубами бы впиться в слоёный край.
На исходном миксе whisper-podlodka-turbo пишет «в пицца» вместо «впиться», и Qwen с фрагментами до 30 секунд выдаёт то же самое. Рядом со слоёным краем пицца выглядит вполне уместно, но в самой песне её нет. Canary добавляет ещё и лишние слова: «карточку», «или», в другом варианте «пиццу». С таким текстом подсказка уже сомнительная, даже если последнее слово распознано правильно.
После BS-RoFormer whisper-podlodka-turbo справляется со строкой, а Qwen по-прежнему пишет «в пицца». Базовому WhisperX и двум GigaAM достаточно исходного микса, поэтому и здесь польза отделения вокала зависит от того, какой распознаватель слушает результат.
Сравнение проверенных конфигураций на 100 песнях
После основного сравнения я отдельно проверил, насколько на результаты влияет подготовка звука. Все распознаватели получали 16 кГц, как Whisper. Сама частота соответствует входу этих моделей, но способ её получения оказался важен. Я повторил пилот на тех же пяти песнях, заменив прежнее преобразование через pydub на SoXR, который корректнее отсекает высокие частоты перед понижением частоты дискретизации. Однозначного улучшения не получилось: на отделённом вокале WER базового Whisper изменился с 15,78% до 16,00%, а у Canary снизился с 36,44% до 33,37%. У GigaAM на исходном миксе качество заметно упало, причём изменилось уже поведение детектора речи: он стал пропускать фрагменты, которые прежде отправлял на распознавание. Поэтому таблицы ниже описывают результат всей проверенной цепочки с прежней подготовкой аудио, а не универсальные свойства моделей независимо от настроек.
Для сравнения я использовал WER macro по сопоставленным строкам. Расшифровка сначала распределяется по строкам референсного текста с учётом текста и времени, затем для каждой песни считается число замен, пропусков и вставок относительно числа слов референса, после чего результаты усредняются между песнями. Так длинные треки не перевешивают короткие. Перед сравнением тексты приводились к нижнему регистру, очищались от пунктуации и различия между «ё» и «е»; дефисы разделяли слова, числа переводились в словесную форму, растянутые написания вроде «дааааа» сокращались. Распевки в скобках убирались, осмысленный бэк-вокал оставался, а некоторые разговорные варианты вроде «щас» и «сейчас» приводились к общей форме.
У этой метрики есть ограничения. Референсные тексты не проходили сплошную ручную сверку с аудио, поэтому в них могут оставаться опечатки, несовпадения версии песни и ошибки сопоставления повторяющихся строк. Если для референсной строки не нашлось расшифровки, её слова считаются пропусками, однако слова ASR, которые алгоритм вообще не смог отнести ни к одной строке, в этот WER не входят. Поэтому это не совсем тот же показатель, что WER при сравнении двух полных текстов целиком. Отдельно я считаю покрытие — долю референсных строк, к которым удалось отнести хотя бы одно распознанное слово. Оно не означает, что строка распознана правильно, а лишь помогает увидеть пропуски и ограничения сопоставления.
95%-е интервалы ниже рассчитаны бутстрапом по песням: 2000 раз случайно выбирались 100 песен с возвращением, для каждой выборки считался средний WER, а границами служили 2,5-й и 97,5-й процентили. При сравнении конфигураций использовались одинаковые выборки. Эти интервалы показывают чувствительность результата к составу корпуса, но, конечно, не устраняют систематические ошибки самих референсов.
В основной таблице использованы Whisper large-v3 в WhisperX и GigaAM v3 с checkpoint’ами CTC и e2e RNN-T. Для Whisper задан русский язык, float16, batch size 8, beam size 10, best_of 5, patience 2 и пословное выравнивание. Варианты с подсказкой и без неё различаются только статичным описанием песни; сам текст песни модели не передаётся. GigaAM получает полный трек через transcribe_longform, который сначала выделяет речевые участки, а затем распознаёт их. Единого lock-файла со всеми историческими версиями библиотек и весов не сохранилось, поэтому эти результаты относятся к проверенным конфигурациям, без гарантии побитового воспроизведения старых расшифровок.
Проверенная конфигурация | WER macro по сопоставленным строкам | 95%-й бутстрап-интервал | Покрытие строк, macro |
|---|---|---|---|
WhisperX large-v3 без подсказки, BS-RoFormer | 17,7% | 14,7–21,1% | 96,2% |
GigaAM v3 e2e RNN-T, BS-RoFormer | 18,4% | 15,3–21,6% | 96,0% |
GigaAM v3 CTC, BS-RoFormer | 18,5% | 15,4–21,8% | 97,2% |
WhisperX без подсказки, Mel-Band RoFormer | 19,3% | 16,1–22,8% | 95,9% |
WhisperX без подсказки, Mel-Band + DSP | 19,0% | 15,9–22,5% | 96,0% |
WhisperX с подсказкой, Mel-Band + DSP | 24,6% | 21,2–28,3% | 90,3% |
GigaAM v3 e2e RNN-T, исходный микс | 24,7% | 21,2–28,4% | 92,8% |
GigaAM v3 CTC, исходный микс | 25,1% | 21,6–28,9% | 94,2% |
WhisperX без подсказки, исходный микс | 26,1% | 22,2–30,3% | 87,8% |
WhisperX с подсказкой, исходный микс | 33,5% | 29,1–38,1% | 82,4% |
Одна из самых полезных правок оказалась простой: я убрал подсказку, в которой объяснял Whisper, что перед ним песня с рифмами, куплетами и припевом. Самого текста песни там не было, однако без этой подсказки WER на исходном миксе снизился с 33,5% до 26,1%. А вот фильтры и компрессор поверх отделённого вокала почти ничего не дали: 19,3% без обработки против 19,0% с ней. Проверка бутстрапом не показала убедительного выигрыша от этого этапа.
На вокале после BS-RoFormer результаты WhisperX и двух GigaAM оказались близки: 17,7%, 18,4% и 18,5% соответственно. WhisperX показал наименьшую долю ошибок, но бутстрап не подтвердил уверенного преимущества: при повторных выборках песен порядок моделей менялся. Поэтому по этому корпусу я не стал объявлять единственного победителя.
Остальные модели сначала проверил на пяти песнях, чтобы понять, стоит ли запускать их на всём корпусе. Этот набор другой, поэтому напрямую сопоставлять проценты с предыдущей таблицей нельзя.
Модель, вокал после BS-RoFormer | WER macro на 5 песнях | Покрытие строк |
|---|---|---|
WhisperX large-v3 без подсказки | 15,5% | 98,0% |
antony66/whisper-large-v3-russian | 19,1% | 91,6% |
bond005/whisper-podlodka-turbo | 23,3% | 89,0% |
Parakeet TDT 0.6B v3 | 26,1% | 98,6% |
Qwen3-ASR 1.7B, фрагменты до 30 секунд | 26,4% | 98,2% |
Voxtral Mini 4B Realtime | 29,4% | 86,0% |
Vosk 0.54 Zipformer2 | 31,7% | 89,4% |
Canary 1B v2 | 36,4% | 81,4% |
Пяти песен недостаточно для общего рейтинга, но на этом наборе русские дообучения Whisper базовую модель не обошли. Для меня этот пилот выполнял скорее роль предварительного отсева, чем полноценного сравнения.
Как теперь выбирается вопрос
За сравнением распознавателей я постепенно ушёл довольно далеко от исходного конкурса, хотя для одного раунда мне по-прежнему было нужно только одно подходящее место в песне. Ошибка в другом куплете никак не мешает вопросу, если выбранный фрагмент распознан правильно. В этот момент и стало окончательно понятно, что оптимизировать всю транскрипцию до последнего слова для моей задачи необязательно: важнее найти небольшой участок, которому можно доверять.
Для треков без готового текста оставил три распознавателя: WhisperX large-v3 без подсказки, GigaAM v3 CTC и GigaAM v3 e2e RNN-T. Сначала все они слушают исходный микс, после чего алгоритм сопоставляет слова по порядку и времени и ищет места, где совпали все три расшифровки. Для выбора ответа двух голосов из трёх недостаточно. Перед ответом должны совпасть ещё хотя бы три слова подряд, желательно пять, без длинной паузы. Среди таких участков алгоритм ищет конец фразы, по возможности с существительным, и дополнительно проверяет, не прозвучало ли слово-ответ раньше в том же отрывке.
Если на исходном миксе подходящего места не нашлось, BS-RoFormer отделяет вокал, который затем слушают те же три модели. Здесь появляется дополнительное условие: выбранное слово должны были распознать хотя бы две модели на исходном миксе, поскольку игрок будет слушать оригинальную песню вместе с инструментами. Когда и этот вариант не проходит проверки, трек пропускается.
Пары моделей я тоже пробовал и встретил показательный случай в песне «37» группы «джинсы тарковского»: WhisperX и GigaAM CTC выбрали «самолёта», хотя в тексте «самолётом». Тройка отвергла этот участок благодаря проверке согласованного контекста, причём само окончание неверно услышали все три модели. Получается, от ошибки спасла именно проверка соседних слов, а одного совпадения ответа было бы недостаточно. Здесь же хорошо вспоминается и «Путина» из «Атомной романтики»: даже три модели способны одинаково ошибиться, поэтому согласие — не доказательство правильности, а ещё один фильтр.
В этой схеме WhisperX даёт таймкоды для нарезки, знаки препинания GigaAM RNN-T помогают найти конец фразы, а CTC участвует в проверке совпадений. По моим замерам на видеокарте, две GigaAM при уже загруженных моделях суммарно тратят примерно две секунды на распознавание четырёхминутного трека, без учёта подготовки звука и загрузки моделей. Такая прибавка ко времени подготовки меня устраивает.
Сколько приходится ждать
Полный рабочий прогон из 100 входных треков на NVIDIA GeForce RTX 5060 Ti с 16 ГБ видеопамяти занял 4 часа 4 минуты 40 секунд. Получение песен и текстов из Яндекса заняло первые 4 минуты 34 секунды, а на последующую обработку приходилось в среднем 144 секунды на входной трек. В этом прогоне 93 песни с готовым текстом прошли через Mel-Band RoFormer и WhisperX, а семь без текста обрабатывались в режиме согласия трёх моделей. Это те же 100 треков, что и в WER-корпусе, но числа описывают разные вещи: 92 + 8 обозначает источники референсных текстов, а 93 + 7 наличие текста у генератора в этом запуске. Разница приходится на «Индустрию смерти» Пургена: её референсный текст для лабораторного сравнения взят из LRCLIB, а во время рабочего прогона генератор получил текст из Яндекс Музыки.
Полный рабочий прогон дал 97 вопросов. Самым долгим этапом оказался RoFormer. Для 93 песен с готовым текстом время распределилось так:
Этап | Среднее на трек | Диапазон |
|---|---|---|
Отделение вокала через Mel-Band RoFormer | 107,1 с | 55,6–188,5 с |
Освобождение разделителя и подготовка звука перед WhisperX | 6,9 с | 3,7–12,0 с |
Загрузка WhisperX, распознавание, выравнивание слов и очистка памяти | 33,0 с | 29,7–47,4 с |
Выбор вопроса и сохранение двух MP3, если вопрос найден | 1,1 с | 0,8–2,2 с |
На отделение вокала пришлось около 73% суммарного времени разделения и распознавания в этом режиме. Загрузка моделей входит во время соответствующих этапов, а первоначальное скачивание весов из интернета в замер не входит. Среднее время выбора вопроса и сохранения MP3 рассчитано по 91 созданному вопросу: ещё две песни в этом режиме были пропущены. Например, в «Новый год чем-то снова…» группы «кьюаркод» Mel-Band отработал за 56 секунд, а в «Моя бабушка курит трубку» Гарика Сукачёва за 189 секунд. Вместе с подготовкой звука и WhisperX эти песни заняли соответственно 89 и 235 секунд. У «Венского конвертика» длительностью 3 минуты 45 секунд разделение заняло 132 секунды, оставшаяся обработка 55 секунд, а выбор вопроса и запись файлов ещё около секунды.
Просто убрать разделение вокала было бы заманчиво, но для полной расшифровки оно действительно помогает: у WhisperX WER меняется с 26,1% на исходном миксе до 17,7% после BS-RoFormer, у GigaAM CTC — с 25,1% до 18,5%, у RNN-T — с 24,7% до 18,4%. Для самой игры, однако, это различие можно использовать иначе. Даже в несовершенной расшифровке часто находится короткий участок, который все три модели распознали одинаково, поэтому режим согласия сначала пробует исходный микс и запускает отделение вокала только при неудаче.
Для пяти треков полного рабочего прогона, которым запасной проход не понадобился, распознавание тремя моделями и отбор заняли в среднем 47 секунд, от 41 до 53 секунд на трек. Если же приходится переходить к BS-RoFormer, ко времени первого распознавания добавляются разделение вокала и ещё один проход моделей. Два трека, дошедшие до запасного прохода в полном прогоне, обрабатывались 159 и 207 секунд. Поэтому BS-RoFormer в режиме согласия я оставил именно запасным вариантом; путь с готовым текстом пока по-прежнему использует Mel-Band RoFormer для каждого трека.
Загрузка моделей и видеопамять
Чтобы понять, сколько из этого времени уходит на смену моделей, я отдельно повторил обработку полного «Венского конвертика» с замером каждого этапа. Загрузка Mel-Band RoFormer заняла 5,7 секунды, BS-RoFormer — 3,1 секунды, а освобождение Mel-Band после обработки около 0,1 секунды. У WhisperX загрузка распознавателя заняла 17,5 секунды, загрузка модели для выравнивания слов — ещё 11,6 секунды. Само распознавание в этом запуске заняло 5,5 секунды, выравнивание — 1,3 секунды. Значительная часть ожидания действительно пришлась на подготовку моделей. Веса уже лежали локально, но загрузчики обращались к Hugging Face за метаданными, поэтому это время нельзя считать только чтением файлов с диска.
У GigaAM разницу хорошо видно на двух последовательных обращениях с одним и тем же файлом. Первый запрос к CTC занял 11,7 секунды, повторный с уже загруженной моделью — 0,5 секунды; у RNN-T получилось 6,4 и 1,2 секунды. Время первого запроса включает запуск нужных компонентов и распознавание, поэтому целиком приписывать его переключению модели было бы неверно. Это отдельный замер, а не среднее по всей партии: в журнале большого прогона загрузка и работа каждой модели не разделялись.
В том же запуске я измерял занятую видеопамять через nvidia-smi. Перед обработкой на видеокарте уже было занято около 1,2 ГиБ; таблица показывает полное наблюдаемое потребление вместе с этим фоном и моделями, которые оставались загруженными.
Этап | Наблюдаемый пик занятой VRAM |
|---|---|
Mel-Band RoFormer | 4,6 ГиБ |
BS-RoFormer | 4,2 ГиБ |
GigaAM CTC | 2,7 ГиБ |
GigaAM RNN-T, CTC остаётся загруженной | 3,2 ГиБ |
Whisper large-v3, обе GigaAM остаются загруженными | 10,3 ГиБ |
Выравнивание слов после Whisper | 8,6 ГиБ |
Это ориентиры именно для моей конфигурации: batch size 1 у RoFormer, batch size 8 и float16 у WhisperX, опрос памяти примерно раз в 0,2 секунды. Они не доказывают, что каждая модель требует именно столько памяти или что весь проект обязательно требует 16 ГБ. Пики нельзя складывать, поскольку этапы выполняются последовательно, а в показания входят оставшиеся выделения памяти предыдущих этапов. Подготовка звука, выбор вопроса и экспорт MP3 выполняются на CPU.
Отдельная проверка режима согласия: 98 вопросов
В этой проверке все 100 треков прошли через отбор по согласию трёх моделей, без готовых текстов на входе. Использовались сохранённые расшифровки: нейросети повторно не запускались, проверялся именно выбор вопроса. Это отдельный эксперимент, тогда как полный рабочий прогон с двумя путями обработки дал 97 вопросов.
Проверка режима согласия на 100 треках | Количество |
|---|---|
Получили вопрос | 98 |
Вопрос выбран без отделения вокала | 91 |
Для вопроса понадобилось отделить вокал | 7 |
Трек пропущен: подходящего вопроса не нашлось | 2 |
Слово-ответ подтверждено текстом песни | 98 |
Все 98 слов-ответов подтвердились по текстам песен. Иногда поправка требовалась самому референсному тексту: в «Будущих мамах» Лигалайза было написано «металлоИКателем», а модели распознали «металлоИСкателем». При этом в самих подсказках ошибки остались: например, в «Плак-плак» система выбрала правильный ответ «умереть», но перед ним написала «И мне так уж страшно» вместо «И не так уж страшно». Проверка нескольких слов перед ответом не покрывает весь текст, который видит игрок, поэтому подтверждение всех 98 ответов ещё не означает, что каждый вопрос целиком безупречен. Точность выбранных точек обрыва аудио этой проверкой я тоже не оценивал.
Есть и ещё одно ограничение: правила отбора я разрабатывал, разбирая ошибки на этом же корпусе из 100 песен. Поэтому результат 98 из 98 показывает, что текущая схема хорошо работает на использованном наборе, но не заменяет независимой проверки на новых треках, которые не участвовали в настройке алгоритма.
Без вопроса остались «Gitar» Петра Налича, где английский текст попал в конфигурацию для русского языка, и «Батя-токарь» ZAPRAVKA, для которого ни на миксе, ни на вокале не нашлось подходящего слова с согласованным контекстом. Для моей игры пропустить такие треки допустимо: из плейлиста всё равно получается достаточно вопросов.
Как этим пользоваться
Со стороны ведущего подготовка теперь сводится к тому, чтобы добавить ссылки на треки, альбомы или плейлисты Яндекс Музыки и запустить генерацию. Если у песни есть текст, программа использует его вместе с таймкодами распознавания, а если нет — выбирает вопрос по согласию трёх моделей. Результат сохраняется в виде фрагмента с вопросом, продолжения с ответом и текста с пропуском.
К началу партии вся работа нейросетей уже закончена: Flask и Socket.IO обслуживают ведущего и игроков, а nginx раздаёт страницы и готовые файлы. Игрокам достаточно открыть страницу в браузере на телефоне. Есть и упрощённый режим с одним WhisperX и отделением вокала, если согласие моделей выключено или модели GigaAM недоступны. Результат 98 из 100 относится именно к трём моделям, на упрощённый режим его переносить нельзя.
Что в итоге
В результате у меня получилась игра, для которой больше не нужно вручную готовить каждую новую партию. Полный рабочий прогон с двумя путями обработки дал 97 вопросов из 100 входных треков и занял около четырёх часов. В отдельной проверке режима согласия удалось выбрать 98 вопросов из 100, и все слова-ответы подтвердились по текстам. Для домашнего конкурса меня такой результат устраивает, хотя ошибки в подсказках остаются, а качество точек обрыва ещё нужно проверять отдельно.
Главным решением за всё это время оказалось не улучшение WER на очередные несколько процентов, а сужение самой задачи. Для игры не требуется идеально распознать всю песню: достаточно найти один участок, которому можно доверять, а если его нет — отказаться от вопроса. Когда признаки хорошего фрагмента удалось сформулировать, выбор описался обычными правилами, и LLM для этого больше не понадобилась. Сравнение нескольких распознавателей тоже оказалось полезнее попытки выбрать одну «лучшую» модель: их ошибки различаются, а согласованный контекст помогает отсеивать часть неудачных вариантов. Хотя, как показал «Путин», даже несколько моделей иногда уверенно ошибаются вместе.
Исходники What The Track и инструкция по запуску лежат на GitHub. Если захочется устроить похожий конкурс, можно развернуть игру у себя и попробовать её на своей музыке; мне особенно интересно, на каких песнях эта схема начнёт ошибаться у других. Из двух корпоративных идей у меня в итоге получились новогодний гимн, музыкальная игра и довольно обстоятельное знакомство с ошибками распознавания песен. Зато теперь можно добавить плейлист, запустить подготовку и не подсматривать ответы, чтобы наконец сыграть в собственный конкурс вместе с друзьями.
Нескучных всем выходных и интересных мероприятий!

