Introducción a fasttext: entrenando el modelo con lenguaje coloquial chapín
Facebook liberó un software para word embeddings hace tiempo llamado fasttext que posiciona las palabras de un documento en un espacio vectorial basado en los n-gramas de las letras que las conforman y en skipgrams de palabras para detectar el contexto en que se usan. Con esto se logra pasar las palabras de una representación dispersa (sparse) a una representación densa de menos dimensiones. En este post quiero introducir superficialmente este paquete de software y su uso sobre datos de un foro de internet con lenguaje coloquial guatemalteco.
Para retroceder un poco, por si no se entiende bien lo que significa, un espacio vectorial es sencillamente un espacio generado por vectores. Tomar por ejemplo dos vectores; digamos el dedo pulgar y el dedo índice de la mano izquierda, estirarlos e imaginar que son flechas cuyas puntas van hacia afuera de la mano. Con estos dos vectores/dedos generamos un plano de dos dimensiones (porque se genera con 2 vectores). Podemos referirnos a cada punto en este plano multiplicando números por los dos vectores generadores y sumando, por ejemplo, pulgar*0 + índice*0 nos daría el punto de origen que estaría entre los dos dedos, pulgar*1 + índice*0 nos daría el punto en la punta del dedo pulgar, y así, se podría multiplicar cualquier número real por los vectores para referirnos a cualquier punto en el plano generado por los dos dedos/vectores. Si ponemos los dedos en un ángulo recto, hasta podríamos decir que hemos generado el plano cartesiano.

Tras este ejercicio espero que se comprenda aunque sea descuidadamente lo que es un espacio vectorial. En el análisis computacional de lenguaje las palabras suelen tomarse como vectores de un inmenso espacio vectorial utilizando cada palabra como un vector. Así, por ejemplo, si tenemos un vocabulario de 3,000 palabras tendríamos un espacio de 3,000 dimensiones. Un método común para análisis de lenguaje utilizado desde hace décadas consiste en tomar documentos y contar las veces que aparece cada palabra para formar un vector que represente a cada documento. A este método se le llama “bag of words”, o bolsa de palabras, ya que las palabras son agrupadas en un objeto sin tomar en cuenta su posición ni su función en el documento. Con este método se lograron algunas cosas interesantes, como el LDA (latent dirichlet analysis), que permite sugerir temas latentes, a partir del análisis de múltiples documentos. Dichos temas latentes serán vectores en ese espacio “esparcido” (holgado o espacioso) de palabras y representarían los temas que se abordan en el “corpus” de documentos. Corpus es la colección de documentos que se utilizan para generar el modelo.

Los word embeddings comenzaron mucho antes de que a google se le ocurriera su algoritmo word2vec, que es ligeramente inferior a fasttext. La base estadística y matemática va más allá de mi comprensión de momento. Gracias a que todo esto del machine learning es como una carrera tecnológica en la que varios compiten, facebook liberó su código fasttext luego de que google liberara sus modelos de word embeddings.
Fasttext utiliza un método llamado skipgram para modelar el contexto de cada palabra. Con esto, se logra capturar más información sobre la función de las palabras dentro de sus entornos. El objetivo de este tipo de análisis es reducir las dimensiones, desde miles o incluso millones de dimensiones (una por palabra), a entre 100 y 300 dimensiones. Esto es, desde un espacio holgado o esparcido (creo que no existe esa palabra) hacia un espacio compacto y denso utilizando la estructura de los caracteres que conforman las palabras y el contexto dado por los skipgrams. Fasttext puede manejar palabras nuevas, que no estaban en los datos de entrenamiento, ya que está basado en los caracteres, y no en las palabras completas. Esto lo logra utilizando n-gramas que son sub-secuencias de letras dentro de las palabras. Por ejemplo “gatos”, tiene los n-gramas: “ga”, “gat”, “gato”, “at”, “ato”, “atos”, “tos”, “os”. Esto irá agrupando a nombres comunes masculinos en plural que terminen en “os”, como “perros”, “vasos”, etc. Por lo tanto fasttext bastante sensible a la similitud de las palabras y también a la manera en que se usan en sus contextos.
Todo esto podría hacerse con una red neuronal tipo auto-encoder, pero la maravilla de este modelo es su inmensa simpleza. Está todo explicado en el paper original.
Para mi fasttext es el mejor algoritmo de código libre para este tipo de análisis. Lo próximo será liberarse de las palabras; hace poco vi un paper sobre análisis de representaciones densas de texto sin necesidad de símbolos (es decir, sin necesidad de palabras) en ( Schutze et. al 2017 ). Una cosa poéticamente iconoclasta, debo admitir. Ir más allá de los símbolos y buscar patrones al nivel de las letras y sus contextos me parece un rollo más holístico. Lamentablemente esos investigadores no han publicado su código, y tomaría bastante esfuerzo implementar su algoritmo sin ninguna base.
Mientras tanto me enfoco en fasttext. Lo he querido probar desde que vi la noticia de su liberación bajo licencia libre, pero hasta ahora he tenido la oportunidad. El primer paso es obtener datos para entrenar el modelo. En Guatemala hay un foro en línea bastante activo llamado Velocidad máximaque es principalmente sobre carros. Sin embargo, en este foro hablan de todo lo que se puedan imaginar, desde problemas personales, hasta noticias de política o deportes. Todo esto utilizando un lenguaje muy coloquial y bastante vulgar. Hice un scraper con scrapy para descargar los mensajes del foro. Esto tomo varios días, inesperadamente. Al final bajé más de 10 millones de mensajes de 442K threads y 32K usuarios en un csv de 1.1GB.
Pandas cargó el archivo sin problemas. Luego de procesar el texto para quitar caracteres indeseados, el paso siguiente es sencillamente entrenar el modelo con fasttext. Este software sólo requiere un documento de texto plano, con las palabras separadas por espacios, preferiblemente sin signos de puntuación. He dejado los parámetros de entrenamiento por defecto, pero es posible que se pueda optimizar para el español coloquial guatemalteco.
Pensé que tal magnitud de datos tomarían mucho tiempo para entrenar, pero resultó terminar en un par de horas con 8 cores y 32GB de RAM (el proceso en sí utilizó sólo unos 3GB). Un corpus con 177K palabras distintas (muchas de ellas variaciones de lo mismo pero con mala ortografía). Lo bueno de la redundancia es que el modelo va a ser capaz de reforzar su aprendizaje, así que en este caso, no hay problema con la mala ortografía. Incluso podría hacerse un corrector de ortografía basado en esto.
Seguramente no puedo compartirles los datos de velmax ya que tienen copyright, pero comparto el modelo entrenado para que experimenten con él, si quieren:
https://nyc3.digitaloceanspaces.com/bodegona/models/velmax.model.200dim.vec https://nyc3.digitaloceanspaces.com/bodegona/models/velmax.model.200dim.bin
Para probarlo he usado la función de “nearest neighbor”, que nos permite obtener los vecinos de una palabra dentro del embedding (i.e., el espacio vectorial de palabras modelado). Uno de mis objetivos con todo esto ha sido modelar el lenguaje coloquial de Guatemala así que pongo palabras coloquiales para ver si el modelo asocia los conceptos correctos.
Query word? chapin chapino 0.834364 chapine 0.766271 guatemalteco 0.764185 chapins 0.748131 chaping 0.720491 chapinismo 0.707461 chapincito 0.697228 chapi 0.693809 guetemalteco 0.691146 chapinpro 0.684765 |
Query word? chilero deahuevo 0.871795 ahuevo 0.860998 chileron 0.855466 deawevo 0.844884 bonito 0.836588 chileroo 0.830754 chiler 0.821744 virgo 0.818426 talega 0.816686 deawebo 0.816431 |
Query word? chela chelada 0.846549 cerveza 0.824583 chelas 0.816342 chelass 0.793193 chelita 0.778253 cervezita 0.762 waro 0.756938 michelada 0.755222 cervez 0.753732 guaro 0.752261 |
Query word? cuate chavo 0.827149 primo 0.808173 hermano 0.750137 cuñado 0.73964 micuate 0.728905 tio 0.728159 uncuate 0.722373 amigo 0.700042 cuatio 0.699274 suegro 0.688571 |
---|---|---|---|
Query word? cerote serote 0.923591 0te 0.880849 ceerote 0.87035 pizado 0.859552 pisado 0.851393 recerote 0.850498 hijueputa 0.846845 jijueputa 0.837298 culero 0.836045 |
Query word? guiro wiro 0.801524 chavito 0.795261 guirito 0.749938 wirito 0.737565 patojito 0.704937 patojo 0.701541 niño 0.692471 guiros 0.685105 wuiro 0.682691 |
Query word? chance trabajo 0.821697 chancesin 0.789478 chancecin 0.777124 chanse 0.775734 chancea 0.762104 chancecito 0.747803 trabajor 0.747429 trabajon 0.746398 chancesito 0.728345 |
Query word? pisto dinero 0.850317 plata 0.801297 dineroo 0.758293 pistio 0.756213 dineroy 0.746532 billlete 0.745822 dineron 0.742313 pistiyo 0.73964 billeton 0.736571 |
He resaltado los significados menos coloquiales para cada palabra coloquial. En definitiva este modelo ha comprendido el lenguaje del foro velmaxiano y sus chapinismos. Aún queda mucho por explorar para próximos posts.