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

Быстрые команды удобнее не только пользователям, но и системе: запросы через слово «Алиса» требуют обращения к модели распознавания речи ASR, которой из‑за её размеров необходимы серверные вычислительные ресурсы, а модель быстрых команд устроена гораздо компактнее. Она работает прямо на устройстве, а значит, ограничена вычислительными ресурсами самой колонки — её CPU и оперативной памятью. Из‑за этого модель нельзя сильно увеличить: ей приходится оставаться компактной, зато запрос обрабатывается быстрее.
За распознавание быстрых команд отвечает нейросеть. Её архитектура почти полностью совпадает с решением для наушников Яндекс Дропс, которое подробно описал в своей статье Григорий Афанасенко. Разница в основном в масштабе: наша модель весит всего от 0,5 до 1,5 МБ в зависимости от железа конкретного устройства.
Со временем перед нами встала задача добавить к базовым командам «лайк» и «дизлайк» для управления треками, а также команды «включи блютус» и «выключи блютус». Особенно это актуально для Станции Стрит, которую часто берут с собой на природу, где нет интернета. Но главным было гарантировать абсолютное отсутствие ухудшения на уже запущенных командах и не слишком сильно увеличивать потребление ресурсов на устройстве.
Откуда мы берём данные для обучения
Для старых команд у нас накопился приличный объём логов, на которых можно улучшать модель, а логи для новых команд пришлось поискать среди пользовательских запросов к Алисе. У таких логов есть минус — слева от нужной команды там почти всегда идёт активационное слово «Алиса». Так как наши модели оценивают фиксированный аудиоконтекст слева и справа от фразы, постоянное соседство с активационным словом — это out‑of‑domain для нашей модели. Чтобы нейросеть не переобучилась под обязательное присутствие «Алисы» перед новыми командами, мы просто обрезали звук так, чтобы полностью сохранить нужную нам команду без активационного слова.
Но это породило другую проблему: в реальной жизни люди произносят команду вплотную к имени помощника, поэтому слева от неё остаётся слишком мало звука. Модели критически важно видеть контекст звука на две секунды или больше до момента произнесения команды. Это помогает не активироваться на фразы, которые были сказаны не для колонки, что улучшает качество модели.
Чтобы решить эти проблемы, мы попросили людей записать нужные фразы на колонки в условиях обычной квартиры. Так мы избавились от «Алисы» на входе и зафиксировали нужное количество звука с обеих сторон. Было несколько нюансов: в искусственных условиях люди часто говорят менее естественно, чем в обычной жизни, а собирать датасет вручную — процесс долгий. Но мы хотели собрать как можно больше записей, ведь качество моделей растёт с увеличением объёма хороших тренировочных данных.
В итоге мы выбрали обучение в две стадии:
Сначала делаем претрейн на огромном массиве неочищенных данных из ASR‑логов.
Затем дообучаем модель на очищенных, специально записанных пользователями данных.
Стадия обучения |
Датасет |
Количество данных |
Претрейн |
ASR |
60–100 млн |
Дообучение |
Квартира |
400 тыс. — 1 млн |
Как мы обучаем модель
Первый вариант обучения модели, который приходит в голову, — переобучить систему с нуля, смешивая логи старых команд с новым датасетом. Но в нашем случае этот подход слишком опасен регрессией качества старых команд. Единственный способ хоть как‑то контролировать баланс между качеством старых и новых фраз в таком сценарии — крутить пропорции датасетов при обучении и менять веса классов в функции потерь. А они не дают никаких гарантий: невозможно перед запуском ответить на вопрос: «Что будет с качеством распознавания фразы „дальше“, если смешать датасеты в пропорции 80 на 20?» Нам пришлось бы запускать бесконечные эксперименты с перебором гиперпараметров, и не факт, что за разумное время мы вообще нашли бы устраивающий нас компромисс.
Второй вариант — обучить отдельную маленькую модель под новые фразы. На инференсе звук будет подаваться сразу в обе модели, что гарантирует сохранность качества старых команд.
Но и у этого подхода есть минусы:
Страдает поддержка. Поддерживать две независимые модели на инференсе дороже, чем крутить одну с тем же суммарным количеством дополнительных параметров.
Страдает качество. Внутри единой модели выучиваются общие акустические паттерны, полезные для всех команд сразу. Обучая новую полностью изолированную модель, мы впустую тратим её ёмкость на повторение пройденного — модель учит признаки, которые и так знает старая.
Для таких сценариев есть целое направление — непрерывное обучение (continual learning). Его методы созданы как раз для того, чтобы адаптировать модель под новые задачи и при этом не сломать то, что уже работает. Например, популярный подход Elastic Weight Consolidation (EWC) удерживает веса нейросети в определённых рамках, не давая им сильно уходить от исходных значений.
Но в непрерывном обучении мы снова упираемся в отсутствие гарантий: единственный рычаг управления — гиперпараметр внутри функции потерь, который определяет, насколько сильно веса итоговой модели будут притягиваться к старым. И хотя для дообучения с EWC нужен в основном датасет с новыми командами (который гораздо меньше датасета со старыми), нам всё равно пришлось бы запускать десятки тренировок и перебирать этот коэффициент вслепую. Да и стабильность процесса обучения с EWC оставалась под большим вопросом.
Модель Parameter‑Efficient Fine‑Tuning и её ограничения
Мы решили присмотреться к идее Parameter‑Efficient Fine‑Tuning (PEFT). Обычно это семейство методов используют для тюнинга моделей под специфический домен, когда данных мало, а бюджет на вычисления сильно ограничен.
Но есть нюанс: в своём классическом виде те же адаптеры или популярный LoRA вмешиваются во внутренние активации слоёв. Из‑за этого их пришлось бы натаскивать сразу на две задачи: учить новые команды и параллельно следить, чтобы модель не забыла старые. А значит, мы снова возвращаемся к исходной точке — никаких гарантий против регрессии качества старых команд на выходе.

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

И если по оперативной памяти расход вырастет несильно (слои, отмеченные на схеме пунктиром, не занимают дополнительного места), то вычислительной нагрузке достанется ощутимый удар, ведь нам придётся обсчитывать по два раза одни и те же базовые слои.
На схеме есть узкое место: в нижней ветке мы раз за разом гоняем тяжёлые активации нейросети, и чем они больше, тем сильнее страдают и память, и процессор девайса.
Логично попытаться сжать эти активации до более компактного вида, но, если переборщить, модель просто не сможет вытащить из урезанных активаций ничего полезного. Нужно искать компромисс.
Адаптеры или LoRA обязаны сохранять оригинальную размерность только по одной причине: их выход потом нужно возвращать в оригинальные слои базовой модели. А что, если разорвать эту связь? Эта мысль привела нас к решению: зачем делать двойную работу, если можно брать готовую информацию из старых слоёв как есть и обучать только надстройку специально для новых фраз?
Мы поступили так: начиная с определённого слоя оригинальной модели, мы просто отводим параллельную ветку, забираем туда активации замороженного слоя, а внутри считаем небольшой добавочный вектор, который конкатенируем на каждом последующем шаге.
Получается отличный симбиоз:
Новые слои имеют прямой доступ к мощной базе знаний старой модели.
Модель учится распознавать новые команды, не тратя ёмкость на удержание старого контекста.
Мы полностью контролируем размерность новых слоёв, подгоняя её под лимиты железа.

За счёт переиспользования внутренних представлений существующей большой модели получилось добиться лучшего качества, чем при подходе, который использует отдельную модель. У нас получилось уменьшить количество ложных срабатываний примерно на 60%.
За счёт новой архитектуры мы получили хороший профит по ресурсам: уменьшили потребление CPU примерно на 35%, а потребление RAM — примерно на 50%.
Вместо заключения
В итоге нам удалось найти тот самый компромисс с помощью модульного подхода: мы научились быстро добавлять в колонку новые команды, гарантировали абсолютную стабильность старых сценариев и при этом минимально увеличили нагрузку на процессор и память.
Всеми деталями этого исследования и более подробным сравнением с другими подходами мы поделились в нашей статье Scalable Keyword Spotting via Modular Network Expansion, которую приняли на конференцию Interspeech 2026. Если вам интересна логика, которая стоит за нашим решением, или хочется глубже погрузиться в тему эффективного расширения легковесных моделей голосовой активации, заглядывайте в полную версию нашей статьи.