Chatbot que aprende a hablar


En la sesión pasada vimos cómo construir un chatbot guiado por el estado de la información, por mucho tiempo fue una estrategia muy sólida para construir chatbots. En esta sesión nos vamos a enfocar cómo podemos usar aprendizaje automático para generar un chatbot. Aprendizaje automático es un área gigantesca de la computación que nos ocuparía mucho tiempo revisar, pero los conceptos importantes para esta sesión son:

  • Aprendizaje automático crea un modelo computacional de predicción en el sentido que tendremos una entrada $X$ y produciremos una salida $y$. Por ejemplo, podemos pensar que $X$ de alguna forma codifica el clima de $n$ días anteriores a hoy y $y$ es la predicción de cómo será el clima hoy; o $X$ es una imagen y $y$ es una posición en la imagen dónde hay un rostro; o $X$ es una pregunta del usuario y $y$ será la respuesta a ese usuario.
  • Un modelo de aprendizaje automático consiste de parámetros, a veces decenas, otras veces miles, y en modelos sofisticados cientos de miles o millones.
    Estos parámetros son como válvulas de una tubería que es el modelo y tenemos que fijarlas de alguna forma para que el modelo haga buenas predicciones. Al inicio de la tubería ponemos nuestro valores de entrada $X$, estos valores navegarán la tubería dependiendo de los parámetros y producirán una salida al final.
  • El proceso de identificar los valores de los parámetros se denomina entrenamiento (training). Existen diversas metodologías para identificar una buena configuración de los parámetros, por ejemplo basados en estadística o analíticos. En los últimos años ha habido un gran avance con métodos aproximativos iterativos, es decir, que hacen un juego de viene-viene proponen una configuración, se evalúa el desempeño de esa configuración, se propone una nueva configuración basada en una corrección dado el desempeño, y se repite el ciclo hasta que estamos satisfechos con la predicción, algo parecido cuando el viene-viene nos ayuda a estacionar nuestro coche.
  • Para el entrenamiento se necesitan datos de entrenamiento. Estos son ejemplos de como lucen las predicciones $y$ dado $X$. Por ejemplo, de años anteriores extraemos secuencias de $n$ días de climas y cómo fue el clima en el $n$ día; o usamos colecciones de imágenes y las posiciones de los rostros en esas imágenes; o conversaciones pasadas de dónde podamos hacer pares de pregunta usuario y respuesta que debe dar un chatbot. Estos ejemplos se usan para guiar el entrenamiento e identificar los parámetros de nuestro modelo.
  • Además de los datos de entrenamiento, muchas veces tenemos datos de prueba (testing) y datos de desarrollo (developing). Estos son otros conjuntos de ejemplos pero que nunca presentamos a nuestro modelo durante el entrenamiento, estos nos sirven para cuantificar que tanto está aprendiendo nuestro sistema dados los aciertos que tiene el modelo al ver estos ejemplos nuevos. Los datos de desarrollo nos ayuda a cuantificar el desarrollo del modelo en los diferentes ciclos de entrenamiento. Los datos de prueba los usamos para cuantificar el desempeño de un modelo que identificamos como bueno. Esto nos permite de una forma subjetiva decir que tan bueno es nuestro sistema, además que nos permitirá compararnos con otros.

Para una revisión más extensa de los elementos del aprendizaje automático pueden leer esta introducción al . Aquí hay unos ejemplos de cómo predecir tuits irónicos, géneros musicales o rostros

Todo es un vector

Para que los modelos de aprendizaje automático puedan funcionar es necesario convertir la entrada a un vector. Por ejemplo, en nuestro chatbot tenemos que encontrar un método para transformar una oración en un vector. Afortunadamente hay varias opciones:

  • Bolsa de palabras este método consiste en registrar el número que aparece una palabra en una oración en un vector donde cada dimensión corresponde a una palabra diferente. Las tres primeras secciones de este post presentan esta idea más a fondo.
  • One hot vector bolsa de palabras es muy efectiva representando a un texto de forma general. Pero como aglutinamos todas las palabras en un sólo vector perdemos información del orden en que ocurrieron estas palabras. Por lo que una alternativa es representar a la oración como una secuencia de vectores, que rápidamente evoluciona a representar la oración en una matriz. Cada renglón representa una palabra diferente, y cada columna una posición de nuestra oración. La idea es prender con un 1 la palabra que ocurre en cada posición. Un problema que surge es que diferentes oraciones con longitudes diferentes generan matrices con dimensiones diferentes, y generalmente esto es una mala idea para nuestros modelos. La forma de solucionarlo es definir una longitud máxima, lo que sea más grande se pierde; lo que sea más pequeño se llena de zeros (padding). Otro problema es que estos vectores son dispersos, están saturados de zeros.
  • Embeddings Para solucionar el problema de vectores dispersos de one hot una opción es representar a las palabras como vectores densos, es decir que tienen pocos zeros. Para esto definimos una dimensionalidad de nuestras palabras por ejemplo: $100$ y cada palabra esta representado por un vector diferente con $100$ valores diferentes. En una situación ideal, la palabra hombre y mujer están distantes entre si, pero mujer y emprendedora están cerca de la misma forma que hombre y emprendedor están. De alguna forma los vectores por palabra representan el concepto de esa palabra. A estos vectores se les demomina embeddings y tienen que salir de algún lado. Para nuestra fortuna los podemos considerar como parámetros de nuestro modelo y dejar que el entrenamiento identifique los valores más adecuados para representar esas palabras.

Modelos para chatbot

De una conversación hay varios aspectos que podemos modelar a través de aprendizaje automático:

  • Argumentos de las frases Algo que podemos predecir es la categoría de las palabras en una oración (información léxica). Por ejemplo, para la frase quiero un kilo de naranjas podemos asociar quiero con el argumento _commandbuy, un con _quantity1 y naranjas con _typeorange. De tal forma que podemos deducir que el comando es: buy(orange,1). Para lograr esto necesitamos un sistema predictivo que vea una palabra y determine el tipo. Por ejemplo, que vea quiero como $X$ y produzca como $y$ _commandbuy. Y así para los otros casos, de tal forma que se convierte en una colección de ejemplos para entrenar y luego presentarle la oración quiero un kilo de manzanas y podamos recuperar buy(apple,1). Es recomendable que $X$ no sólo esté conformada por la palabra que queremos predecir, sino que incluya más información como todas las palabras alrededor o toda la oración.
    Para poder construir estos ejemplos necesitaríamos manualmente revisar conversaciones y etiquetar la categoría de cada argumento, por ejemplo:
quiero -> command_buy
un -> quantity_1
kilo -> none
de -> none
naranjas -> type_orange
  • intensión de la frase una opción es mapear la frase a una intención. Por ejemplo, la frase hola tiene la intensión de saludar y quiero un kilo de naranja tiene la intensión de pedir algo. Si para cada frase que nos diga el usuario podemos predecir su intención entonces podríamos responder correspondiendo a dicha intención, por ejemplo para saludar podríamos regresar el saludo, o para una petición podríamos analizar a mayor profundidad la oración e identificar los argumentos, y de esa forma satisfacer la petición. Para este caso, necesitamos ejemplos de frases con sus intenciones correspondientes.

  • Generar la respuesta automáticamente este es el modelo por excelencia, lo que buscamos hacer es un modelo predictivo que para una frase del usuario genere una frase de respuesta. Parece sacado de ficción, pero afortunadamente no es tan lejano y tenemos la tecnología para hacerlo. Sin embargo, no predecimos toda la frase, sino la palabra siguiente, con esa palabra generamos la siguiente, así hasta generar una oración. Para este modelo necesitamos pares de pregunta respuesta, y lo que queremos generar es ejemplos de gene palabra por palabra de la respuesta de la siguiente forma:

¿quiero un kilo de naranjas? -> muy
¿quiero un kilo de naranjas? muy -> bien
¿quiero un kilo de naranjas? muy bien -> hemos
¿quiero un kilo de naranjas? muy bien hemos -> agregado
¿quiero un kilo de naranjas? muy bien hemos agregado -> un
¿quiero un kilo de naranjas? muy bien hemos agregado un -> kilo
¿quiero un kilo de naranjas? muy bien hemos agregado un kilo -> de
¿quiero un kilo de naranjas? muy bien hemos agregado un kilo de -> naranjas

Deep learning y RNN

Deep learning es la metodología que nos va a permitir generar el modelo predictivo para generar respuestas automáticamente. Deep learning es una evolución de redes neuronales y que en los últimos años ha mejorado y permite la construcción de arquitecturas muy complejas. Parte de las mejoras es la propuesta de redes recurrentes (RNNs). Estas son arquitecturas que funcionan muy bien generando secuencias. Ya que una frase es una secuencia de palabras se han demostrados ser muy buenas para el procesamiento de textos. En redes profundas los parámetros del modelo se le conocen como pesos.

Una forma común de pensar en las redes recurrentes es la de codificacor/decodificador, en esta configuración una RNN lee una oración u crea un resumen de esta que representa como un vector. Mientras eso hace una RRN, otra RNN aprende a decodificar o a escribir una oración, toma el resumen de la primera y la decodifica. Esta configuración se usa para traducción automática, una RNN lee una oración en inglés, crea un resumen, este lo toma otra RNN y comienza a escribir en español decodificando el resumen.

En chatbots podemos usar una configuración similar. Una RNN toma una lo dicho por el usuario, lo codifica y otra RNN toma eso y lo decodifica produciendo la respuesta. Desafortunadamente en esta estrategía no tenemos control en lo que va a producir el chatbot y generalmente produce basura.