Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Контекстно-зависимый диалог с Kinect
Продукты и технологии:
Microsoft Kinect
В статье рассматриваются:
- значение контекстно-зависимого диалога и мультимодальной коммуникации;
- архитектура Kinect;
- класс SpeechTracker;
- применение словаря для выбора правильного намерения пользователя;
- запуск программы;
- свойство Confidence;
- создание иллюзии помощника-человека.
Исходный код можно скачать по ссылке
Познакомьтесь с Lily (Лили), моим секретарем. Мы часто общаемся, и по моим указаниям Lily выполняет рутинные деловые задачи, например ищет информацию и работает с документами Microsoft Office. Но, что важнее, Lily — виртуальный секретарь, WPF-приложение с поддержкой Microsoft Kinect, которое является частью проекта развития средств контекстно-зависимого диалога и мультимодальной коммуникации.
Прежде чем рассматривать конкретный код моего приложения (я разработал его в рамках своей дипломной работы в Университете Джорджа Мейсона), я поясню, что подразумеваю под контекстно-зависимым диалогом и мультимодальной коммуникацией.
Контекстно-зависимый диалог и мультимодальная коммуникация
Мы, люди, обладаем разнообразными и сложными средствами общения. Рассмотрим следующий сценарий: ребенок начинает плакать. Когда малыш замечает, что его мама на него смотрит, он указывает на погремушку, лежащую на полу. Мама сочувственно улыбается, как обычно делают мамы, наклоняется, поднимает погремушку и возвращает ее ребенку. Довольный, что получил назад свое сокровище, малыш вскрикивает и хлопает в ладоши, чтобы затем жадно вцепиться в погремушку.
Эта сцена описывает простую последовательность событий. Но рассмотрим ее подробнее. Давайте изучим данные виды коммуникации. Представим себе внедрение системы программного обеспечения, из которой убрали или малыша или маму, а коммуникации содействует система. Вы сразу можете себе представить, насколько действительно сложны и запутанны способы общения, применяемые обеими действующими сторонами. В понимании плача ребенка, вскрика радости и звука от хлопка в ладоши задействовано распознавание аудиосигналов. Чтобы понять жесты ребенка, указывающего на погремушку, а также сделать вывод о том, что через сочувственную улыбку мама подразумевает мягкий укор, необходим визуальный анализ. Поскольку такие распространенные действия, как в этом случае, происходят часто, мы принимаем за данность используемый уровень сложности до тех пор, пока нам не приходится применять тот же уровень опыта с машиной.
Немного усложним коммуникацию. Возьмем такой сценарий. Вы входите в комнату, где разговаривает несколько человек. Вы слышите всего одно слово: «cool». Остальные в комнате выжидательно смотрят на вас. А что вы можете добавить? Ведь «cool» может много чего означать. К примеру, кто-то, возможно, говорил перед этим о температуре в помещении. А может, выражал одобрение («that car is cool»). Он мог обсуждать и отношения между странами («negotiations are beginning to cool»). Без опоры на контекст, окружающий это слово, мало шансов на понимание значения слова в момент его произнесения. Необходим некий уровень семантического понимания для того, чтобы уловить подразумеваемое значение. Эта концепция лежит в основе данной статьи.
Lily — виртуальный секретарь в обстановке типичного бизнес-офиса.
Проект Lily
Я создал проект Lily как финальный для CS895: Software for Context-Aware Multiuser Systems в Университете Джорджа Мейсона под руководством Жуау Педро Соуза (Dr. Joao Pedro Sousa). Как упоминалось, Lily — виртуальный секретарь в обстановке типичного бизнес-офиса. Я использовал устройство Kinect и Kinect for Windows SDK beta 2. Kinect предоставляет цветную видеокамеру, датчик глубины (depth-sensing camera), решетку из четырех микрофонов и удобный API, с помощью которого можно создавать естественные UI. Кроме того, на сайтах Microsoft Kinect for Windows (microsoft.com/en-us/kinectforwindows) и Channel 9 (bit.ly/zD15UR) есть масса полезных примеров. Сравнительно недорогой пакет Kinect дал невероятные возможности разработчикам. Kinect побил мировой рекорд Гиннеса в номинации «самое быстро продаваемое бытовое устройство» (on.mash.to/hVbZOA). Технические характеристики Kinect (документированные по ссылке bit.ly/zZ1PN7) таковы:
- цветная видеокамера VGA с разрешением 640×480 при 30 кадрах в секунду;
- датчик глубины с разрешением 640×480 при 30 кадрах в секунду;
- решетка из четырех микрофонов;
- поле обзора:
- горизонтальное: 57 градусов;
- вертикальное: 43 градуса;
- физическая амплитуда наклона (tilt range): ± 27 градусов;
- диапазон чувствительности датчика глубины: 1,2–3,5 м;
- система отслеживания по скелету:
- возможность отслеживания до шести человек, в том числе двух активных игроков;
- возможность отслеживания 20 сочленений на активного игрока;
- система подавления эхо-сигналов, улучшающая качество голосового ввода;
- распознавание речи.
Архитектура Kinect
Microsoft также предоставляет схему архитектуры, на которой построен Kinect (рис. 1).
Цифры в кружках на рис. 1 соответствуют следующему.
- Аппаратная часть Kinect: Аппаратные компоненты, в том числе датчик Kinect и USB-концентратор, через который датчик подключается к компьютеру.
- Драйверы Microsoft Kinect: Драйверы Windows 7 для датчика Kinect устанавливаются при установке SDK. Драйверы Microsoft Kinect поддерживают:
- микрофонную решетку датчика Kinect как аудиоустройства режима ядра, к которому можно обращаться через стандартные аудио-API в Windows;
- потоковое изображение и данные глубины;
- функции перечисления устройств, позволяющие приложению использовать более одного датчика Kinect, если они подключены к компьютеру.
- NUI API: Набор API, получающих данные от датчиков изображения и управляющих устройствами Kinect.
- KinectAudio DMO: Kinect DMO расширяет поддержку микрофонных решеток в Windows 7, чтобы обеспечить формирование диаграммы направленности (beamforming) и функциональность локализации источника.
- Стандартные API в Windows 7: Звуковые, речевые и медийные API в Windows 7, описанные в Windows 7 SDK и Microsoft Speech SDK (Kinect for Windows SDK beta Programming Guide).
В этой статье я продемонстрирую, как я использовал микрофонную решетку и механизм распознавания речи (speech recognition engine, SRE) для создания контекстно-зависимых голосовых команд. Иначе говоря, команды, которые слушает Kinect, будут зависеть от контекста, создаваемого пользователем. Я покажу инфраструктуру, в которой приложение будет отслеживать действия пользователя, загружая и выгружая грамматики (grammars) в SRE (в зависимости от контекста), что дает пользователю естественные и интуитивно понятные средства взаимодействия с Lily без необходимости запоминать специфические команды и шаблоны использования.
Класс SpeechTracker
Для проекта Lily я использовал отдельный класс SpeechTracker, отвечающий за всю обработку речи. SpeechTracker был спроектирован так, чтобы он выполнялся в потоке, независимом от UI; это делает его гораздо более «отзывчивым», что крайне важно в этом приложении. Какая польза от помощника, если он вас никогда не слушает?
Прежде чем забираться в сердцевину SpeechTracker, стоит подумать о нескольких вещах. Во-первых, об определении контекстов, которые приложение должно прослушивать. Например, у Lily будут контексты «Research» (обработка действий, относящихся к поиску данных и информации), «Office» (обработка таких действий, как открытие документов Word и презентаций PowerPoint, а также других задач, относящихся к офисной работе), «Operations» (пользователь может изменять параметры устройства Kinect) и «General» (обработка всех мелочей, которые могут оказаться независимыми от любого реального контекста, например «Сколько времени?», «Завершить работу» или обратная связь с системой). В своем примере я создал еще несколько контекстов, но самый важный из них — «Context». Этот контекст сообщает Lily, в какой режим следует переключиться. Другими словами, перечислениеContext используется для определения контекста, который должен прослушиваться системой. Подробнее об этом — немного позже.
Затем каждый контекст моделируется с помощью перечислений, как показано на рис. 2.
Рис. 2. Пример контекста
Смоделировав контексты, нужно сделать следующий шаг — определить средства, передающие намерение пользователя в конкретном контексте. Для этого я использовал структуру, которая просто хранит контексты и содержит переменную типа bool:
struct Intention
{
public Context context;
public General general;
public Research research;
public Office office;
public Operations kinnyops;
public Meeting meeting;
public Translate translate;
public Entertain entertain;
public bool contextOnly;
}
Важна булева переменная. Если Intention — смена контекста, то contextOnly равна true, в ином случае — false. Ее предназначение станет понятнее потом, а пока просто помните, что это необходимый флаг.
Каково намерение пользователя?
Теперь, когда проект Lily способен сообщать Intention (намерение), он должен знать, когда и какой объект Intention следует использовать в период выполнения. Для этого я создал словарь System.Collections.Generic.Dictionary<TKey, TValue>, в котором ключом является произнесенное слово (или фраза), а значением — сопоставленный Intention. Начиная с Microsoft .NET Framework 3.0 у нас есть лаконичный способ создания объектов и инициализации свойств, как показано на рис. 3.
Рис. 3. Словарь ContextPhrases
Этот словарь определяет фразы Context. Ключами являются слова и фразы, произносимые конечным пользователем, которые потом сопоставляются с неким Intention. Объявление каждого Intention и инициализация его свойств требует всего одной строки. Заметьте, что один Intention (скажем, Research) можно сопоставить с несколькими отдельными словами и фразами. Это позволяет создавать богатые лексические словари, способные моделировать язык конкретной предметной области и лексикон данного пользователя. (Обратите внимание на один важный момент, относящийся к ContextPhrases: свойство contextOnly установлено в true. Это сообщает системе, что данное действие используется только для смены активного контекста. Тем самым можно сократить логику обработки произнесенных слов.)
Более наглядный пример сказанному см. во фрагменте кода из словаря GeneralPhrases, показанного на рис. 4.
Рис. 4. Словарь GeneralPhrases
Заметьте, что в нескольких случаях один и тот же Intention моделируется с помощью разных фраз, давая системе возможность обрабатывать диалог с пользователем так, чтобы это выглядело было естественно для человека. Одно ограничение, о котором вы должны знать, заключается в том, что любой словарь, предназначенный для использования в SRE, может содержать не более 300 записей. Поэтому будет разумным тщательно продумывать содержимое лексических словарей и грамматики. Даже без такого ограничения словари следовало бы поддерживать как можно меньшими для максимального быстродействия.
Теперь, когда лексические словари связаны с объектами Intention, я могу перейти к более интересной части. Первым делом системе нужно получить описатель SpeechRecognitionEngine:
ri = SpeechRecognitionEngine.InstalledRecognizers()
.Where(r => r.Id == RecognizerId).FirstOrDefault();
if (ri == null)
{
// No RecognizerInfo => bail
return;
}
sre = new SpeechRecognitionEngine(ri.Id);
Далее берем ранее подготовленные фразы и преобразуем их в Choices:
// Формируем категории Choices
var contextPhrases = new Choices();
foreach (var phrase in ContextPhrases)
contextPhrases.Add(phrase.Key);
Сравнительно недорогой пакет Kinect дал невероятные возможности разработчикам.Я выполняю ту же операцию для всех ранее созданных фраз. Затем Choices передается методуAppend в GrammarBuilder. Последнее, что я делаю, — создаю объекты Grammar и загружаю их в SRE. Для этого я просто создаю новый Grammar и передаю GrammarBuilder, представляющий нужную грамматику, как показано на рис. 5.
Рис. 5. Создание объектов Grammar и их загрузка в механизм распознавания речи (SRE)
// И наконец, создаем наши объекты Grammar
gContext = new Grammar(gbContext);
gGeneral = new Grammar(gbGeneral);
gResearch = new Grammar(gbResearch);
gOffice = new Grammar(gbOffice);
gOperations = new Grammar(gbOperations);
gMeeting = new Grammar(gbMeeting);
gTranslation = new Grammar(gbTranslation);
gEntertain = new Grammar(gbEntertain);
// В этой точке мы будем загружать
// только грамматики Context и General
sre.LoadGrammar(gContext);
sre.LoadGrammar(gGeneral);
allDicts = new List<Dictionary<string, Intention>>() {
ContextPhrases,
GeneralPhrases,
ResearchPhrases,
OfficePhrases,
OperationsPhrases,
MeetingPhrases,
TranslationPhrases,
EntertainPhrases
};
Заметьте, что здесь лишь два объекта Grammar — gContext и gGeneral — загружаются в SRE, но все остальные грамматики были добавлены в список фраз. Вот как я воздействую на контекстно-зависимую часть прослушивания. Общие (general) и контекстные (context) фразы должны постоянно присутствовать в SRE, так как они могут быть произнесены в любое время безо всякого предопределенного шаблона. Однако при идентификации контекстной фразы будет загружаться одна дополнительная грамматика. Чтобы завершить эту часть приложения, я просто обрабатываю событие SpeechRecognized в SRE. Аргумент SpeechRecognizedEventArgs используется для оценки того, что было произнесено. Вернемся к рис. 4; если аргумент имеет Intention, который помечен как contextOnly, то системе нужно выгрузить третий Grammar (при его наличии, конечно) из SRE и загрузить новый идентифицированный Grammar. Это позволяет приложению слушать разные лексические словари и лексиконы в зависимости от контекста, который находится в области видимости в данный момент.
В словаре (рис. 4) есть ключ типа string, представляющий произнесенную фразу, и значение типа Intention, которое указывает, какие действия ожидает пользователь от системы. В процедуре добавления каждой записи в словарь содержится конструктор объекта Intention, который обычно состоит из трех компонентов: сопоставления контекста, меняет ли данное событие контекст и (если контекст остается прежним) какое действие подразумевается.
Определив все словари поддерживаемых фраз, я добавляю эту информацию в SRE, предоставляемую устройством Kinect, как показано на рис. 6.
Рис. 6. Механизм распознавания речи
Intention | Намерение |
Context | Контекст |
Phrases | Фразы |
Speech Recognition Engine | Механизм распознавания речи |
В конечном счете это сообщает SRE, что прослушивать и как помечать информацию, когда она услышана. Однако в попытке сделать систему более интеллектуальной и удобной в использовании я ограничил систему так, чтобы в SREединовременно загружались только три контекста с соответствующими словарями фраз. Фразы Context и General всегда загружены из-за их фундаментальной природы. Третий загружаемый контекст и фразы определяются взаимодействием с конечным пользователем. Когда Lily слушает окружающую среду, «она» реагирует на ключевые слова и фразы и заменяет один набор фраз в SRE другим. Прояснить это поможет пример.
Как это работает
При первом запуске Lily загружает ContextPhrases и GeneralPhrases в SRE. Это позволяет системе слушать команды, которые заставят ее либо сменить контекст, либо выполнить общие действия. Например, по окончании инициализации, если пользователь спросит: «Сколько времени?», Lily «поймет» это (это часть GeneralPhrases) и отреагирует, сообщив текущее время. Аналогично, если пользователь произносит «мне нужна информация», Lily понимает, что это флаг загрузки ResearchPhrases в SRE и начнет слушать команды в контексте Research. Это дает возможность Lily достигать трех важных целей.
- Максимальное быстродействие за счет того, что Lily слушает минимальный набор релевантных фраз.
- Возможность использования языка, лексемы которого неоднозначны и имеют разный смысл в разных контекстах (вспомните пример со словом «cool»), благодаря поддержке одного лексикона в указанном контексте.
- 3. Система может слушать несколько разных фраз, но сопоставлять их все с одинаковыми действиями (например, все фразы «Lily, what time is it?», «What time is it?» и «Do you know the time?» можно сопоставить с одним действием — ответом пользователю о текущем времени). Потенциально это позволяет поддерживать богатый лексикон в контекстно-зависимом диалоге с системой. Вместо того чтобы заставлять пользователя запоминать ключевые слова и фразы один в один, проектировщик может моделировать несколько разных распространенных способов указывать одно и то же. Тем самым пользователь получает гибкость в выражении команд разными словами. Одна из целей вездесущих вычислений (ubiquitous computing) состоит в том, чтобы устройства ушли на задний план. Создание контекстно-зависимых диалоговых систем наподобие Lily помогает пользователю абстрагироваться от компьютера — он становится для него помощником, а не набором выполняемых на нем приложений.
В словаре есть ключ типа string, представляющий произнесенную фразу, и значение типа Intention, которое указывает, какие действия ожидает пользователь от системы.
Вооружив Lily всеми необходимыми знаниями теперь можно слушать команды и реагировать действиями, подходящими в текущем контексте. Осталось лишь создать экземпляр KinectAudioSource и указать его параметры. В проекте Lily я выделил всю обработку аудио в класс SpeechTracker. Затем я вызываю метод BeginListening в новом потоке, отделяя обработку от UI-потока. Этот метод показан на рис. 7.
Рис. 7. KinectAudioSource
private void BeginListening()
{
kinectSource = new KinectAudioSource());
kinectSource.SystemMode = SystemMode.OptibeamArrayOnly;
kinectSource.FeatureMode = true;
kinectSource.AutomaticGainControl = true;
kinectSource.MicArrayMode = MicArrayMode.MicArrayAdaptiveBeam;
var kinectStream = kinectSource.Start();
sre.SetInputToAudioStream(kinectStream,
new SpeechAudioFormatInfo(EncodingFormat.Pcm,
16000,
16,
1,
32000,
2,
null));
sre.RecognizeAsync(RecognizeMode.Multiple);
}
Можно задать несколько параметров в зависимости от создаваемого приложения. Детальное описание этих параметров см. в документации Kinect for Windows SDK Programming Guide (bit.ly/Avrfkd). Затем просто регистрирую свое WPF-приложение на событие SpeechTracker SpeechDetected, которое в основном похоже на событие SRE SpeechRecognized, но использует Intention как один из аргументов. Если SRE обнаруживает совпадение с любой из контекстных фраз, которые были в него загружены, он генерирует событие SpeechRecognized. Класс SpeechTracker обрабатывает это событие и проверяет, не указывает ли Intention на смену контекста. Если указывает, SpeechTracker обрабатывает выгрузку и загрузку соответствующих объектов Grammar и генерирует событие SpeechContextChanged. В ином случае генерируется событие SpeechDetected, и любое приложение, подписанное на это событие, может выполнять его обработку.
Лексические словари, прослушиваемые устройством Kinect, будут зависеть от контекста, создаваемого пользователем.
Свойство Confidence
Сначала одно замечание: в примере, который я нашел в сети, утверждалось, что свойство Confidence в SpeechRecognizedEventArgs ненадежно и использовать его не стоит (что противоречит документации в SDK). Я обнаружил, что, когда оно не используется, событие SpeechRecognized генерируется почти постоянно, даже если ничего не произносится. Поэтому в своем обработчике событий SpeechRecognized я первым делом проверяю Confidence. Если его значение менее 95%, я игнорирую результаты. (Число 95 взято в качестве порогового чисто эмпирическим путем: лишь начиная с этого значения я получал нужный мне уровень точности распознавания. По сути, в SDK рекомендуется выполнить тесты и оценивать это значение в зависимости от конкретного сценария.) Когда я сделал так, ложные срабатывания исчезли. Так что советую тщательно проверять любые утверждения и решения, которые можно найти в сети. Мой опыт совпал с информацией, изложенной в документации SDK, а также с примерами, которые Microsoft предоставляет на сайте для Kinect в Windows, — они оказались чрезвычайно ценными и точными.
Меня часто спрашивают: сколько времени требуется Kinect для обучения распознавания речи? Как показал мой опыт, это обучение вообще не требуется. Как только я задал нужное значение Confidence, Kinect великолепно работал безо всякого обучения, настройки и т. д. Я был главным субъектов тестов, но привлекал к этому делу и своих дочерей семи и восьми лет (спасибо вам, Кензи и Шахразад!), и они были в восторге от того, что могли говорить папиному компьютеру, что ему делать, а тот все понимал и действовал соответственно.
Создание иллюзии помощника-человека
Поддержка переключения контекстов, основанная на том, что система может наблюдать за средой, открывает богатые возможности во взаимодействии пользователя (человека) и Lily (машины). Чтобы создать настоящую иллюзию помощника, я добавил массу мелочей. Например, когда люди говорят между собой, им не обязательно снова и снова повторять одни и те же фразы. Поэтому, если вы обращаетесь к Lily, система выбирает в качестве ответа случайную фразу. Другими словами, когда пользователь спрашивает: «Lily?», Lily случайным образом отвечает: «Да», «Я здесь», «Что я могу сделать для вас?» и т. д.
Я решил сделать еще один шаг. Некоторые фразы предусматривают подстановку имени пользователя или обращения по половому признаку (сэр или мадам). Если случайно выбирается одна из этих фраз, тогда так же случайно используется имя или обращение. Это создает диалог, который никогда не бывает совершенно одинаковым. Мелкие детали, подобные этой, кажутся тривиальными и вряд ли стоящими усилий, но, видя реакцию пользователя при взаимодействии с такой системой, вы осознаете, что уникальность наших коммуникаций отчасти строится на этих мелких деталях. Я сам ловил себя на том, что думаю о Lily иначе, чем о других программах. В ходе тестирования и отладки мне нужно было искать некоторые спецификации или какой-то кусок кода. Когда я начинал поиск, я продолжал общаться с Lily и указывать «ей» завершить работу или что-то другое. Спустя некоторое время я понял, что начинаю скучать по уровню «человеческого взаимодействия», когда Lily не работает. Полагаю, это лучшее доказательство тому, что Kinect открывает совершенно новую эру в развитии естественных UI.
Создание контекстно-зависимых диалоговых систем наподобие Lily помогает пользователю абстрагироваться от компьютера — он становится для него помощником, а не набором выполняемых на нем приложений.
На рис. 8 показана последовательность объектов, необходимых для создания системы, которая слушает и действует по устным командам пользователя.
Рис. 8. Создание системы, которая слушает и действует по устным командам
Enums representing Contexts | Перечисления, представляющие контексты |
Intention | Intention |
Dictionary of Phrases | Словарь фраз |
Choices | Choices |
GrammarBuilders | Объекты GrammarBuilder |
Grammars | Объекты Grammar |
В следующей статье мы рассмотрим использование средств мониторинга глубины и скелетного отслеживания Kinect и их соединение со средствами распознавания речи для достижения мультимодальной коммуникации. Важность контекста станет еще очевиднее при добавлении этого компонента. Вы увидите, как связать движения тела с аудиокомандами и заставить систему анализировать весь спектр человеческой коммуникации.
Исходный код можно скачать по ссылке code.msdn.microsoft.com/mag201204Kinect.
Лиленд Холмквист (Leland Holmquest) — сотрудник Microsoft. Ранее работал в Naval Surface Warfare Center Dahlgren (Далгренская лаборатория научно-исследовательского центра вооружений надводных кораблей ВМС). Трудится над диссертацией в Университете Джорджа Мейсона (факультет информационных технологий).
Выражаю благодарность за рецензирование статьи эксперту Руссу Уильямсу (RussWilliams).**