Восходящая обработка* (bottom-up) тип обработки информации, основанный на поступлении данных из среды для формирования восприятия.Естественное распознавание речи также сильно зависит от контекстных сигналов, которые позволяют предвидеть содержание и временную структуру речевого сигнала. Ранее проведенные исследования показали, что во время восприятия непрерывной речи важную роль играет именно механизм прогнозирования. Этот процесс связывают с бета колебаниями.
Нисходящая обработка* (top-down) разбор системы на составляющие для получения представления о ее композиционных подсистемах способом обратной инженерии.Разработанная ранее нейрокомпьютерная модель, включающая соединение реалистичных тета- и гамма- возбуждающих/тормозных сетей, была способна предварительно обрабатывать речь таким образом, чтобы затем ее можно было правильно декодировать.
Привет всем. В данной статье я расскажу историю как мы с двоюродным братом сделали свою умную колонку.
На самом деле никакая она неумная, грубая и не особо полезная, но зато весёлая и с характером.
За мной сама идея, программирование, железо (подбор и настройка).
От брата 3D-модель, 3D-печать, железо (подбор и электромонтаж).
Статья по-большей части описывает то, что делал я, лишь немного касаясь 3D-модели.
Будучи большим фанатом известного мультсериала Футурама, однажды (где-то в 2018 году)мне захотелось заиметь самодельную голову робота Бендера Родригеса. В голове, в том числе крутились дурацкие варианты сделать её из какой-нибудь кастрюли. В силу своей глупости идея была забыта и заброшена ровно до того момента пока у одного хорошего человека, моего брата, товарища xbostа не появился 3D-принтер (весна 2019 года). И тут эта идея снова ожила
Обсудив эту идею за пивом, принялись за работу. Брат начал делать 3D-модель, а я искать, что из электронного хлама в ящике стола можно задействовать в проекте.
К тому моменту, у меня уже несколько лет валялась без дела плата Intel Galileo Gen2. И было желание задействовать её в этом проекте. Изначально никаких умных функций не планировалась, просто запихнуть её в корпус вместе с динамиком и светодиодами, вытащить кнопочку, при нажатии на которую воспроизводились бы цитаты из серий и светились диоды.
В то же время вокруг буйным цветом расцветали (и продолжают расцветать сейчас) умные колонки с голосовыми ассистентами. Они вежливы (Алиса правда хамовата), достаточно много всего умеют и не работают без Интернета. И по мне достаточно скучны.
Это привело к мысли, что на основе Бендера с его вредным, эгоистичным и вообще отрицательным характером можно сделать для себя отличную умную колонку. Этакий арт-проект, протест против умных колонок. И обязательно работающую оффлайн, даже ценой производительности.
Почитав о системах распознавания речи с возможностью оффлайн-распознавания, а также узнав, что ещё один хороший человек, коллега с прошлой работы, в то время писавший диплом, использует CMU Sphinx, выбор был остановлен на нём.
В силу своей природной хм невнимательности, я упустил существование более подходящей для моей задачи версии pocketsphinx, и начал с большого CMU Sphinx на Java.
Создал простенькие JSGF-грамматику и программу на Яве. Взял несколько наиболее известных цитат для проигрывания(with blackjack and hookers, bite my shiny metal ass, kill all humans и т.п.). Пробовал изначально на достаточно мощном компьютере(MacBook Pro 13-го года), был доволен результатом производительности, но понимал, что на Галилео меня ждёт нечто другое. Но дело оказалось совсем плохо.
Вообще Галилео уже давно заброшен Интелом. Стандартный Линукс, шедший с ним мне в принципе особенно не нравился. Поэтому попробовал с последней доступной для него сборкой Дебиан.
Туда с проблемами(подробности уже честно не вспомню) был поставлен JRE. В качестве устройства ввода/вывода аудио была использована USB-гарнитура. И Результат был крайне печален в плане производительности. Сейчас опять же не вспомню, возможно неправильную акустическую модель использовал на ней, но на реакции уходило 30-60 секунд. Плюс брат начал разрабатывать 3D-модель, и сказал, что габариты Галилео большеваты. Плюс отсутствие встроенного Wi-Fi. В общем Галилео опять отправилась в стол.
Решено было попробовать на гораздо более популярной Малинке, и выбор пал на слабую, но самую компактную версию Raspberry Pi Zero W. А также, прокачав внимательность, узнал о pocketsphinx (отличная статья для старта), перешёл на него, и переписал программу на Питоне.
При переходе на Малину, с подачи xbostа, родилось название для проекта Pinder (Raspberry Pi + Bender). Да, я прекрасно помню историю с Pidora в русскоязычном сегменте, но в данном случае намеренно выбрал такое лулзовое для русского уха название.
И так предыстория завершена, можно переходить непосредственно к описанию Пиндера.
Перечень использованных компонентов:
Raspberry Pi Zero W собственно основа всего.
UPS-Lite for Raspberry Pi Zero
Маленький ИБП для Малинки. Его штатный выключатель был выпаян, и к его контактам был припаян микропереключатель (см. далее по списку).
RGB адресная светодиодная лента на WS2812B, 60 светодиодов на 1 метр
Для подсветки и анимации зубов(18 штук) и глаз(2 штуки).
В принципе подойдёт любая, работающая в Линуксе. Подключается через OTG-кабель в единственный доступный для этого порт на Малине Зеро.
Усилитель и один динамик от таких колонок
В общем тут колхозный вариант был использован. Колонки были раздербанены, взят один динамик, усилитель вытащен из корпуса. Можно было купить отдельный усилитель и динамик, но для меня самым быстрым вариантом было тогда купить эти колонки и разобрать на части.
Но во время разработки поначалу использовался микрофон от телефонной гарнитуры Philips.
Микропереключатель с лапкой KLS7-KW10
Замыкается/размыкается при вставлении/вынимании "антенны" Бендера. Включает/выключает питание от UPS к Малине.
3,5мм разъём и гнездо jack. Для подключения микрофона к аудиокарте (микрофон находится наверху Бендера, в антенне).
В общем внутри всё достаточно колхозно.
Схема подключений очень простая:
Глаза сидят на отдельном пине от зубов и запараллелены между собой. Если бы делал сейчас, то включил бы глаза на одну ленту вместе с зубами, но что уже сделано, то сделано.
Здесь я не смогу рассказать многого, так как эта часть работы полностью брата.
3D-модель и небольшая инструкция доступны здесь.
Зубы и глаза напечатаны фотополимерной смолой на Anycubic Photon. Все остальные части PLA на Creality Ender 3.
Если будут какие-то вопросы по 3D-модели и печати можно задать мне, я их передам, либо попробовать напрямую спросить у xbostа на thingiverse (но не уверен будет ли он на них отвечать).
Краткая схема сборки:
Фото в процессе сборки и полностью собранном виде:
В качестве ОС используется штатный Raspbian (теперь Raspberry Pi OS).
За распознавание, как уже писалось выше, отвечает pocketsphinx. В качестве аудиоподсистемы используется Alsa (Pulseaudio выпилен).
Подсветка управляется с помощью библиотеки Adafruit_Blinka.
Данные о заряде/напряжении читаются из UPS-Lite посредством SMBus.
При разработке никакими лучшими практиками не руководствовался, поэтому код попахивает.
Поддерживается два языка: английский и русский. Для каждого языка своя JSGF-грамматика, набор аудио-сэмплов(сэмплов в репозитории нет, по соображениям авторских прав) и синтез речи. Русский дорабатывался(и дорабатывается) с некоторым опозданием.
Основной целью была просто возможность отвечать фановыми фразами из серий. Задаешь ему вопросы типа Как дела?, Где ты родился?, Что думаешь о Сири?. Ищется и воспроизводится ответ из сэмплов (в случае отсутствия сэмпла используется синтез речи, но об этом чуть позже).
Изначально скорость ответов на Малине была не очень шустрой (4-6 секунд до ответа):
Покопавшись у себя в коде, были найдены и уничтожены необязательные паузы. То же самое касалось и сэмплов (были пустые места вплоть до 1 секунды в начале файлов). А также прочитана информация о параметрах оптимизации pocketsphinx. Получилось уже получше:
Далее начал добавлять кое-какие полезные функции. Первой стала проигрывание музыки с локальной ФС или интернет-радио с помощью MPD. При этом докричаться до Бендера при проигрывании музыки на приличной громкости сложновато:
После достаточно долгого перерыва, живя на даче, была добавлена первая функция умного дома- управление освещением в своём углу через ModBusTCP. Вот только Бендера недостаточно иногда просто попросить включить свет, нужно обязательно сказать "пожалуйста". Работает достаточно шустро:
Потом однажды захотелось добавить читалку RSS-новостей. Это уже было невозможно без синтеза речи, но при этом хотелось, чтобы синтезатор звучал как, или хотя бы похоже на голос Бендера. Такой синтез речи на Малине Зеро представляется малореальным и поэтому в этом моменте пришлось сдаться и задействовать онлайн-сервис.
Почитав информацию и попробовав разные варианты остановился на Microsoft Azure Custom Speech.
При создании пользовательского голоса на выбор есть три варианта:
Statistical Parametric стандартное качество, нужно небольшое количество(для английского языка) сэмплов для обучения.
Concatenative высокое качество, нужно 6000 сэмплов для обучения.
Neural премиум-качество. По факту недоступно(доступно из США, при написании челобитной в Майкрософт зачем тебе это нужно и выкладывании 100000$).
Более подробно по технологиям синтеза речи можно почитать например на Википедии.
У меня не было большого количества сэмплов, поэтому сначала поигрался со Statistical Parametric. Результат был неплох, голос конечно не был похож(такой тип синтеза для сильной похожести и не предназначен), но интонации передавал сносно. В итоге на основе набора данных созданного с помощью этой модели я создал оффлайновую модель для CMU Flite, используемую в случае отсутствия связи с MS Azure.
Но всё же хотелось большей похожести и я решился попробовать собрать 6000 сэмплов для Concatenative модели, использующей отрывки из сэмплов настоящего голоса. Очень помог некий хороший человек, выложивший на YouTube 7 видео The Best of Bender. Надёргав оттуда сэмплов, приплюсовав к ним те что уже были и натравив на них майкрософтовский же Text-to-Speech (здесь у меня набор тулзов вспомогательных), получил что-то около 2000 транскрибированных сэмплов. Было принято решение просто скопировать это всё три раза под разными именами, чтобы получить 6000.
В итоге всё это было залито на обучение модели, и результат получился следующим:
Да конечно не идеально, но меня результат трудов устроил.
В итоге синтез речи используется не только для чтения новостей, но и в случае отсутствия оригинального сэмпла. Сначала ищется сэмпл. Если его нет, проверяется связь с порталом MS Azure, если есть синтезируется с помощью него. Если же связи с Azure нет используется локальная модель Flite(а для русского языка роботизированный голос eSpeak).
В сумме периодическими волнами и рывками разработка шла с весны 2019-го по весну 2020-го, в свободное время(хорошо видно по коммитам на гитхабе). Далее уже даже не волнами, просто отдельными всплесками.
Как таковых планов развития проекта нет. Если появляется желание и вдохновение, то добавляю что-нибудь. Так конечно напрашивается сделать режим просто болталки на нейронке, обученной на фразах Бендера. Ещё возможно добавить режим bluetooth-колонки(и чтобы зубы загорались синим в этом режиме) и приложение для смартфона, для активации схемы патриотизма.
Но для начала надо изобрести удлинитель пальца.
Исходный код ПО и 3D-модель выложены под открытыми лицензиями, так что если у кого-то есть желание сделать своего Бендера, добавить свои функции и улучшить буду рад.
На этом статья подошла к концу. Спасибо, что прочитали!
Всем хороших новостей!
При разработке ботов для Telegram и других месенджеров, периодически возникает задача распознавания и выполнения запросов, высказанных человеческим языком. Именно эта "фишка", по некоторому мнению, и является главным отличием ботов от приложений командной строки. Под катом описан собственный фреймворк для исполнения произвольных речевых команд. Описания ключевых концепций сопровождены примерами на языке Kotlin.
За основу для распознания речи возьмем нормализованные семантические представления. Их выбор обусловлен прежде всего простотой и легкостью реализации. Начнем с базиса, пример из исходников фреймворка:
/** Правило проверяет лексему на соответствие */typealias Rule = (String) -> Boolean/** Нормализованное семантическое представление */open class Semnorm(vararg val rules: Rule)/** Правило задает стемы для семантических представлений */fun stem(vararg stems: String): Rule = { stems.any(it::startsWith) }/** Правило задает точные соответствия для семантических представлений */fun word(vararg words: String): Rule = { words.any(it::equals) }/** Проверяем слово на соответствие семантике */fun String.matches(norm: Semnorm) = norm.rules.any { it(this) }
Теперь у нас появилась возможность задавать предопределенные нормализованные семантические представления в виде объектов:
object Day : Semnorm(stem("day", "суток", "сутк", "дня", "ден", "дне"))
Фреймворк ставит их в соответствие лексемам входящих фраз, и предложение начинает выглядеть, например так:
assertThat( "забань васю на 5 минут".tokenize(), equalTo( listOf( Token("забань", Ban), Token("васю", null), Token("на", null), Token("5", Number), Token("минут", Minute) ) ))
С распознаванием речи мы разобрались. Код токенизатора приложен в репозитории, доступном в конце статьи. Перейдем к исполнению команд из речи. А вот здесь и начинается самое интересное: фреймворк позволяет для каждого семантического представления навесить заданное поведение. Снова простейший пример, как распознать запрос справки на двух языках:
object Help : ExecutableSemnorm(stem( "помощ", "справк", "правил", "help", "rule", "faq", "start", "старт",)) { override fun execute(bot: Botm: Message) { val faq = message.from.relatedFaq() bot.sendMessage(m.chat.id, faq) }}
Что насчет более сложного поведения, зависящего от различных слов в предложении? Оно тоже поддерживается, вот как, например, исполняется, уже известное из тестов предложение забанить Васю:
object Ban : DurableSemonrm(stem( "ban", "block", "mute", "бан", "блок", "забан", "завали", "замьют",)) { override fun execute( bot: Bot, attackerMessage: Message, duration: Duration) { val victimMessage = attackerMessage.replyToMessage val victimId = victimMessage.from.id val untilSecond = now().epochSecond + duration.inWholeSeconds bot.restrictChatMember( attackerMessage.chat.id, victimId, untilSecond) }}
Откуда это семантическое представление знает о своей продолжительности? Дело в том, что ему вовсе не обязательно парсить всю цепочку токенов целиком. Достаточно задать только минимально необходимое поведение для каждого представления, например для времени:
object Week : Semnorm(stem("week", "недел")) { override fun toDuration(number: Long) = days(number) * 7}
Или для любых команд, зависящих от времени:
class DurableSemnorm(vararg rules: Rule) : ExecutableSemnorm(*rules) { final override fun execute( token: Iterator<Token>, bot: Bot, m: Message) = execute(bot, message, token.parseDuration()) abstract fun execute(bot: Bot, m: Message, duration: Duration)}
Благодаря такой архитектуре, нам больше не приходится думать о запутанной логике работы интерпретатора. Достаточно просто определить желаемые атрибуты для семантических представлений и наслаждаться результатом. Пример бота, использующего эту концепцию, можно посмотреть на Github: https://github.com/demidko/timecobot
Какое-то время назад мы писали цикл статей про то, как правильно измерять качество систем распознавания речи, и собственно снимали метрики с доступных решений (цикл статей 1, 2, 3) (на тот момент и коммерческих и некоммерческих решений). На Хабре была выжимка из этого цикла в рамках этой статьи, но до масштабного обновления исследования, достойного публикации на Хабре, руки никак не доходили (это требует как минимум большого количества усилий и подготовки).
Прошло некоторое время и пора обновить наше исследование, сделав его по-настоящему ультимативным. По сравнению с прошлыми исследованиями изменилось или добавилось следующее:
Мы старались следовать нашей стандартной методологии (см. ссылки выше) с небольшими изменениями:
wav
(или
просто PCM);ogg/opus
в системы,
которые его поддерживают, но потом отказались от такой идеи, потом
что резко вырос процент "пустых" ответов;Все модели, кроме Silero bleeding egde, это модели упакованные в production сервисы.
Датасет | Ashmanov | Sber | Sber | Silero | Silero new | Tinkoff | Yandex | ||
---|---|---|---|---|---|---|---|---|---|
default | enhanced | IVR | prod | bleeding edge | |||||
Чтение | 10 | 11 | 10 | 7 | 7 | 6 | 8 | 13 | |
Умная колонка | 35 | 24 | 6 | 30 | 27 | 27 | 14 | ||
Энергосбыт | 24 | 39 | 41 | 20 | 16 | 11 | 15 | 13 | |
Звонки (такси) | 47 | 16 | 18 | 22 | 32 | 13 | 12 | 21 | 15 |
Публичные выступления | 28 | 27 | 24 | 18 | 14 | 12 | 20 | 21 | |
Финансы (оператор) | 31 | 37 | 37 | 24 | 33 | 25 | 24 | 23 | 22 |
Аэропорт | 31 | 36 | 37 | 26 | 21 | 22 | 25 | 21 | |
Аудио книги | 22 | 60 | 54 | 19 | 24 | 20 | 28 | 22 | |
Радио | 24 | 61 | 40 | 26 | 18 | 15 | 27 | 23 | |
Умная колонка (далеко) | 42 | 49 | 8 | 41 | 27 | 52 | 18 | ||
Банк | 62 | 30 | 32 | 24 | 28 | 39 | 35 | 28 | 25 |
Звонки (e-commerce) | 34 | 45 | 43 | 34 | 45 | 29 | 29 | 31 | 28 |
Заседания суда | 34 | 29 | 29 | 31 | 20 | 20 | 31 | 29 | |
Yellow pages | 45 | 43 | 49 | 41 | 32 | 29 | 31 | 30 | |
Финансы (клиент) | 43 | 55 | 59 | 41 | 67 | 38 | 37 | 33 | 32 |
YouTube | 32 | 50 | 41 | 34 | 28 | 25 | 38 | 32 | |
Звонки (пранки) | 44 | 72 | 66 | 46 | 41 | 35 | 38 | 35 | |
Медицинские термины | 50 | 37 | 40 | 50 | 35 | 33 | 42 | 38 | |
Диспетчерская | 61 | 68 | 68 | 54 | 41 | 32 | 43 | 42 | |
Стихи, песни и рэп | 54 | 70 | 60 | 61 | 43 | 41 | 56 | 54 | |
Справочная | 39 | 50 | 53 | 32 | 25 | 20 | 27 |
Также интерес представляет процент пустых ответов сервисов (не совсем ясно, это баг или фича, артефакт нагрузки или самих моделей, но где-то снижение нагрузки помогает снизить этот процент). Традиционно этот процент высокий у Гугла. И как ни странно он довольно высокий у Сбера (и там скорее всего это фича, так как их пропускная способность явно не узкое место).
Ashmanov | Sber | Sber | Silero | Tinkoff | Yandex | |||
---|---|---|---|---|---|---|---|---|
default | enhanced | IVR | ||||||
Чтение | 0% | 0% | 0% | 0% | 0% | 5% | 4% | |
Умная колонка | 0% | 2% | 0% | 0% | 4% | 0% | ||
Энергосбыт | 1% | 12% | 13% | 6% | 0% | 2% | 1% | |
Звонки (такси) | 0% | 0% | 0% | 1% | 0% | 0% | 7% | 0% |
Публичные выступления | 0% | 1% | 0% | 0% | 0% | 2% | 0% | |
Финансы (оператор) | 0% | 0% | 0% | 2% | 0% | 0% | 6% | 0% |
Аэропорт | 0% | 8% | 10% | 4% | 0% | 4% | 0% | |
Аудио книги | 0% | 22% | 6% | 2% | 0% | 1% | 0% | |
Радио | 0% | 19% | 2% | 3% | 1% | 4% | 0% | |
Умная колонка (далеко) | 0% | 12% | 0% | 0% | 1% | 0% | ||
Банк | 0% | 2% | 3% | 1% | 1% | 0% | 5% | 1% |
Звонки (e-commerce) | 0% | 0% | 0% | 7% | 1% | 0% | 7% | 0% |
Заседания суда | 0% | 0% | 0% | 1% | 0% | 4% | 0% | |
Yellow pages | 1% | 13% | 9% | 14% | 0% | 2% | 2% | |
Финансы (клиент) | 0% | 0% | 7% | 35% | 9% | 0% | 5% | 0% |
YouTube | 0% | 13% | 1% | 6% | 0% | 1% | 0% | |
Звонки (пранки) | 1% | 33% | 12% | 17% | 5% | 1% | 1% | |
Медицинские термины | 0% | 1% | 0% | 7% | 0% | 6% | 1% | |
Диспетчерская | 3% | 26% | 28% | 25% | 0% | 2% | 4% | |
Стихи, песни и рэп | 2% | 19% | 3% | 25% | 0% | 1% | 1% | |
Справочная | 1% | 12% | 14% | 9% | 0% | 3% | 0% |
Неудивительно, что каждый силен в том домене, на котором фокусируется. Tinkoff на звонках в банк, справочную, финансовые сервисы. Сбер имеет ультимативно лучшие результаты на своей "умной колонке" (спекулирую, что они поделились в лучшем случае 1/10 своих данных) и в среднем неплохие показатели. IVR модель Сбера на доменах, где оригинальные данные лежат у нас в 8 kHz, показывает себя достойно, но она не ультимативно лучшая. Приятно удивил Яндекс в прошлых рейтингах их модели были не в списке лидеров, а сейчас точно лучше, чем в среднем по больнице. Другой сюрприз Google, который является аутсайдером данного исследования вместе с Ашмановым.
Также интересно посчитать количество доменов, где production модели поставщика лучшие / худшие (допустим с неким "послаблением" в 10% от лучшего или худшего результата):
Сервис | Лучше всех | Хуже всех |
---|---|---|
Ashmanov | 0 | 7 |
1 | 13 (9 у enhanced) | |
Sber | 2 | 0 |
Sber IVR | 4 | 4 |
Silero | 13 | 0 |
Tinkoff | 6 | 2 |
Yandex | 10 | 1 |
Как и ожидалось наша модель показывает в среднем неплохие показатели на всех доменах, заметно отставая на банках и финансах. Также если смотреть по формальной метрике "на каком числе доменов модель лучшая или почти лучшая" то наша модель как минимум лучше всех генерализуется. Если включить в забег нашу bleeding edge модель (мы пока не выкатили ее еще), то она отстает только на "умной колонке" и банковских датасетах, лидируя уже на 17 доменах из 21. Это логично, так как у нас нет своей колонки и банки очень неохотно делятся своими данными даже приватно.
У Сбера на момент тестирования было только gRPC API. Это не самое удачное решение для SMB клиентов с точки зрения удобства, имеющее более высокий порог на вход. Также в их реализации вообще не прокидываются важные ошибки (или отсутствуют в принципе, чем часто грешат корпоративные сервисы). Документация запрятана внутри портала их экосистемы, но в целом кроме лишней "сложности" проблем особо там нет, читать приятно. 40 страниц на два метода это конечно сильно (мы читали сначала в PDF), но документация хотя бы подробная и с примерами и пояснениями.
У Яндекса и Гугла стандартная корпоративная документация. Она несложная, но иногда длиннее, чем хотелось бы. Есть и обычные и потоковые интерфейсы. У Яндекса кстати она стала сильно приятнее и человечнее с момента, когда я в последний раз ее видел.
У Tinkoff само распознавание работает по умолчанию также через gRPC, а поверх написаны клиенты (в тех, которые мы разбирали было много лишнего). С учетом фокуса на enterprise (оставим за скобками этические, правовые и финансовые последствия монетизации банком ваших данных без явного согласия и возможности отказаться) это имеет больше смысла, чем то, что сделал Сбер. Это уже мои спекуляции, но скорее всего это в первую очередь артефакт разработки решения под свои нужды.
У сервиса Ашманова вообще нет документации, примеры не работают из коробки, пришлось немного позаниматься перебором для запуска. Отдельно отмечу, что обычно b2b сервисы не славятся читаемыми ошибками и читаемой документацией, но тут вообще не было ни ошибок, ни документации. Или 500-я ошибка или 200 с пустым ответом. Это создает легкий когнитивный диссонанс с учетом проработки анимации девушки-маскота, количества маркетинговых материалов и "успешных" кейсов.
У нашего сервиса само публичное АПИ весьма минималистичное и состоит из 2 методов (синтеза и gRPC нет еще в публичной документации) с примерами. Есть также gRPC АПИ, которое сейчас проходит обкатку. Наверное я тут не лучший судья, но основная ценность как мне кажется состоит в радикальной простоте для публичного АПИ и детальных инструкциях / сайзингах / опциях конфигурирования для более крупных клиентов.
Все АПИ, которые мы протестировали (кроме Ашманова) показали себя довольно бодро по скорости (это баг или фича решать вам). Для измерения пропускной способности мы считаем показатель секунд аудио в секунду на 1 поток распознавания (RTS = 1 / RTF):
Сервис | RTS per Thread | Threads | Комментарий |
---|---|---|---|
Ashmanov | 0.2 | 8 | |
Ashmanov | 1.7 | 1 | |
4.3 | 8 | ||
Google enhanced | 2.9 | 8 | |
Sber | 13.6 | 8 | |
Sber | 14.1 | 1 | |
Silero | 2.5 | 8 | 4-core, 1080 |
Silero | 3.8 | 4 | 4-core, 1080 |
Silero | 6.0 | 8 | 12 cores, 2080 Ti |
Silero | 9.7 | 1 | 12 cores, 2080 Ti |
Tinkoff | 1.4 | 8 | |
Tinkoff | 2.2 | 1 | |
Yandex | 5.5 | 2 | 8 много пустых ответов |
Поскольку никто не публикует сайзинги облачных и даже иногда коробочных (тут поправьте меня, если пропустил) версий своих систем публично (кстати прошлая версия нашего сайзинга например доступна по ссылке), то довольно сложно оценить адекватность работы систем по ресурсам. Ведь за АПИ может скрываться как одна VDS, так и сотни карт Nvidia Tesla, которыми любят хвастаться корпорации в своих пресс-релизах (что кстати частично подтверждается результатами Сбера пропускная способность там не падает от роста нагрузки совсем). Расчеты выше не являются заменой полноценным сайзингам.
В защиту нашей системы могу сказать, что за этим бенчмарком стоит довольно слабый сервер конфигурации EX51-SSD-GPU, у которого сейчас есть некоторая фоновая нагрузка и который скорее сейчас оптимизирован на скорость ответа а не на пропускную способность. Еще небольшой тонкий момент состоит в том, что мы считали время каждого запроса и суммировали и поэтому никак не нормализовывали результаты на пинг, но оставим это для следующих исследований.
Вообще меня очень приятно удивили результаты Сбера. На текущих версиях моделей у нас например сайзинг на 12 ядерном процессоре + GPU рассчитан на ~150 RTS. По идее это означает, что если мы поднимем тестовый и сервис на 12+ ядрах процессора на чуть более новой карточке, мы должны получить результаты более близкие к Сберу. У нас все равно не получается получить такие же высокие показатели без просадки от нагрузки, но какие-то выводы уже можно строить и получается все равно весьма достойно. Снимаем шляпу перед инженерами Сбера и ставим aspirational цель сделать наш сервис еще в 2-3 раза быстрее.
На цене мы останавливаться особо не будем (большая часть серьезных клиентов все равно не использует облако), но в очередной раз неприятный сюрприз преподнес Гугл выставив круглый счет за смешной (как нам кажется) объем. А ответ прост зачастую облачные корпоративные сервисы распознавания имеют не только крутой ценник (и в случае Гугла еще и в долларах), но и неочевидные системы округления вверх. В начале своего пути мы тестировали какой-то сервис из Великобритании который округлял до 60 секунд!
Довольно приятно, что наш публичный некоммерческий датасет Open STT, неоднократно обсуждавшийся на Хабре, был предвестником релизов публичных данных, например от Сбера. Но долгосрочно все равно хотелось бы видеть хотя бы какую-то соразмерность вклада госкорпораций количеству вложенных в них публичных денег. В сравнении с похожими релизами на западе, мы пока сильно отстаем. Да и Яндекс традиционно не публикует ничего полезного в сфере распознавания речи, интересно почему.
Технология распознавания эмоций в речи может может найти применение в огромном количестве задач. В частности, это позволит автоматизировать процесс мониторинга качества обслуживания клиентов call-центров.
Определение эмоций человека по его речи уже относительно насыщенный рынок. Я рассмотрела несколько решений от компаний российского и международного рынков. Попробуем разобраться, в чем их преимущества и недостатки.
1) Empath
В 2017 году был основан японский стартап Empath. Он создал платформу Web Empath, основанную на алгоритмах, обученных на десятках тысяч голосовых образцов японской медицинской технологической компании Smartmedical. Недостатком платформы является то, что она анализирует только голос и не пытается распознать речь.
Эмоции, передаваемые человеком по текстовому и голосовому каналу, часто не совпадают. Поэтому анализ тональности лишь по одному из каналов недостаточен. Деловым разговорам, особенно, присуща сдержанность в проявлении эмоций, поэтому, как правило, позитивные и негативные фразы произносятся абсолютно безэмоциональным голосом. Однако бывают и противоположные ситуации, когда слова не имеют эмоционального окраса, а голос ярко показывает настроение человека.
Также важное влияние на форму проявления эмоционального состояния оказывают культурные и языковые особенности. И попытки многоязычной классификации эмоций демонстрируют значительное снижение эффективности их распознавания [1]. Тем не менее, такое решение имеет место быть, а компания имеет возможность предлагать свое решение клиентам по всему миру.
В составе программного продукта Smart Logger II компании ЦРТ есть модуль речевой аналитики QM Analyzer, позволяющий в автоматическом режиме отслеживать события на телефонной линии, речевую активность дикторов, распознавать речь и анализировать эмоции. Для анализа эмоционального состояния QM Analyzer измеряет физические характеристики речевого сигнала: амплитуда, частотные и временные параметры, ищет ключевые слова и выражения, характеризующие отношение говорящего к теме [2]. При анализе голоса первые несколько секунд система накапливает данные и оценивает, какой тон разговора был нормальным, и далее, отталкиваясь от него, фиксирует изменения тона в положительную или отрицательную сторону [3].
Недостатком такого подхода является неверное определение нормального тона в случае, когда уже в начале записи речь имеет позитивный или негативный эмоциональный окрас. В таком случае оценки на всей записи будут некорректными.
Компания Neurodata Lab разрабатывает решения, которые охватывают широкий спектр направлений в области исследований эмоций и их распознавания по аудио и видео, в том числе технологии по разделению голосов, послойного анализа и идентификации голоса в аудиопотоке, комплексного трекинга движений тела и рук, а также детекции и распознавания ключевых точек и движений мышц лица в видеопотоке в режиме реального времени. В качестве одного из своих первых проектов команда Neurodata Lab собрала русскоязычную мультимодальную базу данных RAMAS комплексный набор данных об испытываемых эмоциях, включающий параллельную запись 12 каналов: аудио, видео, окулографию, носимые датчики движения и другие о каждой из ситуаций межличностного взаимодействия. В создании базы данных приняли участие актеры, воссоздающие различные ситуации повседневного общения [4].
На основе RAMAS с помощью нейросетевой технологии компания Neurodata Lab создала решение для контакт-центров, позволяющее распознавать эмоции в голосе клиентов и рассчитывать индекс удовлетворенности обслуживанием непосредственно во время разговора с оператором. При этом анализ осуществляется как на голосовом уровне, так и на семантическом, при переводе речи в текст. Система также учитывает дополнительные параметры: количество пауз в речи оператора, изменение громкости голоса и общее время разговора.
Однако стоит заметить, что база данных для обучения нейронной сети в данном решении была подготовлена специально с участием актеров. А, согласно исследованиям, переход от модельных эмоциональных баз к распознаванию эмоций в спонтанной речи ведет к заметному снижению эффективности работы алгоритмов [1].
Как видим, у каждого решения есть свои плюсы и минусы. Попробуем взять от аналогов все самое лучшее и реализовать собственный сервис для анализа телефонных звонков.
Empath |
ЦРТ |
Neurodata Lab |
Разрабатываемый сервис |
|
семантический анализ |
- |
+ |
+ |
+ |
русский дата-сет |
- |
нет |
+ |
+ |
дата-сет спонтанных эмоций |
+ |
- |
+ |
В качестве материалов для создания русскоязычного эмоционального дата-сета со спонтанной речью мне была предоставлена база записей телефонных разговоров от IT-компании Эм Си Арт.
Общий алгоритм работы разрабатываемого сервиса выглядит следующим образом.
Блок-схема алгоритма обработки звонкаПри реализации были использованы следующие инструменты:
Шумоочистка RNNoise_Wrapper
Диаризация pyAudioAnalysis
Транскрибация vosk-api
Анализ эмоций текста dostoevsky
Для распознавания эмоций по голосу не нашлось подходящей библиотеки с открытым исходным кодом, поэтому модель для решения данной задачи будем создавать сами.
Для работы со звуковой волной нужно сначала преобразовать ее в цифровой вид. Для этого выполняется процедура дискретизации, после которой будет получен массив чисел, каждое из которых представляет амплитуду звуковой волны через фиксированные промежутки времени. Обучение нейронной сети на этих данных было бы неэффективно, так как их объем очень большой. Чтобы решить данную проблему, можно выполнить преобразование сигнала в набор акустических характеристик. Для этого я использовала библиотеку Librosa.
Я выбрала пять наиболее часто используемых признаков:
мел-частотные кепстральные коэффициенты (MFCC)
вектор цветности
мел-спектрограмма
спектральный контраст
тональный центроид (Tonnetz)
На основе выделенных из записей телефонных разговоров отрезков я составила 3 варианта дата-сетов с различным количеством выделяемых классов эмоций. Также для сравнения результатов обучения была взята берлинская база эмоциональной речи Emo-DB, созданная с привлечением профессиональных актеров.
Сначала я попробовала обучить простые классификаторы библиотеки scikit-learn:
SVC
RandomForestClassifier
GradientBoostingClassifier
KNeighborsClassifier
MLPClassifier
BaggingClassifier
В результате обучения на дата-сете Emo-DB получилось достичь точности распознавания 79%. Однако при тестировании полученной модели на размеченных мной записях телефонных разговоров, точность оказалась равной всего 23%. Это подтверждает тезисы о том, что при многоязычной классификации и переходе от модельных эмоций к спонтанным точность распознавания значительно снижается.
На составленных мной дата-сетах получилось достичь точности 55%.
База данных |
Количество классов |
Количество записей |
Модель |
Точность |
Emo-DB |
4 |
408 |
MLPClassifier |
79.268%/22.983% |
MCartEmo-admntlf |
7 |
324 |
KNeighborsClassifier |
49.231% |
MCartEmo-asnef |
5 |
373 |
GradientBoostingClassifier |
49.333% |
MCartEmo-pnn |
3 |
421 |
BaggingClassifier |
55.294% |
При увеличении количества выделяемых классов эмоций точность распознавания падала. Это так же может быть связано с уменьшением выборки ввиду сложности разметки по большому количеству классов.
Далее я попробовала обучить сверточную нейронную сеть на дата-сете MCartEmo-pnn. Оптимальной архитектурой оказалась следующая.
Точность распознавания такой сети составила 62.352%.
Далее я провела работу по расширению и фильтрации дата-сета, в результате чего количество записей увеличилось до 566. Модель заново была обучена на этих данных. По итогу точность распознавания увеличилась до 66.666%. Это говорит о необходимости дальнейшего расширения набора данных, что приведет к увеличению точности распознавания эмоций по голосу.
График истории обучения и матрица ошибок полученной CNNПри проектировании сервиса была выбрана микросервисная архитектура, в рамках которой создается несколько независимых друг от друга узко сфокусированных сервисов, решающих только одну задачу. Любой такой микросервис можно отделить от системы, и дописав некоторую логику, использовать как отдельный продукт.
Сервис Gateway API производит аутентификацию пользователей по стандарту JSON Web Token и выполнять роль прокси-сервера, направляя запросы к функциональным микросервисам, находящимся в закрытом контуре.
Разработанный сервис был проинтегрирован с Битрикс24. Для этого было создано приложение Аналитика речи. В понятиях Битрикс24 это серверное приложение или приложение второго типа. Такие приложения могут обращаться к REST API Битрикс24, используя протокол OAuth 2.0, а также регистрировать свои обработчики событий. Поэтому достаточно было в сервере добавить роуты для установки приложения (по сути регистрация пользователя), удаления приложения (удаление аккаунта пользователя) и обработчик события OnVoximplantCallEnd, который сохраняет результаты анализа записей в карточках связанных со звонками CRM-сущностей. В качестве результатов приложение добавляет расшифровку записи к звонку и комментарий с оценкой успешности разговора по пятибалльной шкале с прикреплением графика изменения эмоционального состояния по каждому участнику разговора.
Заключение
В работе представлен результат исследования на тему
распознавания эмоций в речи, в ходе которой на основе русскоязычных
записей телефонных разговоров был создан дата-сет эмоциональной
речи, на котором была обучена CNN. Точность распознавания составила
66.66%.
Был реализован веб-сервис, с помощью которого можно выполнять
очистку аудиозаписей от шума, диаризацию, транскрибацию и анализ
эмоций в аудиозаписи или текстовых сообщениях.
Сервис был доработан, чтобы его также можно было использовать как
приложение Битрикс24.
Данная работа выполнялась по заказу компании Эм Си Арт в рамках ВКР
бакалавра образовательной программы "Нейротехнологии и
программирование" университета ИТМО. Также по этой теме у меня был
доклад на X КМУ и была принята на
публикацию в "Сборнике трудов Конгресса" статья.
В ближайшее время планируется работа по улучшению точности
распознавания эмоций по голосу через расширение набора данных для
обучения нейросети, а также замена инструмента диаризации, так как
качество его работы на практике оказалось недостаточно
хорошим.
Список источников
Давыдов, А. Классификация эмоционального состояния диктора по голосу: проблемы и решения / А. Давыдов, В. Киселёв, Д. Кочетков // Труды международной конференции "Диалог 2011.". 2011. С. 178185.
Smart Logger II. Эволюция систем многоканальной записи. От регистрации вызовов к речевой аналитике [Электронный ресурс]. Режим доступа: http://www.myshared.ru/slide/312083/.
Smart logger-2 не дремлет. Эмоции операторов call-центров и клиентов под контролем [Электронный ресурс]. Режим доступа: https://piter.tv/event/_Smart_logger_2_ne_drem/.
Perepelkina, O. RAMAS: Russian Multimodal Corpus of Dyadic Interaction for Studying Emotion Recognition / O. Perepelkina, E. Kazimirova, M. Konstantinova // PeerJ Preprints 6:e26688v1. 2018.
Небольшой проект. Простая реализация. Заметка по диалплану астериск, командам консоли и АПИ распознавания Яндекса. Вы прочитаете и не наступите на мои грабли, я прочитаю через полгода-год и вспомню, что делал.
Задача: получать текстовое представление разговоров, записанных на астериске.
Сначала запись разговора
MixMonitor записывает разговор. Обычно MixMonitor записывает в один канал обоих собеседников. Нам надо получить каждый канал в отдельном файле. Поэтому есть две опции r и t, где мы можем указать файлы для записи разных каналов.
Также используется параметр b - для начала записи в момент начала разговора.
С 16 астериска была опция S - для синхронизации t и r файлов, (в тот, который позже начался записываться добавлялась тишина в начало файла). С 18 астериска опцию S убрали, т.к. это стало поведением по умолчанию, а добавили контр-опцию n. Но я использую b, поэтому эти дополнительные пляски мне не потребовались.
MixMonitor(record-o.wav,br(record-r.wav)t(record-t.wav),command)
Затем также в команде MixMonitor'а мы укажем команду для выполнения после записи. В рамках этой команды мы нормализуем каждую запись - выровняем по уровню и затем смерджим две записи в один двухканальный файл.
sox --norm record-t.wav record-t-norm.wav // нормализация записи одной стороны разговора
sox --norm record-r.wav record-r-norm.wav // нормализация записи второй стороны разговора
sox record-r-norm.wav record-t-norm.wav --channels 2 --combine merge record.wav // сливаем записи в один файл
Теперь итоговый файл можно прослушать в стерео режиме - в одном ухе слышно одного участника разговора, во втором - второго участника разговора. Интересный эффект присутствия, как будто по ролям читают, но не всем нравится такой формат прослушивания.
Для прослушивания можно использовать файл record-o.wav - первый файл из MixMonitor'а, записан традиционным методом, привычным для уха.
Файлы в формате wav достаточно много места занимают. Поэтому для хранения я их конвертирую в mp3 и копирую на хранилище.
Еще пара вариантов как организовать раздельную запись каналов на астериске
https://howto.a17.su/asterisk/call-recording.html
https://voxlink.ru/kb/asterisk-configuration/integraciya-asterisk-so-speech-analytics/
Теперь распознавание
Для распознавания дальше использую сервис Яндекса.
У Яндекса есть несколько API для распознавания: короткие аудио, длинные аудио и потоковое. Короткие - это до 30 секунд, поэтому пользуюсь API для длинных аудио.
Длинные аудио - передать можно wav или ogg файлы. С wav файлами дело не пошло, и в самом API еще необходимо указывать дополнительные параметры для wav-формата, поэтому я прежде чем отправлять на распознавание переконвертирую в ogg. Яндекс определит, что ogg двухканальный и распознает его по двум каналам без дополнительных параметров
/usr/bin/ffmpeg -i record.wav -acodec libopus record.ogg // команда переконвертации в ogg
Также есть пара нюансов
Во-первых, длинные аудио (прежде чем распознать) необходимо закачать в облако Яндекса, а в сервис распознавания передать уже ссылку на запись в облаке.
Хранилище Яндекса является S3-совместимым, поэтому для закачивания подойдет любая утилита или библиотека работающая с S3-хранилищем Амазона. Для хранения файлов в хранилще используются buckets.
Документация на Яндекс.Storage
Второе, сначала мы создаем задание на распознавание, получаем его id. А уже потом по его id чекаем на наличие результата (при этом количество операций на проверку статуса заданий ограничено, немало, конечно, но и не бесконечно).
Документация на Яндекс.Облако Распознавание длинных аудио
Документация на Яндекс.Облако Отслеживание статуса операции
Так получилось, что мое тестирование было в августе 2020, и попало на какой-то факап очереди заданий. И поэтому распознавания производились очень долго - по 2 и более часов.
Т.к. в Яндекс.Облаке и поддержка платная, отдельной строкой, то на мой тикет не отвечали оперативно. В чате же Яндекс.Облака достаточно быстро сообщили, что есть проблемы. Ну, а позже и на тикет ответили. И очередь починили. в штатном режиме все работает вполне оперативно.
По тарификации распознавания
Хранилище: место и операции - это тарифицируется. Распознавание - тоже. Все понемногу. Использую корпоративный тариф.
Тарификация одноканальных и двухканальных записей одинаковая, т.е. по деньгам нет разницы распознать одну минуту одноканальной записи или одну минуту двух каналов (а вот три канала будет уже вдвое дороже).
Посчитать на Тарификаторе Яндекса (раздел SpeechKit)
Ключи доступа. Тут главное не запутаться, так как у вас будут ключи и от сервиса распознавания (API ключ), и от хранилища S3 (статический ключ). Оба вида ключа на сервисном аккаунте.
Надеюсь, заметка сэкономит вам несколько минут, и вы быстрее реализуете свой проект по необходимости.