Cómo manejar palabras que no están en el vocabulario de word2vec de manera óptima

Tengo una lista de ~ 10 millones de oraciones, donde cada una de ellas contiene hasta 70 palabras.

Estoy ejecutando gensim word2vec en cada palabra y luego tomando el promedio simple de cada oración. El problema es que uso min_count = 1000, por lo que muchas palabras no están en el vocabulario.

Para resolver eso, intersecto la matriz de vocab (que contiene aproximadamente 10000 palabras) con cada oración, y si hay al menos un elemento en esa intersección, devuelve su promedio simple; de ​​lo contrario, devuelve un vector de ceros.

El problema es que el cálculo de cada promedio lleva mucho tiempo cuando lo ejecuto en todo el conjunto de datos, incluso cuando se divide en varios subprocesos, y me gustaría obtener una mejor solución que pudiera ejecutarse más rápido.

Estoy ejecutando esto en una instancia de EC2 r4.4xlarge.

Ya intenté cambiar a doc2vec, que fue mucho más rápido, pero los resultados no fueron tan buenos como el promedio simple de word2vec.

word2vec_aug_32x = Word2Vec(sentences=sentences, min_count=1000, size=32, window=2, workers=16, sg=0) vocab_arr = np.array(list(word2vec_aug_32x.wv.vocab.keys())) def get_embedded_average(sentence): sentence = np.intersect1d(sentence, vocab_arr) if sentence.shape[0] > 0: return np.mean(word2vec_aug_32x[sentence], axis=0).tolist() else: return np.zeros(32).tolist() pool = multiprocessing.Pool(processes=16) w2v_averages = np.asarray(pool.map(get_embedded_average, np.asarray(sentences))) pool.close() 

Si tiene alguna sugerencia de diferentes algoritmos o técnicas que tengan el mismo propósito de incrustar oraciones y pueda resolver mi problema, me encantaría leerlo.

Puedes usar FastText en lugar de Word2Vec. FastText puede incrustar palabras fuera de vocabulario mirando información de subpuntos (ngrams de caracteres). Gensim también tiene una implementación FastText, que es muy fácil de usar:

 from gensim.models import FastText model = FastText(sentences=training_data, size=128, ...) word = 'hello' # can be out of vocabulary embedding = model[word] # fetches the word embedding 

Por Doc2Vec general, la utilidad del vector de texto de Doc2Vec es bastante similar (o cuando se sintoniza, un poco mejor) en comparación con un promedio simple de vectores de palabras. (Después de todo, los algoritmos son muy similares, trabajan en la misma forma de los mismos datos, y los modelos creados tienen aproximadamente el mismo tamaño). Si hubo una gran caída, es posible que haya errores en el proceso de Doc2Vec .

Como lo observa @AnnaKrogager, FastText puede manejar palabras fuera de vocabulario mediante la síntesis de vectores de conjeturas, utilizando fragmentos de palabras. (Esto requiere idiomas en los que las palabras tengan tales raíces compartidas). Los vectores pueden no ser excelentes, pero a menudo son mejores que ignorar por completo las palabras desconocidas, o usar vectores de todo cero o vectores de conexión aleatoria.

¿La división entre procesos ayuda al tiempo de ejecución? Porque hay muchos gastos generales en el envío de subprocesos de lotes de trabajo y subprocesos, y los subprocesos en Python pueden causar un aumento repentino de las necesidades de memoria, y tanto los gastos generales y posiblemente el intercambio de memoria virtual podrían superar cualquier otro beneficio del paralelismo .