Compartir a través de


Kinect

Diálogo que tenga en cuenta el contexto con Kinect

Leland Holmquest

Descargar el ejemplo de código

Les presento a Lily, mi asistente de oficina. A menudo conversamos y a mis órdenes Lily realiza tareas comerciales comunes, como buscar información y trabajar con documentos de Microsoft Office. Pero lo más importante es que Lily es un asistente de oficina virtual, una aplicación compatible con Kinect de Windows Presentation Foundation de Microsoft que pertenece a un proyecto para avanzar los medios del diálogo que tenga en cuenta el contexto y la comunicación multimodo.

Antes de entrar en el código fundamental de mi aplicación, la que desarrollé como parte de mi trabajo de posgrado en la Universidad George Mason, voy a explicar qué significa el diálogo que tenga en cuenta el contexto y la comunicación multimodo.

Diálogo que tenga en cuenta el contexto y la comunicación multimodo.

Como seres humanos, poseemos medios de comunicación ricos y complejos. Considere la siguiente situación: un bebé comienza a llorar. Cuando el infante nota que su madre lo está mirando, apunta a la galleta que está en el suelo. La madre sonríe de esa manera comprensiva que posee, se agacha, recoge la galleta y se la devuelve al bebé. Encantado porque recuperó su tesoro, el bebé chilla y palmotea rápidamente antes de tomar con muchas ganas la galleta.

Esta escena describe una simple secuencia de eventos. Pero echemos un vistazo más detenido. Examinemos los modos de comunicación que ocurrieron. Consideremos implementar un sistema de software en que el bebé o la madre desaparece y la comunicación se facilita por el sistema. Rápidamente nos damos cuenta de lo verdaderamente complejos y complicados que son los métodos de comunicación empleados por lo dos actores. Hay procesamiento de audio para comprender el llanto, el chillido o la alegría del bebé y el sonido de sus palmoteos. Existe un análisis visual necesario para comprender los gestos representados por el bebé apuntando a la galleta, como también para deducir el sutil reproche que la madre hace cuando sonríe comprensivamente. Como suele suceder en casos que involucran situaciones tan omnipresentes como esta, damos por sentado el nivel de sofisticación empleado hasta que tenemos que implementar el mismo nivel de experiencia a través de una máquina.

Agreguemos un poco más de complejidad a los métodos de comunicación. Considere la siguiente situación. Entra a una habitación donde varias personas están en la mitad de una conversación. Escucha una sola palabra: "genial". Las personas en la habitación lo miran buscando que realice un aporte. ¿Qué puede ofrecer? Genial pueden significar muchas cosas. Por ejemplo, esa persona puede haber estado hablando sobre una persona en especial. Quien hablaba tal vez estaba mostrando su aprobación por algo ("ese automóvil es genial"). La persona podría haber estado analizando la relación entre países ("la negociación es genial"). Sin contar con la ventaja del contexto que rodea una palabra individual, es muy difícil comprender el significado de la palabra en el momento en que se pronuncia. Debe existir cierto nivel de comprensión semántica con el fin de comprender el significado que se le quiere dar. Este concepto es el núcleo de este artículo.

El proyecto Lily

Creé el Proyecto Lily como proyecto final para CS895: software para sistemas multiusuarios que tengan en cuenta el contexto en la Universidad George Mason, curso a cargo del Dr. João Pedro Sousa. Como ya mencioné, Lily es un asistente virtual colocado en un escenario típico de oficina comercial. Usé el dispositivo Kinect y la versión beta 2 del SDK de Kinect para Windows. Kinect proporciona una cámara a color, una cámara que capta la profundidad, una matriz de cuatro micrófonos y un práctico API que se puede usar para crear IU naturales. Además, el sitio de Microsoft Kinect para Windows (microsoft.com/en-us/kinectforwindows) and Channel 9 (bit.ly/zD15UR) proporciona una gran cantidad de útiles ejemplos relacionados. Kinect le proporcionó a los desarrolladores increíbles capacidades en un paquete (relativamente) económico. Esto quedó demostrado cuando Kinect rompió el Record Guinness como el “dispositivo de consumo de venta más rápida” (on.mash.to/hVbZOA). Las especificaciones técnicas de Kinect (que aparecen en bit.ly/zZ1PN7) incluyen:

  • Cámara de movimiento VGA color: resolución de 640x480 píxeles a 30 cuadros por segundo (fps)
  • Cámara de profundidad: resolución de 640x480 píxeles a 30 fps
  • Matriz de cuatro micrófonos
  • Campo de vista
    • Campo de vista horizontal: 57 grados
    • Campo de vista vertical: 43 grados
    • Intervalo de inclinación física: ± 27 grados
    • Intervalo del sensor de profundidad: 1,2 m - 3,5 m
  • Sistema de seguimiento de esquelético
    • Capacidad de seguir hasta seis personas, incluidos dos jugadores activos
    • Capacidad de seguir 20 articulaciones por jugador
  • Un sistema de cancelación de eco que mejora la entrada de la voz
  • Reconocimiento de voz

La arquitectura de Kinect

Microsoft también proporciona una interpretación de la arquitectura en la que se basa Kinect, como se muestra en la figura 1.

Kinect for Windows ArchitectureFigura 1 Arquitectura de Kinect para Windows

Los números encerrados en un círculo de la figura 1 corresponden a lo siguiente:

  1. Hardware de Kinect: los componentes de hardware, incluido el sensor Kinect y el hub USB, a través del cual se conecta el sensor al equipo.
  2. Controladores de Kinect de Microsoft: los controladores de Windows 7 para el sensor Kinect se instalan como parte del proceso de configuración de la versión beta de SDK, como se describe en este documento. Los controladores de Kinect de Microsoft son compatibles con:
    • la matriz de micrófonos del sensor Kinect como un dispositivo de audio en modo kernel al cual se puede acceder a través de las API estándar de audio en Windows.
    • Imagen de transmisión y datos de profundidad.
    • Funciones de enumeración de dispositivos que le permite a una aplicación usar más de un sensor Kinect conectados al equipo.
  3. NUI API: conjunto de API que recopila datos de los sensores de imágenes y controla los dispositivos de Kinect.
  4. KinectAudio DMO: El DMO de Kinect que extiende la compatibilidad de la matriz de micrófonos en Windows 7 para exponer la conformación de haces y la funcionalidad de localización de la fuente.
  5. API estándar de Windows 7: las API de audio, voz y medios en Windows 7, como se describen en el SDK de Windows y el SDK de Microsoft Speech (Guía de programación de la versión beta del SDK de Kinect para Windows).

En este artículo, demostraré cómo usar la matriz de micrófonos y el motor de reconocimiento de voz (SRE) para crear vocabularios que son específicos para el contexto. En otras palabras, los vocabularios a los que estará atento Kinect dependerán del contexto que crea el usuario. Mostraré un marco en el cual la aplicación vigilará lo que hace el usuario, alternando la gramática en el SRE (según el contexto), lo que le proporciona al usuario un medio natural e intuitivo de interacción con Lily, sin tener que memorizar comandos específicos y patrones de uso.

La clase SpeechTracker

Para el Proyecto Lily, usé una clase separada llamada SpeechTracker para administrar todo el procesamiento de voz. SpeechTracker se diseñó para ejecutarse en un subproceso independiente de la interfaz del usuario, lo que le daba mejor respuesta, aspecto fundamental de esta aplicación. ¿De qué sirve un asistente que nunca escucha?

Antes de entrar de lleno a SpeechTracker, es necesario reflexionar sobre algunas cosas. Lo primero es determinar los contextos en los que la aplicación debe escuchar. Por ejemplo, Lily tiene un contexto de "Investigación" que administra acciones relacionadas con la búsqueda de datos e información; un contexto "Office" que administra acciones como abrir documentos de Word y presentaciones de PowerPoint, como también otras tareas relacionadas con un escenario de oficina; un contexto "Operaciones" que le permite al usuario ajustar el dispositivo Kinect y; un contexto "General que administra todas esas pequeñas cosas que pueden surgir independientes de cualquier contexto real (por ejemplo, "¿Qué hora es?" "Apagar" o comentarios para el sistema). Existen algunos otros contextos que creé en mi ejemplo, pero ningún otro es importante en este contexto de "Contexto". Este contexto se usa para comunicar en qué marco de referencia debe estar Lily. En otras palabras, la enumeración de Contexto se usa para determinar el contexto al que el sistema debe estar escuchando. Más adelante hablaremos sobre esto.

Luego, cada contexto se modela a través del uso de enumeraciones, como se muestra en la figura 2.

Example of ContextFigura 2 Ejemplo de contexto

Con los contextos modelados, lo siguiente es un medio para transmitir la intención del usuario dentro de un contexto específico. Para poder lograr esto, usé una estructura que apenas contiene un contenedor para cada contexto y un 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;
}

El bool es importante. Si la intención es simplemente ejecutar un cambio de contexto, entonces el contextOnly es verdadero, de otra forma es falso. La utilidad de esto será más evidente más adelante, pero por ahora hay que comprender que es una marca necesaria.

¿Cuál es la intención del usuario?

Ahora que el Proyecto Lily tiene la capacidad de comunicar una intención, necesita saber cuándo y qué intención usar para en el tiempo de ejecución. Para poder hacer eso, creé un diccionario System.Collections.Generic.Dictionary<TKey, TValue> en el cual la clave corresponde a un palabra o frase dicha y el valor es la intención asociada. Desde la aparición de Microsoft .NET Framework 3.0, contamos con una forma breve de crear objetos e inicializar propiedades, como se muestra en la figura 3.

The ContextPhrases Dictionary
Figura 3 El diccionario ContextPhrases

Este diccionario en especial define las frases de contexto. Las claves corresponden a palabras y frases que el usuario final dice, las que luego se asocian con una intención. Cada intención se declara y sus propiedades se ubican en una sola línea. Vea que una sola intención (por ejemplo, Investigación) se puede asignar a varias palabras y frases individuales. Esto proporciona la capacidad de crear vocabularios ricos que pueden modelar el idioma específico del dominio y el léxico del sujeto en cuestión. (Tenga presente una cosa importante de ContextPhrases: la propiedad contextOnly está configurada como verdadero. Esto le dice al sistema que la acción se usa solo para cambiar qué contexto está activo. Esto le permite al sistema acortar el ciclo de la lógica detrás de la administración de eventos de voz).

Para obtener un mejor ejemplo de esto, observe el fragmento del diccionario GeneralPhrases que aparece en la figura 4.

The GeneralPhrases Dictionary
Figura 4 El diccionario GeneralPhrases

Observe que en muchos casos la misma intención se modela con diferentes frases, lo que le brinda al sistema la capacidad de administrar el diálogo con el usuario de forma rica y humana. Una limitación que hay que tener presente es que cualquier diccionario que use el SRE puede contener un máximo de 300 entradas. Por lo tanto, resulta provechoso modelar el vocabulario y la gramática de manera prudente. Incluso si esta no fuera una limitación impuesta, se debe considerar como una mejor práctica para mantener los diccionarios lo más ligeros posibles, con el fin de obtener un mejor rendimiento.

Ahora que los vocabularios están asignados a las intenciones, puedo hablar de la parte realmente entretenida. En primer lugar, el sistema necesita acostumbrarse al SpeechRecognitionEngine:

ri = SpeechRecognitionEngine.InstalledRecognizers()
    .Where(r => r.Id ==  RecognizerId).FirstOrDefault();
if (ri == null)
{
  // No RecognizerInfo => bail
  return;
}
sre = new SpeechRecognitionEngine(ri.Id);

Ahora, tomaré las frases que desarrollé anteriormente y las convertiré en opciones:

// Build our categories of Choices
var contextPhrases = new Choices();
foreach (var phrase in ContextPhrases)
  contextPhrases.Add(phrase.Key);

Haré esta misma operación para todas las frases que creé anteriormente. Las opciones luego pasan por el método de Anexar en un GrammarBuilder. Lo último consiste en crear los objetos de gramática y cargarlos en el SRE. Para lograr esto, simplemente creé una nueva gramática y pasé en el GrammarBuilder la representación de la gramática deseada, como se muestra en la figura 5.

Figura 5 Crear gramáticas y cargar el motor de reconocimiento de voz

// And finally create our Grammars
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);
// We're only going to load the Context and General grammars at this point
sre.LoadGrammar(gContext);
sre.LoadGrammar(gGeneral);
allDicts = new List<Dictionary<string, 
    Intention>>() { ContextPhrases,
                    GeneralPhrases,
                    ResearchPhrases,
                    OfficePhrases,
                    OperationsPhrases,
                    MeetingPhrases,
                    TranslationPhrases,
                    EntertainPhrases };

Observe que solo hay dos gramáticas, gContext y gGeneral, cargadas en el SRE, pero se agregaron todas las gramáticas a una lista de frases. Así es como afecto la porción de tiene en cuenta el contexto de escuchar. Las frases generales y de contexto necesitan estar presentes de manera continua en el SRE, ya que se pueden decir en cualquier momento, sin que existe un patrón predeterminado. Sin embargo, se carga una gramática adicional más cuando se identifica una frase de contexto. Para completar esta parte de la aplicación, simplemente administro el evento SpeechRecognized en el SRE. Se usa el argumento SpeechRecognizedEventArgs para evaluar qué se dijo. Nuevamente con relación a la figura4, si el argumento tiene una intención que está marcada como contextOnly, entonces el sistema necesita descargar la tercera gramática (si es que existe) del SRE y cargar la nueva gramática identificada. Esto le permite a la aplicación escuchar diferentes vocabularios y léxicos que según el contexto que se da actualmente.

El diccionario (consulte la figura 4) tiene un tipo de cadena de clave que representa la frase dicha y un tipo de valor de intención que indica qué acción debe tomar el sistema, con el fin de satisfacer las necesidades del usuario. Dentro de la adición de cada entrada en el diccionario, existe el constructor de la intención, que por lo general posee tres componentes: la asociación de contexto; si este es un evento que cambia el contexto y; (en caso de que no cambie el contexto), qué acción se intenta realizar.

Cuando todos los diccionarios de frases compatibles están definidas, agrego esta información al SRE proporcionado por la unidad Kinect, como se muestra en la figura 6.

Speech Recognition Engine
Figura 6 Motor de reconocimiento de voz

Esto le dice de forma eficaz al SRE qué debe escuchar y cómo etiquetar la información cuando la escucha. Sin embargo, en un intento por hacer que el sistema sea más inteligente y fácil de usar, limité el sistema para que solo tenga tres contextos y sus respectivos diccionarios de frases cargados en el SRE en un momento dado. Las frases de contexto y generales siempre están cargadas debido a su naturaleza fundamental. El tercer contexto y frases cargadas se determina de acuerdo con la interacción con el usuario final. A medida que Lily escucha el entorno, reacciona a palabras y frases clave y elimina un grupo de frases para reemplazarlo con otro en el SRE. Un ejemplo ayudará a clarificar esto.

Funcionamiento

Cuando se inicia Lily por primera vez, ContextPhrases y GeneralPhrases se cargan en el SRE. Esto le permite al sistema escuchar comandos que originarán que cambie el contexto del sistema o que se faciliten las acciones generales. Por ejemplo, después de completar la inicialización, si el usuario pregunta "¿Qué hora es?", Lily lo "comprende" (es parte de las GeneralPhrases) y responde la hora. De la misma forma, si el usuario dice "Necesito cierta información", Lily comprende que esta es una marca para cargar las ResearchPhrases en el SRE y comienza a escuchar en busca de las intenciones asignadas al contexto de Investigación. Esto le permite a Lily alcanzar tres importantes objetivos:

  1. El rendimiento de Lily se maximiza al escuchar solo un conjunto mínimo de frases que pueden ser pertinentes.
  2. Permite el uso de lenguaje que podría ser ambiguo debido a los diferentes significados dentro de distintos contextos (recuerde el ejemplo de "genial") al permitir solo el léxico del contexto específico.
  3. Le permite al sistema escuchar varias frases diferentes, pero asignar distintas frases a las mismas acciones (por ejemplo, "Lily, ¿qué hora es?" "¿Qué hora es?" y "¿Sabes qué hora es?" se pueden asignar a la misma acción de decirle al usuario la hora). Esto tiene el potencial de permitir un léxico abundante para el diálogo específico de contexto con el sistema. En vez de forzar al usuario a memorizar palabras clave o frases individuales, al asignar acciones a un comando, el diseñador puede modelar diferentes formas comunes para indicar lo mismo. Esto le entrega al usuario la flexibilidad para poder decir de forma normal y relajada. Una de las metas de la informática omnipresente es hacer que los dispositivos se mezclen con el entorno. La creación de sistemas de diálogo que tenga en cuenta el contexto, como Lily, contribuye a eliminar la conciencia que tiene el usuario con relación a la existencia del equipo, con lo que se convierte en un asistente, no en una aplicación.

Equipada con todo el conocimiento requerido, Lily puede escuchar y responder con acciones apropiadas al contexto. Lo único que queda por hacer es crear una instancia para KinectAudioSource y especificar sus parámetros. En el caso del Proyecto Lily, puse todo el procesamiento de audio dentro de la clase SpeechTracker. Luego usé el método BeginListening en un nuevo subproceso, con lo que lo separé del subproceso de IU. La figura 7 muestra ese método.

Figura 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);
}

Se pueden configurar varios parámetros, según la aplicación que se crea. Para obtener más información sobre estas opciones, consulte la documentación en la Guía de programación del SDK de Kinect para Windows (bit.ly/Avrfkd). A continuación, simplemente registré mi aplicación WPF con el evento SpeechTracker SpeechDetected, el cual consiste básicamente en una vía para el evento SpeechRecognized del SRE, pero con el uso de la intención como parte de los argumentos del evento. Si el SRE encuentra una coincidencia para cualquiera de las frases de contexto que posee cargadas, destaca el evento SpeechRecognized. El SpeechTracker administra dicho evento y evalúa si la intención indica un cambio de contexto. De ser así, el SpeechTracker administra la descarga y la carga de las gramáticas de manera apropiada y destaca el evento SpeechContextChanged. De lo contrario, destaca el evento SpeechDetected y permite que lo que esté vigilando dicho evento se haga cargo de el.

La propiedad de confianza

Una cosa a tener en cuenta: Un ejemplo que encontré en línea decía que la propiedad de confianza en SpeechRecognizedEventArgs no es confiable y que no hay que usarlo (contrario a la documentación del SDK). Descubrí que al usarlo, el evento SpeechRecognized se activaba de manera continua, incluso cuando no se estaba hablando nada. Por lo tanto, en mi administrador del evento SpeechRecognized, lo primero que hago es revisar la confianza. Si no posee por lo menos un 95% de confianza, hago caso omiso de los resultados. (El número 95 se determinó simplemente a través del ensayo y error, no puedo aceptar el crédito de analizar un valor válido. El 95% simplemente me dio el nivel de resultados que estaba buscando. De hecho, el SDK aconseja probar y evaluar este valor caso a caso). Cuando lo hice, los falsos positivos descendieron hasta llegar a 0. Por lo que aconsejo probar cuidadosamente todas las instrucciones y soluciones que encuentre en línea. Mi experiencia fue que la documentación del SDK, junto con las muestras que entrega Microsoft en el sitio de Kinect para Windows, resultaron ser muy valiosas y muy precisas.

Siempre me preguntan: ¿cuánto entrenamiento de reconocimiento de voz necesita Kinect? Según mi experiencia, nada. Una vez que configuré el calor de confianza, Kinect funcionó perfectamente sin la necesidad de ningún tipo de entrenamiento, ajuste ni nada parecido. Yo mismo fui el sujeto de prueba principal, pero también incluí a mis hijas de 7 y 8 años (¡gracias Kenzy y Shahrazad!) y les encantó descubrir que le podían decir a la computadora de papá lo que tenía que hacer y esta comprendía y actuaba. ¡Se sentían con mucho poder y para mi fue muy satisfactorio!

Crear la ilusión de un asistente humano

La capacidad de cambiar de contexto basado en lo que el sistema observa del entorno crea una muy rica interacción entre el usuario (humano) y Lily (máquina). Para mejorar realmente la ilusión de contar con un asistente, agregué muchas pequeñas características. Por ejemplo, cuando un humano comienza a hablar con otro, por lo general no repetimos las mismas frases una y otra vez. Por lo tanto, cuando se administra la intención de "pulso", el sistema escoge una frase al azar y se la dice al usuario. En otras palabras, cuando el usuario pregunta "¿Lily?", Lily responde de manera aleatoria, "Sí", "Estoy aquí", "¿Qué puedo hacer por ti?" u otras frases.

Llevé esto un poco más allá. Algunas de las frases incluyen un contenedor para el nombre del usuario o para el pronombre específico de acuerdo con el género (señor o señora). Si se selecciona una de estas frases al azar, se determina aleatoriamente si se usa el nombre o el pronombre. Esto crea un diálogo que nunca es exactamente igual. Los pequeños detalles, como el anterior, pueden parecer triviales y que no valen la pena el esfuerzo, pero cuando se observa la respuesta que el humano experimenta al interactuar con el sistema, se hace evidente que parte de la singularidad de nuestras comunicaciones se origina en este tipo de detalles. Creo que Lily es diferente del resto de los programas. Durante el proceso de prueba y depuración, a veces necesitaba buscar cierta especificación o cierta porción de código. A medida que buscaba, continué hablando con Lily y dándole instrucciones para que se apagara, etc. Después de un rato, me di cuenta que extrañaba el nivel de "interacción humana" mientras Lily estaba apagada. Creo que esa experiencia es el mejor testimonio que puedo entregar con relación a que Kinect representa una nueva era de IU natural.

Para repasar, la figura 8 muestra la progresión de los objetos necesarios para crear un sistema que escucha y actúan de acuerdo con los comandos verbales del usuario.

Creating a System that Listens and Acts on Verbal Commands
Figura 8 Creación de un sistema que escucha y actúa de acuerdo con comandos verbales

En el siguiente artículo, analizaré cómo aprovechar las capacidades de seguimiento de profundidad y de esqueleto de Kinect y cómo se asocia con las capacidades de reconocimiento de voz para lograr la comunicación multimodo. La importancia del contexto será aun más evidente dentro del componente de comunicación multimodo. Verá cómo asociar los movimientos del cuerpo con los comandos de audio y cómo hacer que el sistema evalúe el espectro completo de la comunicación humana.

Leland Holmquest es empleado de Microsoft. Anteriormente trabajó para Naval Surface Warfare Center Dahlgren. Actualmente está trabajando en su doctorado sobre Tecnología de la información en la Universidad George Mason.

Gracias al siguiente experto técnico por su ayuda en la revisión de este artículo: Russ Williams