
Привет, Хабр!
Меня зовут Айрат, я руковожу командой Embedded ML в Сбере. Сегодня мы выкатили быстрые команды для умных колонок SberBoom. Они позволяют управлять самим устройством, а также телевизорами Sber, ТВ-приставками SberBox и умным домом с помощью колонки проще и быстрее.
Сегодня я расскажу, как удалось уместить все быстрые команды всего в 6 МБ и благодаря чему наше решение распознает не только простые команды вида «Включи свет», но и сложные со множеством параметров, например, «Яркость сорок пять процентов в коридоре». Мы рассмотрим, что такое спам-команды и как мы добились их корректного распознавания без задержек.
Что такое быстрые команды
Функциональность умных колонок достаточно широка, но часть команд владелец устройства использует значительно чаще, чем другие. Именно для них ему важно удобство в первую очередь. Зачастую такие команды состоят из одного-двух слов, при этом взаимодействие усложняет необходимость перед каждой командой произносить споттерное слово «Салют». Напомню, споттер — это модель на устройстве, которая детектирует ключевое слово «Салют», чтобы начать сессию с сервером для отправки звука.
Чтобы решить эту проблему, мы и сделали быстрые команды: они убирают необходимость говорить споттерное слово для таких команд. Более того, такие команды теперь распознаются локально — прямо на устройстве, а значит, срабатывают быстрее.
Какими бывают быстрые команды

Формулировки команд
Мы старались не ограничиваться конкретными фразами, чтобы общение с колонкой не превращалось в набор заученных заклинаний, а было более естественным. Поэтому колонка понимает синонимичные команды. Примеры возможных формулировок: «Сделай погромче», «Еще потише», «Дальше давай», «Выключи, пожалуйста», «Возобнови», «Следующий трек», «Правее», «На главную страницу».
В команде можно выделить намерение (Intent) и некоторое количество параметров (Slots). Например, «Громкость 3»: намерение — это «Установить громкость», а единственный параметр — «Значение громкости»: «3». Какими могут быть параметры:
Значение громкости: «Громкость три», «Громкость сорок семь процентов».
Место: «Включи свет на кухне», «Выключи свет везде», «Красный свет в зале».
Устройство: «Включи кондиционер», «Выключи люстру в зале».
Значение яркости: «Яркость девяносто процентов».
Цвет: «Красный свет в зале», «Сделай холодный свет».
Кроме того, мы дополнительно учли спам-команды — те, которые часто приходится говорить подряд не один раз. Так, навигация по GUI, чтобы добраться до нужного элемента («ниже ниже вниз вправо правее нажми»), относительное изменение громкости, если плохо помнишь её абсолютные значения («громче громче громче») — это спам-команды. Их можно говорить с минимальными паузами.
Какие стояли ограничения
В умных колонках значительно меньше вычислительных ресурсов, чем на сервере, поэтому постоянно приходится упираться в количество оперативки, диска и CPU ядер. На этот раз на колонках было свободно 6 МБ места на диске (а вот оперативной памяти было достаточно) и 0.7 одного ядра CPU суммарно для споттера и быстрых команд.
Что сделали
Обучение ASR
Первой идеей было обучить споттер с множеством классов на каждую команду, то есть бежать скользящим окном и отвечать на вопрос «есть ли в этом окне команда X», но этот вариант бы не позволил сделать большую вариативность формулировок и команды с параметрами. Кроме того, было бы проблематично понять, сколько раз повторяется одна и та же команда из одного слова подряд.
Поэтому мы решили зайти через задачу ASR (Automatic Speech Recognition, т.е. автоматическое распознавание речи). Обычно серверные модели для распознавания речи могут достигать миллиарда параметров и выполняются на мощных GPU для достижения хорошего качества. Так, серверная модель GigaAM Max в интеллектуальных колонках Sber — это 600 млн параметров. Но мы закономерно не могли позволить себе модель таких размеров для локальной работы, поэтому стали обучать очень маленький ASR. Сразу стало понятно, что полноконтекстная модель здесь не подходит — мы не можем сначала записать весь звук, а потом применить модель сразу ко всей записи. Пришлось бы после конца запроса разом сделать огромное количество вычислений, линейное зависимое от длины запроса, что привело бы к сильной задержке выполнения. Чтобы избежать этой проблемы, решили обучать стриминговую модель, размазывая вычисления по времени — как только приходит фрагмент нового звука, он сразу же обрабатывается.
Провели множество экспериментов; лучше всего себя показала архитектура Conformer RNN-T. Замерили качество — хотя из опробованных эта архитектура была лучшей, быстрые команды она определяла неоптимально (демо записали, но пришлось делать очень много дублей).
Fine-tuning на домен быстрых команд
Нам не требовался универсальный ASR; нам нужно было хорошо работать на срезе запросов быстрых команд, при этом не выдавать быструю команду на речи, где ее нет — то есть избегать ложных срабатываний. Поэтому мы могли ухудшить качество модели в общем случае, но за счет этого улучшить на быстрых командах.
Для этого сгенерировали и отобрали различные тексты запросов на нашем домене и записали с ними датасет в студии для обучения. Ввели метрики ASR FRR (False Reject Rate) — доля запросов быстрых команд, на которых мы не выдали полностью верный текст, и ASR FA/h (False Activations per Hour) — среднее количество выдачи текстов, которое можно условно распознать как ложную команду, в обычной речи за час; для этой метрики отдельно записали датасет речи без быстрых команд. И стали ими балансировать, аккуратно подбирая пропорции в обучающем датасете между различными быстрыми командами и негативами для дообучения модели ASR.
Улучшить качество сильно помогли аугментации — мы смешивали аудио из датасетов с записями музыки или ТВ, чтобы обучить модель адекватно различать быстрые команды на этом фоне. В итоге получили модель с Beta Ready качеством, но она занимала слишком много места на диске.
Сжатие модели
На этот момент мы уже применили всевозможные трюки с уменьшением архитектуры. В свою очередь, веса модели были квантизованы в int8 тип данных (уменьшило размер на 55%) — обычно веса модели обучаются в арифметике с плавающей точкой, а квантизацию весов используют на инференсе для оптимизации производительности и памяти. Но нужно было уменьшать гораздо сильнее. Сначала пришла на помощь обычная архивация, неплохо пожав модель (уменьшило еще на 41%). Посидев чуть дольше, нашли способ достичь необходимого размера — int5 квантизация.
При квантизации всех слоев подобным образом разваливалось качество, поэтому небольшую часть слоев оставляли в int8. Для быстрой реализации — просто зануляли 3 младших бита, а архиватор делал оставшуюся работу (уменьшило еще на 18%). Впоследствии реализовали нативную поддержку пятибитной квантизации. Чуть позже поняли, что можем добиться большей производительности модели, и для ускорения инференса использовали KV-cache — дополнительное переиспользование вычислений с предыдущих фреймов.
Финальные штрихи
Модель ASR — это еще не модель быстрых команд. Во-первых, добавили модуль, который определяет интент и параметры команды. Во-вторых, был необходим EOU (End of Utterance) — модель, которая определяет, что запрос завершен; это просто «включи свет» или, может, пользователь ещё договорит до «включи свет на кухне»? Чтобы не тратить память, добавили голову с EOU прямо в ту же модель ASR, обучая их совместно.
В-третьих, нужно было понять логику при завершении запроса. Если сбрасывать стейт энкодера и декодера, то придется после запроса засыпать на время, пока энкодер заполнит начальный стейт — а значит, плохо будет работать команда после команды подряд. Если сбрасывать только декодер, то конец первой команды может приклеиться ко второй. Не сбрасывать декодер нельзя, так как RNN-T не рассчитан на бесконечную рекурсию. На помощь пришла архитектура Stateless RNN-T, то есть рекурсивная обработка не всей последовательности токенов запроса, а только последних K. Это позволило вообще не сбрасывать никакие стейты между запросами, получая возможность успешно обрабатывать спам-команды.

Выкатили модель во внутреннюю бету, получили оттуда данные ложных срабатываний на созвучные для дообучения, дообучили на этих данных модель, довели до Prod Ready качества и зарелизили. Теперь голосовое управление воспроизведением музыки и громкостью, умным домом, движением по интерфейсу стало проще и естественнее.
Как попробовать
Включить быстрые команды можно в приложении или голосовой командой:
— Салют, включи быстрые команды!
Заключение
Быстрые команды — это определённо полезная фича, а поддержка запросов с параметрами и спам-запросов делает их ещё удобнее. С технологической точки зрения это была не самая простая задача. Зато теперь пользователи могут использовать колонку с комфортом.
Пользуясь случаем: в Telegram-канале GigaDev рассказываем о разработке GigaChat, делимся пошаговыми гайдами и не только. Присоединяйтесь!