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.

(Fuente)

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.

( Bolsa de palabras vrs skipgram para detectar el contexto y la funcionalidad de cada palabra.Fuente. )

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.