How to Build a Fast “Most-Similar Words” Method in SpaCy | Towards Data Science

The recent developments in natural language processing or NLP introduce language models that must be cautiously used in production. For example, the spaCy large English model, en-core-web-lg contains more than 600 thousand 300-d vectors. Or, the pre-trained word2vec-google-news-300 model contains 3 million 300-d vectors for words and phrases. When you want to calculate a metric across these high-dimension vectors, the solution may easily suffer from computation power.
In this article, I want to share how I speeded up the spaCy library to be used in the word similarity API. The spaCy does not support an efficient most-similar method, contrary to Gensim. I recently published a word similarity API, named Owl. This API lets you extract the most similar words to target words using various word2vec models including spaCy. Given a word, this API returns a list of groups of words that are similar to the original word in predefined contexts such as News or General. The General context uses the spaCy large English model.
If you are not familiar with the Word2Vec models, I recommend reading the article below, first. You will find out why Word2Vec models are simple yet revolutionary in machine learning.
towardsdatascience.com
There is no shortcut. I must compute the distance between the vector of the target word and a large number of vectors stored in the word2vec model. However, I can refine the search space with a filter and speed-up computation with an optimized computing library.
I do not need to restore all vectors. I can prune vectors (i.e., refine the search space) using, for example, .prob attribute, provided by spaCy. This attribute helps to select the most frequent words in English w.prob >= -15. Here, you can use any filter that suits your problem. For example, you may want to filter the pool of vectors using the .sentiment attribute that represents the positivity or negativity of a word. The code below shows you how to build a most-similar method for spaCy. This code is not optimized to run fast though.
The latency is a vital factor in API services. I could not afford even 1-sec extra for computation. So, I optimized the most-similar method, explained above, to meet the requirements that I want my API to meet.
I conducted a lot of experiments to determine what are the main time-consuming parts of the implementation. First, I suspected the sort method must be revised. After profiling the code, I found the .similarity method is the main source of latency and must be optimized.
SpaCy uses the cosine similarity in the backend to compute .similarity. Therefore, I decided to replace word.similarity(w) with its optimized counterpart in the most_similar method above. The optimized method cosine_similarity_numba(w.vector, word.vector) uses the Numba library to speed up computations. The results were improved significantly, i.e., latency decreased from ~5 seconds (not acceptable for an API) to ~1.5 seconds (acceptable for an API). You should replace line 12 in the most_similar method with the line below.
by_similarity = sorted(queries, key=lambda w: cosine_similarity_numba(w.vector, word.vector), reverse=True)
Below, you can find the optimized implementation of the cosine similarity using the Numba library. According to its documentation, Numba is an open-source JIT (Just In Time) compiler that can translate Python and NumPy codes into fast machine codes. This functionality is vital to speed up one’s code with minimal changes.
The most-similar words service must be selected according to the contexts and granularity of results. Context is represented by the word2vec model and granularity is determined by the quality of clustering.
The spaCy large English model contains the GloVe Common Crawl word2vec model trained at the GloVe project, Standford university. One may want to use a contextualized word2vec model trained on a specific corpus of data. So, according to project requirements, a word2vec model must be selected. The Owl API gives you the opportunity to work with various word2vec models.
The granularity of results is an important feature of a most-similar service. In below, I want to compare the final outcomes of the most-similar method that I introduce above and the Owl API. You will see how the results of the latter method are more granularized and, therefore, useful.
"Owl (en-core-web-lg)": { 0: ["seattle", "portland", "washington"],1: ["denver", "chicago", "nashville"],2: ["toronto", "montreal", "ontario", "sydney"]  }"spaCy (en-core-web-lg)": ["toronto","seattle","montreal","portland","ontario","denver","washington","chicago","sydney","nashville"]
Owl API is built upon a series of word2vec models including spaCy en-core-web-lg and advanced clustering techniques to create a revolutionary word similarity service. This API can be used in various projects including language understanding or recommendation systems. You can find more information about Owl API here.
When you want to use the NLP models in production, you must use the optimized implementation of subroutines to speed up computations. For example, the cosine similarity is computed frequently for various tasks in NLP. Therefore, you must ensure that it is implemented and compiled efficiently using, for example, the Numba library. Plus, I highly recommend using the Owl API. You benefit from the contextualized and granularized results, as needed.
If you like this post and want to support me...
Follow me on Medium!
Check out my books on Amazon!
Become a member on Medium!
Connect on Linkedin!
Follow me on Twitter!