From 03c8bb9a1f2ffb7ed3a7c6a4febd8fc8bbe4acf6 Mon Sep 17 00:00:00 2001 From: S Mono <10430241+xh2@users.noreply.github.com> Date: Fri, 24 Jul 2020 14:09:57 +0100 Subject: [PATCH 01/32] Make docs clearer on `alpha` parameter in LDA model --- gensim/models/ldamodel.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/gensim/models/ldamodel.py b/gensim/models/ldamodel.py index afb0e035c9..c623814fe0 100755 --- a/gensim/models/ldamodel.py +++ b/gensim/models/ldamodel.py @@ -378,8 +378,9 @@ def __init__(self, corpus=None, num_topics=100, id2word=None, Can be set to an 1D array of length equal to the number of expected topics that expresses our a-priori belief for the each topics' probability. Alternatively default prior selecting strategies can be employed by supplying a string: - - * 'asymmetric': Uses a fixed normalized asymmetric prior of `1.0 / topicno`. + + * 'symmetric': Default; uses a fixed symmetric prior per topic, + * 'asymmetric': Uses a fixed normalized asymmetric prior of `1.0 / (topic_index + sqrt(topic_no))`, * 'auto': Learns an asymmetric prior from the corpus (not available if `distributed==True`). eta : {float, np.array, str}, optional A-priori belief on word probability, this can be: @@ -536,7 +537,8 @@ def init_dir_prior(self, prior, name): If `name` == 'alpha', then the prior can be: * an 1D array of length equal to the number of expected topics, - * 'asymmetric': Uses a fixed normalized asymmetric prior of `1.0 / topicno`. + * 'symmetric': Uses a fixed symmetric prior per topic, + * 'asymmetric': Uses a fixed normalized asymmetric prior of `1.0 / (topic_index + sqrt(topic_no))`, * 'auto': Learns an asymmetric prior from the corpus. name : {'alpha', 'eta'} Whether the `prior` is parameterized by the alpha vector (1 parameter per topic) From 4e1b09c5099ad780fad16bee05ad67febed93a85 Mon Sep 17 00:00:00 2001 From: S Mono <10430241+xh2@users.noreply.github.com> Date: Fri, 24 Jul 2020 15:20:19 +0100 Subject: [PATCH 02/32] Update Hoffman paper link --- gensim/models/ldamodel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gensim/models/ldamodel.py b/gensim/models/ldamodel.py index afb0e035c9..87a1678ce4 100755 --- a/gensim/models/ldamodel.py +++ b/gensim/models/ldamodel.py @@ -14,7 +14,7 @@ The core estimation code is based on the `onlineldavb.py script `_, by `Hoffman, Blei, Bach: -Online Learning for Latent Dirichlet Allocation, NIPS 2010 `_. +Online Learning for Latent Dirichlet Allocation, NIPS 2010 `_. The algorithm: From 25005c53a00e20900b608a4dbc6d27a648668ab6 Mon Sep 17 00:00:00 2001 From: Gordon Mohr Date: Sat, 25 Jul 2020 23:54:06 -0700 Subject: [PATCH 03/32] rm whitespace --- gensim/models/ldamodel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gensim/models/ldamodel.py b/gensim/models/ldamodel.py index c623814fe0..afe2b088c2 100755 --- a/gensim/models/ldamodel.py +++ b/gensim/models/ldamodel.py @@ -378,7 +378,7 @@ def __init__(self, corpus=None, num_topics=100, id2word=None, Can be set to an 1D array of length equal to the number of expected topics that expresses our a-priori belief for the each topics' probability. Alternatively default prior selecting strategies can be employed by supplying a string: - + * 'symmetric': Default; uses a fixed symmetric prior per topic, * 'asymmetric': Uses a fixed normalized asymmetric prior of `1.0 / (topic_index + sqrt(topic_no))`, * 'auto': Learns an asymmetric prior from the corpus (not available if `distributed==True`). From f34956c0cf803b12859a8258f7ccac013264bb35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20=C5=98eh=C5=AF=C5=99ek?= Date: Sun, 26 Jul 2020 11:01:07 +0200 Subject: [PATCH 04/32] Update gensim/models/ldamodel.py --- gensim/models/ldamodel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gensim/models/ldamodel.py b/gensim/models/ldamodel.py index afe2b088c2..aa0a90f1bb 100755 --- a/gensim/models/ldamodel.py +++ b/gensim/models/ldamodel.py @@ -380,7 +380,7 @@ def __init__(self, corpus=None, num_topics=100, id2word=None, Alternatively default prior selecting strategies can be employed by supplying a string: * 'symmetric': Default; uses a fixed symmetric prior per topic, - * 'asymmetric': Uses a fixed normalized asymmetric prior of `1.0 / (topic_index + sqrt(topic_no))`, + * 'asymmetric': Uses a fixed normalized asymmetric prior of `1.0 / (topic_index + sqrt(num_topics))`, * 'auto': Learns an asymmetric prior from the corpus (not available if `distributed==True`). eta : {float, np.array, str}, optional A-priori belief on word probability, this can be: From 7d0ef9e2ce311c3eab1663bab6298070a1b131d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20=C5=98eh=C5=AF=C5=99ek?= Date: Sun, 26 Jul 2020 11:01:15 +0200 Subject: [PATCH 05/32] Update gensim/models/ldamodel.py --- gensim/models/ldamodel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gensim/models/ldamodel.py b/gensim/models/ldamodel.py index aa0a90f1bb..eb65150f23 100755 --- a/gensim/models/ldamodel.py +++ b/gensim/models/ldamodel.py @@ -538,7 +538,7 @@ def init_dir_prior(self, prior, name): * an 1D array of length equal to the number of expected topics, * 'symmetric': Uses a fixed symmetric prior per topic, - * 'asymmetric': Uses a fixed normalized asymmetric prior of `1.0 / (topic_index + sqrt(topic_no))`, + * 'asymmetric': Uses a fixed normalized asymmetric prior of `1.0 / (topic_index + sqrt(num_topics))`, * 'auto': Learns an asymmetric prior from the corpus. name : {'alpha', 'eta'} Whether the `prior` is parameterized by the alpha vector (1 parameter per topic) From 78778a9d7ef7805153714bc9eaa985a310879163 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20=C5=98eh=C5=AF=C5=99ek?= Date: Sun, 26 Jul 2020 12:40:18 +0200 Subject: [PATCH 06/32] Update gensim/models/ldamodel.py --- gensim/models/ldamodel.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gensim/models/ldamodel.py b/gensim/models/ldamodel.py index 87a1678ce4..a438a3143a 100755 --- a/gensim/models/ldamodel.py +++ b/gensim/models/ldamodel.py @@ -14,7 +14,8 @@ The core estimation code is based on the `onlineldavb.py script `_, by `Hoffman, Blei, Bach: -Online Learning for Latent Dirichlet Allocation, NIPS 2010 `_. +Online Learning for Latent Dirichlet Allocation, NIPS 2010 +`_. The algorithm: From b70c82613ac59656408f2403dfc2408f461eecff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20=C5=98eh=C5=AF=C5=99ek?= Date: Sun, 26 Jul 2020 20:33:27 +0200 Subject: [PATCH 07/32] re-applying changes from #2821 --- docs/src/_matutils.rst | 6 +- docs/src/apiref.rst | 5 +- .../core/run_similarity_queries.rst | 51 +++--- .../auto_examples/core/sg_execution_times.rst | 15 +- docs/src/auto_examples/index.rst | 98 +++++------ docs/src/gallery/tutorials/run_annoy.py | 111 ++++++------ docs/src/intro.rst | 2 - docs/src/models/_fasttext_bin.rst | 6 +- docs/src/parsing/porter.rst | 2 +- docs/src/similarities/annoy.rst | 8 + docs/src/similarities/index.rst | 8 - docs/src/summarization/commons.rst | 6 +- docs/src/summarization/graph.rst | 6 +- docs/src/summarization/summariser.rst | 6 +- docs/src/summarization/textcleaner.rst | 6 +- docs/src/test/utils.rst | 6 +- gensim/__init__.py | 12 +- gensim/corpora/wikicorpus.py | 9 +- gensim/models/_fasttext_bin.py | 6 + gensim/models/doc2vec.py | 18 +- gensim/models/fasttext.py | 44 ++--- gensim/models/hdpmodel.py | 1 - gensim/models/ldamodel.py | 12 +- gensim/models/word2vec.py | 5 +- gensim/parsing/porter.py | 5 +- gensim/parsing/preprocessing.py | 24 +-- gensim/similarities/{index.py => annoy.py} | 94 ++++------ gensim/similarities/nmslib.py | 82 +++++---- gensim/similarities/termsim.py | 6 +- gensim/sklearn_api/tfidf.py | 22 +-- gensim/summarization/bm25.py | 17 +- gensim/summarization/keywords.py | 47 ++--- gensim/summarization/summarizer.py | 14 +- gensim/summarization/textcleaner.py | 29 ++-- gensim/test/test_corpora_dictionary.py | 8 - gensim/test/test_fasttext.py | 6 +- gensim/test/test_keyedvectors.py | 4 +- gensim/test/test_similarities.py | 162 +++++++++--------- gensim/test/utils.py | 4 +- setup.py | 4 +- 40 files changed, 458 insertions(+), 519 deletions(-) create mode 100644 docs/src/similarities/annoy.rst delete mode 100644 docs/src/similarities/index.rst rename gensim/similarities/{index.py => annoy.py} (66%) diff --git a/docs/src/_matutils.rst b/docs/src/_matutils.rst index 13459a1bae..545e0e6d7f 100644 --- a/docs/src/_matutils.rst +++ b/docs/src/_matutils.rst @@ -1,8 +1,8 @@ -:mod:`_matutils` -- Cython matutils -=================================== +:mod:`_matutils` -- Compiled extension for math utils +===================================================== .. automodule:: gensim._matutils - :synopsis: Cython math utils + :synopsis: Compiled extension for math utils :members: :inherited-members: :undoc-members: diff --git a/docs/src/apiref.rst b/docs/src/apiref.rst index 1e3e341487..1cc190e677 100644 --- a/docs/src/apiref.rst +++ b/docs/src/apiref.rst @@ -50,6 +50,7 @@ Modules: models/_fasttext_bin models/phrases models/poincare + viz/poincare models/coherencemodel models/basemodel models/callbacks @@ -63,7 +64,8 @@ Modules: models/wrappers/varembed similarities/docsim similarities/termsim - similarities/index + similarities/annoy + similarities/nmslib sklearn_api/atmodel sklearn_api/d2vmodel sklearn_api/hdp @@ -102,4 +104,3 @@ Modules: summarization/summariser summarization/syntactic_unit summarization/textcleaner - viz/poincare diff --git a/docs/src/auto_examples/core/run_similarity_queries.rst b/docs/src/auto_examples/core/run_similarity_queries.rst index b3a107e80b..1dd4624834 100644 --- a/docs/src/auto_examples/core/run_similarity_queries.rst +++ b/docs/src/auto_examples/core/run_similarity_queries.rst @@ -1,10 +1,12 @@ -.. note:: - :class: sphx-glr-download-link-note +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note - Click :ref:`here ` to download the full example code -.. rst-class:: sphx-glr-example-title + Click :ref:`here ` to download the full example code + .. rst-class:: sphx-glr-example-title -.. _sphx_glr_auto_examples_core_run_similarity_queries.py: + .. _sphx_glr_auto_examples_core_run_similarity_queries.py: Similarity Queries @@ -25,6 +27,7 @@ Demonstrates querying a corpus for similar documents. + Creating the Corpus ------------------- @@ -78,6 +81,7 @@ if you completed it, feel free to skip to the next section. + Similarity interface -------------------- @@ -111,6 +115,7 @@ LSI space: + For the purposes of this tutorial, there are only two things you need to know about LSI. First, it's just another transformation: it transforms vectors from one space to another. Second, the benefit of LSI is that enables identifying patterns and relationships between terms (in our case, words in a document) and topics. @@ -142,7 +147,8 @@ no random-walk static ranks, just a semantic extension over the boolean keyword .. code-block:: none - [(0, 0.4618210045327158), (1, 0.07002766527900064)] + [(0, 0.4618210045327162), (1, -0.07002766527900038)] + @@ -173,6 +179,7 @@ might also be indexing a different corpus altogether. + .. warning:: The class :class:`similarities.MatrixSimilarity` is only appropriate when the whole set of vectors fits into memory. For example, a corpus of one million documents @@ -198,6 +205,7 @@ Index persistency is handled via the standard :func:`save` and :func:`load` func + This is true for all similarity indexing classes (:class:`similarities.Similarity`, :class:`similarities.MatrixSimilarity` and :class:`similarities.SparseMatrixSimilarity`). Also in the following, `index` can be an object of any of these. When in doubt, @@ -230,6 +238,7 @@ To obtain similarities of our query document against the nine indexed documents: + Cosine measure returns similarities in the range `<-1, 1>` (the greater, the more similar), so that the first document has a score of 0.99809301 etc. @@ -254,15 +263,16 @@ order, and obtain the final answer to the query `"Human computer interaction"`: .. code-block:: none - (2, 0.9984453) Human machine interface for lab abc computer applications - (0, 0.998093) A survey of user opinion of computer system response time - (3, 0.9865886) The EPS user interface management system - (1, 0.93748635) System and human system engineering testing of EPS - (4, 0.90755945) Relation of user perceived response time to error measurement - (8, 0.050041765) The generation of random binary unordered trees - (7, -0.09879464) The intersection graph of paths in trees - (6, -0.10639259) Graph minors IV Widths of trees and well quasi ordering - (5, -0.12416792) Graph minors A survey + 0.9984453 The EPS user interface management system + 0.998093 Human machine interface for lab abc computer applications + 0.9865886 System and human system engineering testing of EPS + 0.93748635 A survey of user opinion of computer system response time + 0.90755945 Relation of user perceived response time to error measurement + 0.050041765 Graph minors A survey + -0.09879464 Graph minors IV Widths of trees and well quasi ordering + -0.10639259 The intersection graph of paths in trees + -0.12416792 The generation of random binary unordered trees + @@ -319,17 +329,18 @@ on large datasets easily, and to facilitate prototyping of new algorithms for re .. code-block:: none - /Volumes/work/workspace/gensim_misha/docs/src/gallery/core/run_similarity_queries.py:194: UserWarning: Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure. + /Volumes/work/workspace/gensim/trunk/docs/src/gallery/core/run_similarity_queries.py:194: UserWarning: Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure. plt.show() + .. rst-class:: sphx-glr-timing - **Total running time of the script:** ( 0 minutes 0.663 seconds) + **Total running time of the script:** ( 0 minutes 1.563 seconds) -**Estimated memory usage:** 6 MB +**Estimated memory usage:** 37 MB .. _sphx_glr_download_auto_examples_core_run_similarity_queries.py: @@ -342,13 +353,13 @@ on large datasets easily, and to facilitate prototyping of new algorithms for re - .. container:: sphx-glr-download + .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: run_similarity_queries.py ` - .. container:: sphx-glr-download + .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: run_similarity_queries.ipynb ` diff --git a/docs/src/auto_examples/core/sg_execution_times.rst b/docs/src/auto_examples/core/sg_execution_times.rst index 4b085e5650..ef2f22d0ba 100644 --- a/docs/src/auto_examples/core/sg_execution_times.rst +++ b/docs/src/auto_examples/core/sg_execution_times.rst @@ -5,9 +5,14 @@ Computation times ================= -**00:00.844** total execution time for **auto_examples_core** files: +**00:01.563** total execution time for **auto_examples_core** files: -- **00:00.844**: :ref:`sphx_glr_auto_examples_core_run_topics_and_transformations.py` (``run_topics_and_transformations.py``) -- **00:00.000**: :ref:`sphx_glr_auto_examples_core_run_core_concepts.py` (``run_core_concepts.py``) -- **00:00.000**: :ref:`sphx_glr_auto_examples_core_run_corpora_and_vector_spaces.py` (``run_corpora_and_vector_spaces.py``) -- **00:00.000**: :ref:`sphx_glr_auto_examples_core_run_similarity_queries.py` (``run_similarity_queries.py``) ++--------------------------------------------------------------------------------------------------------------+-----------+---------+ +| :ref:`sphx_glr_auto_examples_core_run_similarity_queries.py` (``run_similarity_queries.py``) | 00:01.563 | 37.4 MB | ++--------------------------------------------------------------------------------------------------------------+-----------+---------+ +| :ref:`sphx_glr_auto_examples_core_run_core_concepts.py` (``run_core_concepts.py``) | 00:00.000 | 0.0 MB | ++--------------------------------------------------------------------------------------------------------------+-----------+---------+ +| :ref:`sphx_glr_auto_examples_core_run_corpora_and_vector_spaces.py` (``run_corpora_and_vector_spaces.py``) | 00:00.000 | 0.0 MB | ++--------------------------------------------------------------------------------------------------------------+-----------+---------+ +| :ref:`sphx_glr_auto_examples_core_run_topics_and_transformations.py` (``run_topics_and_transformations.py``) | 00:00.000 | 0.0 MB | ++--------------------------------------------------------------------------------------------------------------+-----------+---------+ diff --git a/docs/src/auto_examples/index.rst b/docs/src/auto_examples/index.rst index 5566611a8b..1c9bfd20c1 100644 --- a/docs/src/auto_examples/index.rst +++ b/docs/src/auto_examples/index.rst @@ -13,7 +13,7 @@ If you're thinking about contributing documentation, please see :ref:`sphx_glr_a .. raw:: html -
+
@@ -33,9 +33,9 @@ Understanding this functionality is vital for using gensim effectively. .. only:: html - .. figure:: /auto_examples/core/images/thumb/sphx_glr_run_core_concepts_thumb.png + .. figure:: /auto_examples/core/images/thumb/sphx_glr_run_core_concepts_thumb.png - :ref:`sphx_glr_auto_examples_core_run_core_concepts.py` + :ref:`sphx_glr_auto_examples_core_run_core_concepts.py` .. raw:: html @@ -53,9 +53,9 @@ Understanding this functionality is vital for using gensim effectively. .. only:: html - .. figure:: /auto_examples/core/images/thumb/sphx_glr_run_corpora_and_vector_spaces_thumb.png + .. figure:: /auto_examples/core/images/thumb/sphx_glr_run_corpora_and_vector_spaces_thumb.png - :ref:`sphx_glr_auto_examples_core_run_corpora_and_vector_spaces.py` + :ref:`sphx_glr_auto_examples_core_run_corpora_and_vector_spaces.py` .. raw:: html @@ -69,13 +69,13 @@ Understanding this functionality is vital for using gensim effectively. .. raw:: html -
+
.. only:: html - .. figure:: /auto_examples/core/images/thumb/sphx_glr_run_topics_and_transformations_thumb.png + .. figure:: /auto_examples/core/images/thumb/sphx_glr_run_topics_and_transformations_thumb.png - :ref:`sphx_glr_auto_examples_core_run_topics_and_transformations.py` + :ref:`sphx_glr_auto_examples_core_run_topics_and_transformations.py` .. raw:: html @@ -89,13 +89,13 @@ Understanding this functionality is vital for using gensim effectively. .. raw:: html -
+
.. only:: html - .. figure:: /auto_examples/core/images/thumb/sphx_glr_run_similarity_queries_thumb.png + .. figure:: /auto_examples/core/images/thumb/sphx_glr_run_similarity_queries_thumb.png - :ref:`sphx_glr_auto_examples_core_run_similarity_queries.py` + :ref:`sphx_glr_auto_examples_core_run_similarity_queries.py` .. raw:: html @@ -108,7 +108,7 @@ Understanding this functionality is vital for using gensim effectively. /auto_examples/core/run_similarity_queries .. raw:: html -
+
@@ -127,9 +127,9 @@ Learning-oriented lessons that introduce a particular gensim feature, e.g. a mod .. only:: html - .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_word2vec_thumb.png + .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_word2vec_thumb.png - :ref:`sphx_glr_auto_examples_tutorials_run_word2vec.py` + :ref:`sphx_glr_auto_examples_tutorials_run_word2vec.py` .. raw:: html @@ -147,9 +147,9 @@ Learning-oriented lessons that introduce a particular gensim feature, e.g. a mod .. only:: html - .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_doc2vec_lee_thumb.png + .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_doc2vec_lee_thumb.png - :ref:`sphx_glr_auto_examples_tutorials_run_doc2vec_lee.py` + :ref:`sphx_glr_auto_examples_tutorials_run_doc2vec_lee.py` .. raw:: html @@ -163,13 +163,13 @@ Learning-oriented lessons that introduce a particular gensim feature, e.g. a mod .. raw:: html -
+
.. only:: html - .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_fasttext_thumb.png + .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_fasttext_thumb.png - :ref:`sphx_glr_auto_examples_tutorials_run_fasttext.py` + :ref:`sphx_glr_auto_examples_tutorials_run_fasttext.py` .. raw:: html @@ -183,13 +183,13 @@ Learning-oriented lessons that introduce a particular gensim feature, e.g. a mod .. raw:: html -
+
.. only:: html - .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_annoy_thumb.png + .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_annoy_thumb.png - :ref:`sphx_glr_auto_examples_tutorials_run_annoy.py` + :ref:`sphx_glr_auto_examples_tutorials_run_annoy.py` .. raw:: html @@ -207,9 +207,9 @@ Learning-oriented lessons that introduce a particular gensim feature, e.g. a mod .. only:: html - .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_lda_thumb.png + .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_lda_thumb.png - :ref:`sphx_glr_auto_examples_tutorials_run_lda.py` + :ref:`sphx_glr_auto_examples_tutorials_run_lda.py` .. raw:: html @@ -227,9 +227,9 @@ Learning-oriented lessons that introduce a particular gensim feature, e.g. a mod .. only:: html - .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_distance_metrics_thumb.png + .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_distance_metrics_thumb.png - :ref:`sphx_glr_auto_examples_tutorials_run_distance_metrics.py` + :ref:`sphx_glr_auto_examples_tutorials_run_distance_metrics.py` .. raw:: html @@ -247,9 +247,9 @@ Learning-oriented lessons that introduce a particular gensim feature, e.g. a mod .. only:: html - .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_wmd_thumb.png + .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_wmd_thumb.png - :ref:`sphx_glr_auto_examples_tutorials_run_wmd.py` + :ref:`sphx_glr_auto_examples_tutorials_run_wmd.py` .. raw:: html @@ -267,9 +267,9 @@ Learning-oriented lessons that introduce a particular gensim feature, e.g. a mod .. only:: html - .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_summarization_thumb.png + .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_summarization_thumb.png - :ref:`sphx_glr_auto_examples_tutorials_run_summarization.py` + :ref:`sphx_glr_auto_examples_tutorials_run_summarization.py` .. raw:: html @@ -287,9 +287,9 @@ Learning-oriented lessons that introduce a particular gensim feature, e.g. a mod .. only:: html - .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_pivoted_doc_norm_thumb.png + .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_pivoted_doc_norm_thumb.png - :ref:`sphx_glr_auto_examples_tutorials_run_pivoted_doc_norm.py` + :ref:`sphx_glr_auto_examples_tutorials_run_pivoted_doc_norm.py` .. raw:: html @@ -302,7 +302,7 @@ Learning-oriented lessons that introduce a particular gensim feature, e.g. a mod /auto_examples/tutorials/run_pivoted_doc_norm .. raw:: html -
+
@@ -317,13 +317,13 @@ These **goal-oriented guides** demonstrate how to **solve a specific problem** u .. raw:: html -
+
.. only:: html - .. figure:: /auto_examples/howtos/images/thumb/sphx_glr_run_downloader_api_thumb.png + .. figure:: /auto_examples/howtos/images/thumb/sphx_glr_run_downloader_api_thumb.png - :ref:`sphx_glr_auto_examples_howtos_run_downloader_api.py` + :ref:`sphx_glr_auto_examples_howtos_run_downloader_api.py` .. raw:: html @@ -337,13 +337,13 @@ These **goal-oriented guides** demonstrate how to **solve a specific problem** u .. raw:: html -
+
.. only:: html - .. figure:: /auto_examples/howtos/images/thumb/sphx_glr_run_doc_thumb.png + .. figure:: /auto_examples/howtos/images/thumb/sphx_glr_run_doc_thumb.png - :ref:`sphx_glr_auto_examples_howtos_run_doc.py` + :ref:`sphx_glr_auto_examples_howtos_run_doc.py` .. raw:: html @@ -361,9 +361,9 @@ These **goal-oriented guides** demonstrate how to **solve a specific problem** u .. only:: html - .. figure:: /auto_examples/howtos/images/thumb/sphx_glr_run_doc2vec_imdb_thumb.png + .. figure:: /auto_examples/howtos/images/thumb/sphx_glr_run_doc2vec_imdb_thumb.png - :ref:`sphx_glr_auto_examples_howtos_run_doc2vec_imdb.py` + :ref:`sphx_glr_auto_examples_howtos_run_doc2vec_imdb.py` .. raw:: html @@ -381,9 +381,9 @@ These **goal-oriented guides** demonstrate how to **solve a specific problem** u .. only:: html - .. figure:: /auto_examples/howtos/images/thumb/sphx_glr_run_compare_lda_thumb.png + .. figure:: /auto_examples/howtos/images/thumb/sphx_glr_run_compare_lda_thumb.png - :ref:`sphx_glr_auto_examples_howtos_run_compare_lda.py` + :ref:`sphx_glr_auto_examples_howtos_run_compare_lda.py` .. raw:: html @@ -396,7 +396,7 @@ These **goal-oriented guides** demonstrate how to **solve a specific problem** u /auto_examples/howtos/run_compare_lda .. raw:: html -
+
@@ -440,7 +440,7 @@ Blog posts, tutorial videos, hackathons and other useful Gensim resources, from .. raw:: html -
+
@@ -450,15 +450,15 @@ Blog posts, tutorial videos, hackathons and other useful Gensim resources, from :class: sphx-glr-footer-gallery - .. container:: sphx-glr-download + .. container:: sphx-glr-download sphx-glr-download-python - :download:`Download all examples in Python source code: auto_examples_python.zip ` + :download:`Download all examples in Python source code: auto_examples_python.zip ` - .. container:: sphx-glr-download + .. container:: sphx-glr-download sphx-glr-download-jupyter - :download:`Download all examples in Jupyter notebooks: auto_examples_jupyter.zip ` + :download:`Download all examples in Jupyter notebooks: auto_examples_jupyter.zip ` .. only:: html diff --git a/docs/src/gallery/tutorials/run_annoy.py b/docs/src/gallery/tutorials/run_annoy.py index 76aef05788..22808b8521 100644 --- a/docs/src/gallery/tutorials/run_annoy.py +++ b/docs/src/gallery/tutorials/run_annoy.py @@ -1,17 +1,17 @@ r""" -Similarity Queries with Annoy and Word2Vec -========================================== +Fast Similarity Queries with Annoy and Word2Vec +=============================================== Introduces the annoy library for similarity queries using a Word2Vec model. """ -LOGS = False +LOGS = False # Set to True if you want to see progress in logs. if LOGS: import logging logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO) ############################################################################### -# The `Annoy Approximate Nearest Neighbors Oh Yeah +# The `Annoy "Approximate Nearest Neighbors Oh Yeah" # `_ library enables similarity queries with # a Word2Vec model. The current implementation for finding k nearest neighbors # in a vector space in gensim has linear complexity via brute force in the @@ -19,10 +19,10 @@ # The retrieved results are exact, which is an overkill in many applications: # approximate results retrieved in sub-linear time may be enough. Annoy can # find approximate nearest neighbors much faster. -# +# # Outline # ------- -# +# # 1. Download Text8 Corpus # 2. Train the Word2Vec model # 3. Construct AnnoyIndex with model & make a similarity query @@ -31,14 +31,14 @@ # 6. Save memory by via memory-mapping indices saved to disk # 7. Evaluate relationship of ``num_trees`` to initialization time and accuracy # 8. Work with Google's word2vec C formats -# +# ############################################################################### # 1. Download Text8 corpus # ------------------------ import gensim.downloader as api text8_path = api.load('text8', return_path=True) -text8_path +print("Using corpus from", text8_path) ############################################################################### # 2. Train the Word2Vec model @@ -61,37 +61,39 @@ 'negative': 5 } model = Word2Vec(Text8Corpus(text8_path), **params) -print(model) +print("Using model", model) ############################################################################### # 3. Construct AnnoyIndex with model & make a similarity query # ------------------------------------------------------------ -# -# An instance of ``AnnoyIndexer`` needs to be created in order to use Annoy in gensim. The ``AnnoyIndexer`` class is located in ``gensim.similarities.index`` -# +# +# An instance of ``AnnoyIndexer`` needs to be created in order to use Annoy in gensim. The ``AnnoyIndexer`` class is located in ``gensim.similarities.annoy``. +# # ``AnnoyIndexer()`` takes two parameters: -# -# * **model**: A ``Word2Vec`` or ``Doc2Vec`` model +# +# * **model**: A ``Word2Vec`` or ``Doc2Vec`` model. # * **num_trees**: A positive integer. ``num_trees`` effects the build # time and the index size. **A larger value will give more accurate results, # but larger indexes**. More information on what trees in Annoy do can be found # `here `__. The relationship # between ``num_trees``\ , build time, and accuracy will be investigated later -# in the tutorial. -# +# in the tutorial. +# # Now that we are ready to make a query, lets find the top 5 most similar words # to "science" in the Text8 corpus. To make a similarity query we call # ``Word2Vec.most_similar`` like we would traditionally, but with an added -# parameter, ``indexer``. The only supported indexer in gensim as of now is -# Annoy. -# -from gensim.similarities.index import AnnoyIndexer +# parameter, ``indexer``. +# +# Apart from Annoy, Gensim also supports the NMSLIB indexer. NMSLIB is a similar library to +# Annoy – both support fast, approximate searches for similar vectors. +# +from gensim.similarities.annoy import AnnoyIndexer # 100 trees are being used in this example annoy_index = AnnoyIndexer(model, 100) # Derive the vector for the word "science" in our model vector = model.wv["science"] -# The instance of AnnoyIndexer we just created is passed +# The instance of AnnoyIndexer we just created is passed approximate_neighbors = model.wv.most_similar([vector], topn=11, indexer=annoy_index) # Neatly print the approximate_neighbors and their corresponding cosine similarity values print("Approximate Neighbors") @@ -99,7 +101,7 @@ print(neighbor) normal_neighbors = model.wv.most_similar([vector], topn=11) -print("\nNormal (not Annoy-indexed) Neighbors") +print("\nExact Neighbors") for neighbor in normal_neighbors: print(neighbor) @@ -117,7 +119,7 @@ model.init_sims() annoy_index = AnnoyIndexer(model, 100) -# Dry run to make sure both indices are fully in RAM +# Dry run to make sure both indexes are fully in RAM vector = model.wv.vectors_norm[0] model.wv.most_similar([vector], topn=5, indexer=annoy_index) model.wv.most_similar([vector], topn=5) @@ -126,10 +128,7 @@ import numpy as np def avg_query_time(annoy_index=None, queries=1000): - """ - Average query time of a most_similar method over 1000 random queries, - uses annoy if given an indexer - """ + """Average query time of a most_similar method over 1000 random queries.""" total_time = 0 for _ in range(queries): rand_vec = model.wv.vectors_norm[np.random.randint(0, len(model.wv.vocab))] @@ -138,7 +137,7 @@ def avg_query_time(annoy_index=None, queries=1000): total_time += time.process_time() - start_time return total_time / queries -queries = 10000 +queries = 1000 gensim_time = avg_query_time(queries=queries) annoy_time = avg_query_time(annoy_index, queries=queries) @@ -152,7 +151,7 @@ def avg_query_time(annoy_index=None, queries=1000): # run to run and is particular to this data set, BLAS setup, Annoy # parameters(as tree size increases speedup factor decreases), machine # specifications, among other factors. -# +# # .. Important:: # Initialization time for the annoy indexer was not included in the times. # The optimal knn algorithm for you to use will depend on how many queries @@ -162,7 +161,7 @@ def avg_query_time(annoy_index=None, queries=1000): # results. If you are making many queries however, the time it takes to # initialize the annoy indexer will be made up for by the incredibly fast # retrieval times for queries once the indexer has been initialized -# +# # .. Important:: # Gensim's 'most_similar' method is using numpy operations in the form of # dot product whereas Annoy's method isnt. If 'numpy' on your machine is @@ -171,17 +170,17 @@ def avg_query_time(annoy_index=None, queries=1000): # Cookbook # `_ # for more details. -# +# ############################################################################### # 5. Persisting indices to disk # ----------------------------- -# +# # You can save and load your indexes from/to disk to prevent having to # construct them each time. This will create two files on disk, *fname* and # *fname.d*. Both files are needed to correctly restore all attributes. Before # loading an index, you will have to create an empty AnnoyIndexer object. -# +# fname = '/tmp/mymodel.index' # Persist index to disk @@ -199,25 +198,25 @@ def avg_query_time(annoy_index=None, queries=1000): approximate_neighbors2 = model.wv.most_similar([vector], topn=11, indexer=annoy_index2) for neighbor in approximate_neighbors2: print(neighbor) - + assert approximate_neighbors == approximate_neighbors2 ############################################################################### # Be sure to use the same model at load that was used originally, otherwise you # will get unexpected behaviors. -# +# ############################################################################### -# 6. Save memory via memory-mapping indices saved to disk +# 6. Save memory via memory-mapping indexes saved to disk # ------------------------------------------------------- -# +# # Annoy library has a useful feature that indices can be memory-mapped from # disk. It saves memory when the same index is used by several processes. -# +# # Below are two snippets of code. First one has a separate index for each # process. The second snipped shares the index between two processes via # memory-mapping. The second example uses less total RAM as it is shared. -# +# # Remove verbosity from code below (if logging active) if LOGS: @@ -228,9 +227,9 @@ def avg_query_time(annoy_index=None, queries=1000): import psutil ############################################################################### -# Bad example: two processes load the Word2vec model from disk and create there -# own Annoy indices from that model. -# +# Bad example: two processes load the Word2vec model from disk and create their +# own Annoy index from that model. +# model.save('/tmp/mymodel.pkl') @@ -253,8 +252,8 @@ def f(process_id): ############################################################################### # Good example: two processes load both the Word2vec model and index from disk -# and memory-map the index -# +# and memory-map the index. +# model.save('/tmp/mymodel.pkl') @@ -280,12 +279,12 @@ def f(process_id): ############################################################################### # 7. Evaluate relationship of ``num_trees`` to initialization time and accuracy # ----------------------------------------------------------------------------- -# +# import matplotlib.pyplot as plt ############################################################################### # Build dataset of Initialization times and accuracy measures: -# +# exact_results = [element[0] for element in model.wv.most_similar([model.wv.vectors_norm[0]], topn=100)] @@ -323,20 +322,20 @@ def f(process_id): # From the above, we can see that the initialization time of the annoy indexer # increases in a linear fashion with num_trees. Initialization time will vary # from corpus to corpus, in the graph above the lee corpus was used -# +# # Furthermore, in this dataset, the accuracy seems logarithmically related to # the number of trees. We see an improvement in accuracy with more trees, but -# the relationship is nonlinear. -# +# the relationship is nonlinear. +# ############################################################################### # 7. Work with Google word2vec files # ---------------------------------- -# +# # Our model can be exported to a word2vec C format. There is a binary and a # plain text word2vec format. Both can be read with a variety of other # software, or imported back into gensim as a ``KeyedVectors`` object. -# +# # To export our model as text model.wv.save_word2vec_format('/tmp/vectors.txt', binary=False) @@ -344,7 +343,7 @@ def f(process_id): from smart_open import open # View the first 3 lines of the exported file -# The first line has the total number of entries and the vector dimension count. +# The first line has the total number of entries and the vector dimension count. # The next lines have a key (a string) followed by its vector. with open('/tmp/vectors.txt') as myfile: for i in range(3): @@ -377,17 +376,17 @@ def f(process_id): print(neighbor) normal_neighbors = wv.most_similar([vector], topn=11) -print("\nNormal (not Annoy-indexed) Neighbors") +print("\nExact Neighbors") for neighbor in normal_neighbors: print(neighbor) ############################################################################### # Recap # ----- -# +# # In this notebook we used the Annoy module to build an indexed approximation # of our word embeddings. To do so, we did the following steps: -# +# # 1. Download Text8 Corpus # 2. Train Word2Vec Model # 3. Construct AnnoyIndex with model & make a similarity query @@ -395,4 +394,4 @@ def f(process_id): # 5. Save memory by via memory-mapping indices saved to disk # 6. Evaluate relationship of ``num_trees`` to initialization time and accuracy # 7. Work with Google's word2vec C formats -# +# diff --git a/docs/src/intro.rst b/docs/src/intro.rst index 1f02030fa4..2b9d564600 100644 --- a/docs/src/intro.rst +++ b/docs/src/intro.rst @@ -22,7 +22,6 @@ Once these statistical patterns are found, any plain text documents (sentence, p Space Model `_ and `unsupervised document analysis `_ on Wikipedia. - .. _design: Features @@ -51,7 +50,6 @@ The **principal design objectives** behind Gensim are: Reach out at info@scaletext.com if you need an industry-grade NLP tool with professional support. - .. _availability: Availability diff --git a/docs/src/models/_fasttext_bin.rst b/docs/src/models/_fasttext_bin.rst index eb9a0ad950..c55bc517fc 100644 --- a/docs/src/models/_fasttext_bin.rst +++ b/docs/src/models/_fasttext_bin.rst @@ -1,8 +1,8 @@ -:mod:`models._fasttext_bin` -- Facebook I/O -=========================================== +:mod:`models._fasttext_bin` -- Facebook's fastText I/O +====================================================== .. automodule:: gensim.models._fasttext_bin - :synopsis: Facebook I/O + :synopsis: I/O routines for Facebook's fastText format :members: :inherited-members: :special-members: __getitem__ diff --git a/docs/src/parsing/porter.rst b/docs/src/parsing/porter.rst index 4b8d68c5d8..7b715f7410 100644 --- a/docs/src/parsing/porter.rst +++ b/docs/src/parsing/porter.rst @@ -1,5 +1,5 @@ :mod:`parsing.porter` -- Porter Stemming Algorithm -========================================================= +================================================== .. automodule:: gensim.parsing.porter :synopsis: Porter Stemming Algorithm diff --git a/docs/src/similarities/annoy.rst b/docs/src/similarities/annoy.rst new file mode 100644 index 0000000000..114b4e588c --- /dev/null +++ b/docs/src/similarities/annoy.rst @@ -0,0 +1,8 @@ +:mod:`similarities.annoy` -- Approximate Vector Search using Annoy +================================================================== + +.. automodule:: gensim.similarities.annoy + :synopsis: Fast Approximate Nearest Neighbor Similarity with the Annoy package + :members: + :inherited-members: + diff --git a/docs/src/similarities/index.rst b/docs/src/similarities/index.rst deleted file mode 100644 index 169b26b740..0000000000 --- a/docs/src/similarities/index.rst +++ /dev/null @@ -1,8 +0,0 @@ -:mod:`similarities.index` -- Fast Approximate Nearest Neighbor Similarity with Annoy package -============================================================================================ - -.. automodule:: gensim.similarities.index - :synopsis: Fast Approximate Nearest Neighbor Similarity with Annoy package - :members: - :inherited-members: - diff --git a/docs/src/summarization/commons.rst b/docs/src/summarization/commons.rst index 7e859c8937..0e952cad9a 100644 --- a/docs/src/summarization/commons.rst +++ b/docs/src/summarization/commons.rst @@ -1,9 +1,9 @@ -:mod:`summarization.commons` -- Common graph functions -========================================================= +:mod:`summarization.commons` -- Graph functions used in TextRank summarization +============================================================================== .. automodule:: gensim.summarization.commons :synopsis: Common graph functions + :synopsis: Common graph functions used in TextRank summarization :members: :inherited-members: :undoc-members: - :show-inheritance: diff --git a/docs/src/summarization/graph.rst b/docs/src/summarization/graph.rst index eb3588077d..142f3eb491 100644 --- a/docs/src/summarization/graph.rst +++ b/docs/src/summarization/graph.rst @@ -1,9 +1,9 @@ -:mod:`summarization.graph` -- Graph -=================================== +:mod:`summarization.graph` -- Graph used in TextRank summarization +================================================================== .. automodule:: gensim.summarization.graph :synopsis: Graph + :synopsis: Graph utilities used in the TextRank summarization algorithm :members: :inherited-members: :undoc-members: - :show-inheritance: diff --git a/docs/src/summarization/summariser.rst b/docs/src/summarization/summariser.rst index 42d2967453..15c0fa08f0 100644 --- a/docs/src/summarization/summariser.rst +++ b/docs/src/summarization/summariser.rst @@ -1,8 +1,8 @@ -:mod:`summarization.summarizer` -- TextRank Summariser -========================================================= +:mod:`summarization.summarizer` -- TextRank Summarizer +====================================================== .. automodule:: gensim.summarization.summarizer - :synopsis: TextRank Summariser + :synopsis: TextRank Summarizer :members: :inherited-members: :undoc-members: diff --git a/docs/src/summarization/textcleaner.rst b/docs/src/summarization/textcleaner.rst index 72eda3d779..d667fd04f7 100644 --- a/docs/src/summarization/textcleaner.rst +++ b/docs/src/summarization/textcleaner.rst @@ -1,8 +1,8 @@ -:mod:`summarization.textcleaner` -- Summarization pre-processing -================================================================ +:mod:`summarization.textcleaner` -- Preprocessing for TextRank summarization +============================================================================ .. automodule:: gensim.summarization.textcleaner - :synopsis: Summarization pre-processing + :synopsis: Preprocessing used in the TextRank summarization :members: :inherited-members: :undoc-members: diff --git a/docs/src/test/utils.rst b/docs/src/test/utils.rst index c8c9bf1808..c3c09495fb 100644 --- a/docs/src/test/utils.rst +++ b/docs/src/test/utils.rst @@ -1,8 +1,8 @@ -:mod:`test.utils` -- Common utils -=========================================================== +:mod:`test.utils` -- Internal testing functions +=============================================== .. automodule:: gensim.test.utils - :synopsis: Common utils + :synopsis: Common utils used in testing Gensim internally :members: :inherited-members: :undoc-members: diff --git a/gensim/__init__.py b/gensim/__init__.py index 2490e90ca3..e2ce0959df 100644 --- a/gensim/__init__.py +++ b/gensim/__init__.py @@ -1,13 +1,15 @@ -"""This package contains interfaces and functionality to compute pair-wise document similarities within a corpus -of documents. +""" +This package contains functionality to transform documents (strings) into vectors, and calculate +similarities between documents. + """ -from gensim import parsing, corpora, matutils, interfaces, models, similarities, summarization, utils # noqa:F401 import logging -__version__ = '3.8.1' +from gensim import parsing, corpora, matutils, interfaces, models, similarities, summarization, utils # noqa:F401 +__version__ = '4.0.0.dev0' logger = logging.getLogger('gensim') -if len(logger.handlers) == 0: # To ensure reload() doesn't add another one +if not logger.handlers: # To ensure reload() doesn't add another one logger.addHandler(logging.NullHandler()) diff --git a/gensim/corpora/wikicorpus.py b/gensim/corpora/wikicorpus.py index 7214d6b2b0..ba371225ab 100644 --- a/gensim/corpora/wikicorpus.py +++ b/gensim/corpora/wikicorpus.py @@ -674,10 +674,11 @@ def get_texts(self): positions, positions_all = 0, 0 tokenization_params = (self.tokenizer_func, self.token_min_len, self.token_max_len, self.lower) - texts = \ - ((text, self.lemmatize, title, pageid, tokenization_params) - for title, text, pageid - in extract_pages(bz2.BZ2File(self.fname), self.filter_namespaces, self.filter_articles)) + texts = ( + (text, self.lemmatize, title, pageid, tokenization_params) + for title, text, pageid + in extract_pages(bz2.BZ2File(self.fname), self.filter_namespaces, self.filter_articles) + ) pool = multiprocessing.Pool(self.processes, init_to_ignore_interrupt) try: diff --git a/gensim/models/_fasttext_bin.py b/gensim/models/_fasttext_bin.py index 26337d51eb..5eeb4ca71a 100644 --- a/gensim/models/_fasttext_bin.py +++ b/gensim/models/_fasttext_bin.py @@ -1,4 +1,10 @@ +#!/usr/bin/env python # -*- coding: utf-8 -*- +# +# Authors: Michael Penkov +# Copyright (C) 2019 RaRe Technologies s.r.o. +# Licensed under the GNU LGPL v2.1 - http://www.gnu.org/licenses/lgpl.html + """Load models from the native binary format released by Facebook. The main entry point is the :func:`~gensim.models._fasttext_bin.load` function. diff --git a/gensim/models/doc2vec.py b/gensim/models/doc2vec.py index 1a55ad9b5f..bd7633db41 100644 --- a/gensim/models/doc2vec.py +++ b/gensim/models/doc2vec.py @@ -5,7 +5,11 @@ # Copyright (C) 2018 RaRe Technologies s.r.o. # Licensed under the GNU LGPL v2.1 - http://www.gnu.org/licenses/lgpl.html -"""Learn paragraph and document embeddings via the distributed memory and distributed bag of words models from +""" +Introduction +============ + +Learn paragraph and document embeddings via the distributed memory and distributed bag of words models from `Quoc Le and Tomas Mikolov: "Distributed Representations of Sentences and Documents" `_. @@ -63,25 +67,19 @@ import logging import os - -try: - from queue import Queue -except ImportError: - from Queue import Queue # noqa:F401 - from collections import namedtuple, defaultdict from collections.abc import Iterable from timeit import default_timer -from dataclasses import dataclass +from dataclasses import dataclass from numpy import zeros, float32 as REAL, vstack, integer, dtype import numpy as np +from six.moves import range +from six import string_types, integer_types, itervalues from gensim import utils, matutils # utility fnc for pickling, common scipy operations etc from gensim.utils import deprecated from gensim.models import Word2Vec -from six.moves import range -from six import string_types, integer_types, itervalues from gensim.models.keyedvectors import KeyedVectors, pseudorandom_weak_vector logger = logging.getLogger(__name__) diff --git a/gensim/models/fasttext.py b/gensim/models/fasttext.py index 5c07a0b540..8b8dfab407 100644 --- a/gensim/models/fasttext.py +++ b/gensim/models/fasttext.py @@ -5,13 +5,16 @@ # Copyright (C) 2018 RaRe Technologies s.r.o. # Licensed under the GNU LGPL v2.1 - http://www.gnu.org/licenses/lgpl.html -"""Learn word representations via Fasttext: `Enriching Word Vectors with Subword Information +""" +Introduction +------------ +Learn word representations via fastText: `Enriching Word Vectors with Subword Information `_. This module allows training word embeddings from a training corpus with the additional ability to obtain word vectors for out-of-vocabulary words. -This module contains a fast native C implementation of Fasttext with Python interfaces. It is **not** only a wrapper +This module contains a fast native C implementation of fastText with Python interfaces. It is **not** only a wrapper around Facebook's implementation. This module supports loading models trained with Facebook's fastText implementation. @@ -20,9 +23,6 @@ For a tutorial see `this notebook `_. -**Make sure you have a C compiler before installing Gensim, to use the optimized (compiled) Fasttext -training routines.** - Usage examples -------------- @@ -277,21 +277,15 @@ import logging import os +from collections.abc import Iterable import numpy as np from numpy import ones, vstack, float32 as REAL -import six -from collections.abc import Iterable import gensim.models._fasttext_bin from gensim.models.word2vec import Word2Vec from gensim.models.keyedvectors import KeyedVectors from gensim import utils -from gensim.utils import deprecated, call_on_class_only - - -logger = logging.getLogger(__name__) - try: from gensim.models.fasttext_inner import ( # noqa: F401 train_batch_any, @@ -305,6 +299,9 @@ raise utils.NO_CYTHON +logger = logging.getLogger(__name__) + + class FastText(Word2Vec): def __init__(self, sentences=None, corpus_file=None, sg=0, hs=0, vector_size=100, alpha=0.025, @@ -446,8 +443,8 @@ def __init__(self, sentences=None, corpus_file=None, sg=0, hs=0, vector_size=100 ways. Check the module level docstring for some examples. """ - self.load = call_on_class_only - self.load_fasttext_format = call_on_class_only + self.load = utils.call_on_class_only + self.load_fasttext_format = utils.call_on_class_only self.callbacks = callbacks if word_ngrams != 1: raise NotImplementedError("Gensim's FastText implementation does not yet support word_ngrams != 1.") @@ -776,7 +773,7 @@ def clear_sims(self): self._clear_post_train() @classmethod - @deprecated( + @utils.deprecated( 'use load_facebook_vectors (to use pretrained embeddings) or load_facebook_model ' '(to continue training with the loaded full model, more RAM) instead' ) @@ -789,7 +786,7 @@ def load_fasttext_format(cls, model_file, encoding='utf8'): """ return load_facebook_model(model_file, encoding=encoding) - @deprecated( + @utils.deprecated( 'use load_facebook_vectors (to use pretrained embeddings) or load_facebook_model ' '(to continue training with the loaded full model, more RAM) instead' ) @@ -803,7 +800,7 @@ def load_binary_data(self, encoding='utf8'): """ m = _load_fasttext_format(self.file_name, encoding=encoding) - for attr, val in six.iteritems(m.__dict__): + for attr, val in m.__dict__.items(): setattr(self, attr, val) def save(self, *args, **kwargs): @@ -1522,19 +1519,8 @@ def _unpack(m, num_rows, hash2index, seed=1, fill=None): _MB_START = 0x80 -def _byte_to_int_py3(b): - return b - - -def _byte_to_int_py2(b): - return ord(b) - - -_byte_to_int = _byte_to_int_py2 if six.PY2 else _byte_to_int_py3 - - def _is_utf8_continue(b): - return _byte_to_int(b) & _MB_MASK == _MB_START + return b & _MB_MASK == _MB_START def ft_ngram_hashes(word, minn, maxn, num_buckets): diff --git a/gensim/models/hdpmodel.py b/gensim/models/hdpmodel.py index 3682f94b39..d8d7185487 100755 --- a/gensim/models/hdpmodel.py +++ b/gensim/models/hdpmodel.py @@ -62,7 +62,6 @@ from gensim import interfaces, utils, matutils from gensim.matutils import dirichlet_expectation, mean_absolute_difference from gensim.models import basemodel, ldamodel - from gensim.utils import deprecated logger = logging.getLogger(__name__) diff --git a/gensim/models/ldamodel.py b/gensim/models/ldamodel.py index b3bd1a4963..c4a26e6967 100755 --- a/gensim/models/ldamodel.py +++ b/gensim/models/ldamodel.py @@ -560,11 +560,15 @@ def init_dir_prior(self, prior, name): if isinstance(prior, six.string_types): if prior == 'symmetric': logger.info("using symmetric %s at %s", name, 1.0 / self.num_topics) - init_prior = np.fromiter((1.0 / self.num_topics for i in range(prior_shape)), - dtype=self.dtype, count=prior_shape) + init_prior = np.fromiter( + (1.0 / self.num_topics for i in range(prior_shape)), + dtype=self.dtype, count=prior_shape, + ) elif prior == 'asymmetric': - init_prior = np.fromiter((1.0 / (i + np.sqrt(prior_shape)) for i in range(prior_shape)), - dtype=self.dtype, count=prior_shape) + init_prior = np.fromiter( + (1.0 / (i + np.sqrt(prior_shape)) for i in range(prior_shape)), + dtype=self.dtype, count=prior_shape, + ) init_prior /= init_prior.sum() logger.info("using asymmetric %s %s", name, list(init_prior)) elif prior == 'auto': diff --git a/gensim/models/word2vec.py b/gensim/models/word2vec.py index a6523babdf..fee4c0873a 100755 --- a/gensim/models/word2vec.py +++ b/gensim/models/word2vec.py @@ -5,7 +5,10 @@ # Copyright (C) 2018 RaRe Technologies s.r.o. # Licensed under the GNU LGPL v2.1 - http://www.gnu.org/licenses/lgpl.html -"""This module implements the word2vec family of algorithms, using highly optimized C routines, +""" +Introduction +============ +This module implements the word2vec family of algorithms, using highly optimized C routines, data streaming and Pythonic interfaces. The word2vec algorithms include skip-gram and CBOW models, using either diff --git a/gensim/parsing/porter.py b/gensim/parsing/porter.py index b70377855d..c579f44beb 100644 --- a/gensim/parsing/porter.py +++ b/gensim/parsing/porter.py @@ -7,8 +7,9 @@ Author - Vivake Gupta (v@nano.com), optimizations and cleanup of the code by Lars Buitinck. -Examples: ---------- +Examples +-------- + .. sourcecode:: pycon >>> from gensim.parsing.porter import PorterStemmer diff --git a/gensim/parsing/preprocessing.py b/gensim/parsing/preprocessing.py index 97acef1f22..777ca46e8e 100644 --- a/gensim/parsing/preprocessing.py +++ b/gensim/parsing/preprocessing.py @@ -3,36 +3,20 @@ # # Licensed under the GNU LGPL v2.1 - http://www.gnu.org/licenses/lgpl.html -"""This module contains methods for parsing and preprocessing strings. Let's consider the most noticeable: - -* :func:`~gensim.parsing.preprocessing.remove_stopwords` - remove all stopwords from string -* :func:`~gensim.parsing.preprocessing.preprocess_string` - preprocess string (in default NLP meaning) +"""This module contains methods for parsing and preprocessing strings. Examples ---------- +-------- + .. sourcecode:: pycon - >>> from gensim.parsing.preprocessing import remove_stopwords + >>> from gensim.parsing.preprocessing import remove_stopwords, preprocess_string >>> remove_stopwords("Better late than never, but better never late.") u'Better late never, better late.' >>> >>> preprocess_string("Hel 9lo Wo9 rld! Th3 weather_is really g00d today, isn't it?") [u'hel', u'rld', u'weather', u'todai', u'isn'] - -Data: ------ - -.. data:: STOPWORDS - Set of stopwords from Stone, Denis, Kwantes (2010). -.. data:: RE_PUNCT - Regexp for search an punctuation. -.. data:: RE_TAGS - Regexp for search an tags. -.. data:: RE_NUMERIC - Regexp for search an numbers. -.. data:: RE_NONALPHA - Regexp for search an non-alphabetic character. -.. data:: RE_AL_NUM - Regexp for search a position between letters and digits. -.. data:: RE_NUM_AL - Regexp for search a position between digits and letters . -.. data:: RE_WHITESPACE - Regexp for search space characters. -.. data:: DEFAULT_FILTERS - List of function for string preprocessing. - """ import re diff --git a/gensim/similarities/index.py b/gensim/similarities/annoy.py similarity index 66% rename from gensim/similarities/index.py rename to gensim/similarities/annoy.py index 392d000b4e..d9816e2336 100644 --- a/gensim/similarities/index.py +++ b/gensim/similarities/annoy.py @@ -5,36 +5,19 @@ # Licensed under the GNU LGPL v2.1 - http://www.gnu.org/licenses/lgpl.html """ -Intro ------ -This module contains integration Annoy with :class:`~gensim.models.word2vec.Word2Vec`, -:class:`~gensim.models.doc2vec.Doc2Vec`, :class:`~gensim.models.fasttext.FastText` and -:class:`~gensim.models.keyedvectors.KeyedVectors`. +This module integrates Spotify's `Annoy `_ (Approximate Nearest Neighbors Oh Yeah) +library with Gensim's :class:`~gensim.models.word2vec.Word2Vec`, :class:`~gensim.models.doc2vec.Doc2Vec`, +:class:`~gensim.models.fasttext.FastText` and :class:`~gensim.models.keyedvectors.KeyedVectors` word embeddings. .. Important:: - To use this module, you must have the ``annoy`` library install. + To use this module, you must have the ``annoy`` library installed. To install it, run ``pip install annoy``. +""" -What is Annoy -------------- -Annoy (Approximate Nearest Neighbors Oh Yeah) is a C++ library with Python bindings to search for points in space -that are close to a given query point. It also creates large read-only file-based data structures that are mmapped -into memory so that many processes may share the same data. - - -How it works ------------- -Using `random projections `_ -and by building up a tree. At every intermediate node in the tree, a random hyperplane is chosen, -which divides the space into two subspaces. This hyperplane is chosen by sampling two points from the subset -and taking the hyperplane equidistant from them. - -More information about Annoy: `github repository `_, -`author in twitter `_ -and `annoy-user maillist `_. +# Avoid import collisions on py2: this module has the same name as the actual Annoy library. +from __future__ import absolute_import -""" import os try: @@ -49,16 +32,14 @@ from gensim.models import KeyedVectors -_NOANNOY = ImportError( - "Annoy is not installed, if you wish to use the annoy " - "indexer, please run `pip install annoy`" -) +_NOANNOY = ImportError("Annoy not installed. To use the Annoy indexer, please run `pip install annoy`.") -class AnnoyIndexer(object): - """This class allows to use `Annoy `_ as indexer for `most_similar` method - from :class:`~gensim.models.word2vec.Word2Vec`, :class:`~gensim.models.doc2vec.Doc2Vec`, - :class:`~gensim.models.fasttext.FastText` and :class:`~gensim.models.keyedvectors.Word2VecKeyedVectors` classes. +class AnnoyIndexer(): + """This class allows the use of `Annoy `_ for fast (approximate) + vector retrieval in `most_similar()` calls of + :class:`~gensim.models.word2vec.Word2Vec`, :class:`~gensim.models.doc2vec.Doc2Vec`, + :class:`~gensim.models.fasttext.FastText` and :class:`~gensim.models.keyedvectors.Word2VecKeyedVectors` models. """ @@ -66,8 +47,8 @@ def __init__(self, model=None, num_trees=None): """ Parameters ---------- - model : :class:`~gensim.models.base_any2vec.BaseWordEmbeddingsModel`, optional - Model, that will be used as source for index. + model : trained model, optional + Use vectors from this model as the source for the index. num_trees : int, optional Number of trees for Annoy indexer. @@ -75,7 +56,7 @@ def __init__(self, model=None, num_trees=None): -------- .. sourcecode:: pycon - >>> from gensim.similarities.index import AnnoyIndexer + >>> from gensim.similarities.annoy import AnnoyIndexer >>> from gensim.models import Word2Vec >>> >>> sentences = [['cute', 'cat', 'say', 'meow'], ['cute', 'dog', 'say', 'woof']] @@ -102,7 +83,7 @@ def __init__(self, model=None, num_trees=None): raise ValueError("Only a Word2Vec, Doc2Vec, FastText or KeyedVectors instance can be used") def save(self, fname, protocol=2): - """Save AnnoyIndexer instance. + """Save AnnoyIndexer instance to disk. Parameters ---------- @@ -113,7 +94,7 @@ def save(self, fname, protocol=2): Notes ----- - This method save **only** index (**model isn't preserved**). + This method saves **only the index**. The trained model isn't preserved. """ fname_dict = fname + '.d' @@ -123,12 +104,12 @@ def save(self, fname, protocol=2): _pickle.dump(d, fout, protocol=protocol) def load(self, fname): - """Load AnnoyIndexer instance + """Load an AnnoyIndexer instance from disk. Parameters ---------- fname : str - Path to dump with AnnoyIndexer. + The path as previously used by ``save()``. Examples -------- @@ -153,38 +134,34 @@ def load(self, fname): fname_dict = fname + '.d' if not (os.path.exists(fname) and os.path.exists(fname_dict)): raise IOError( - "Can't find index files '%s' and '%s' - Unable to restore AnnoyIndexer state." % (fname, fname_dict) + "Can't find index files '%s' and '%s' - unable to restore AnnoyIndexer state." % (fname, fname_dict) ) - else: - try: - from annoy import AnnoyIndex - except ImportError: - raise _NOANNOY - - with utils.open(fname_dict, 'rb') as f: - d = _pickle.loads(f.read()) - self.num_trees = d['num_trees'] - self.index = AnnoyIndex(d['f']) - self.index.load(fname) - self.labels = d['labels'] + try: + from annoy import AnnoyIndex + except ImportError: + raise _NOANNOY + + with utils.open(fname_dict, 'rb') as f: + d = _pickle.loads(f.read()) + self.num_trees = d['num_trees'] + self.index = AnnoyIndex(d['f'], metric='angular') + self.index.load(fname) + self.labels = d['labels'] def build_from_word2vec(self): """Build an Annoy index using word vectors from a Word2Vec model.""" - self.model.init_sims() return self._build_from_model(self.model.wv.vectors_norm, self.model.wv.index2word, self.model.vector_size) def build_from_doc2vec(self): """Build an Annoy index using document vectors from a Doc2Vec model.""" - docvecs = self.model.docvecs docvecs.init_sims() - labels = [docvecs.index_to_doctag(i) for i in range(0, docvecs.count)] + labels = [docvecs.index_to_doctag(i) for i in range(docvecs.count)] return self._build_from_model(docvecs.vectors_docs_norm, labels, self.model.vector_size) def build_from_keyedvectors(self): """Build an Annoy index using word vectors from a KeyedVectors model.""" - self.model.init_sims() return self._build_from_model(self.model.vectors_norm, self.model.index2word, self.model.vector_size) @@ -194,7 +171,7 @@ def _build_from_model(self, vectors, labels, num_features): except ImportError: raise _NOANNOY - index = AnnoyIndex(num_features) + index = AnnoyIndex(num_features, metric='angular') for vector_num, vector in enumerate(vectors): index.add_item(vector_num, vector) @@ -204,7 +181,7 @@ def _build_from_model(self, vectors, labels, num_features): self.labels = labels def most_similar(self, vector, num_neighbors): - """Find the approximate `num_neighbors` most similar items. + """Find `num_neighbors` most similar items. Parameters ---------- @@ -219,7 +196,6 @@ def most_similar(self, vector, num_neighbors): List of most similar items in format [(`item`, `cosine_distance`), ... ] """ - ids, distances = self.index.get_nns_by_vector( vector, num_neighbors, include_distances=True) diff --git a/gensim/similarities/nmslib.py b/gensim/similarities/nmslib.py index 4fad9761a5..b0fc246214 100644 --- a/gensim/similarities/nmslib.py +++ b/gensim/similarities/nmslib.py @@ -5,15 +5,17 @@ # Licensed under the GNU LGPL v2.1 - http://www.gnu.org/licenses/lgpl.html """ -Intro ------ +This module integrates `NMSLIB `_ fast similarity +search with Gensim's :class:`~gensim.models.word2vec.Word2Vec`, :class:`~gensim.models.doc2vec.Doc2Vec`, +:class:`~gensim.models.fasttext.FastText` and :class:`~gensim.models.keyedvectors.KeyedVectors` +vector embeddings. -This module contains integration NMSLIB with :class:`~gensim.models.word2vec.Word2Vec`, -:class:`~gensim.models.doc2vec.Doc2Vec`, :class:`~gensim.models.fasttext.FastText` and -:class:`~gensim.models.keyedvectors.KeyedVectors`. -To use NMSLIB, instantiate a :class:`~gensim.similarities.nmslib.NmslibIndexer` class -and pass the instance as the indexer parameter to your model's most_similar method -(e.g. :py:func:`~gensim.models.doc2vec.most_similar`). +.. Important:: + To use this module, you must have the external ``nmslib`` library installed. + To install it, run ``pip install nmslib``. + +To use the integration, instantiate a :class:`~gensim.similarities.nmslib.NmslibIndexer` class +and pass the instance as the `indexer` parameter to your model's `model.most_similar()` method. Example usage ------------- @@ -24,11 +26,11 @@ >>> from gensim.models import Word2Vec >>> >>> sentences = [['cute', 'cat', 'say', 'meow'], ['cute', 'dog', 'say', 'woof']] - >>> model = Word2Vec(sentences, min_count=1, seed=1) + >>> model = Word2Vec(sentences, min_count=1, iter=10, seed=2) >>> >>> indexer = NmslibIndexer(model) - >>> model.most_similar("cat", topn=2, indexer=indexer) - [('cat', 1.0), ('meow', 0.5595494508743286)] + >>> model.wv.most_similar("cat", topn=2, indexer=indexer) + [('cat', 1.0), ('meow', 0.16398882865905762)] Load and save example --------------------- @@ -40,14 +42,14 @@ >>> from tempfile import mkstemp >>> >>> sentences = [['cute', 'cat', 'say', 'meow'], ['cute', 'dog', 'say', 'woof']] - >>> model = Word2Vec(sentences, min_count=1, seed=1, iter=10) + >>> model = Word2Vec(sentences, min_count=1, seed=2, iter=10) >>> >>> indexer = NmslibIndexer(model) >>> _, temp_fn = mkstemp() >>> indexer.save(temp_fn) >>> >>> new_indexer = NmslibIndexer.load(temp_fn) - >>> model.most_similar("cat", topn=2, indexer=new_indexer) + >>> model.wv.most_similar("cat", topn=2, indexer=new_indexer) [('cat', 1.0), ('meow', 0.5595494508743286)] What is NMSLIB @@ -60,35 +62,35 @@ Why use NMSIB? -------------- -The current implementation for finding k nearest neighbors in a vector space in gensim has linear complexity -via brute force in the number of indexed documents, although with extremely low constant factors. +Gensim's native :py:class:`~gensim.similarities.Similarity` for finding the `k` nearest neighbors to a vector +uses brute force and has linear complexity, albeit with extremely low constant factors. + The retrieved results are exact, which is an overkill in many applications: approximate results retrieved in sub-linear time may be enough. -NMSLIB can find approximate nearest neighbors much faster. -Compared to Annoy, NMSLIB has more parameters to control the build and query time and accuracy. -NMSLIB can achieve faster and more accurate nearest neighbors search than annoy. + +NMSLIB can find approximate nearest neighbors much faster, similar to Spotify's Annoy library. +Compared to :py:class:`~gensim.similarities.annoy.Annoy`, NMSLIB has more parameters to control the build and query time and accuracy. +NMSLIB often achieves faster and more accurate nearest neighbors search than Annoy. + """ +# Avoid import collisions on py2: this module has the same name as the actual NMSLIB library. +from __future__ import absolute_import +import pickle as _pickle + from smart_open import open try: - import cPickle as _pickle + import nmslib except ImportError: - import pickle as _pickle + raise ImportError("NMSLIB not installed. To use the NMSLIB indexer, please run `pip install nmslib`.") from gensim.models.doc2vec import Doc2Vec from gensim.models.word2vec import Word2Vec from gensim.models.fasttext import FastText from gensim.models import KeyedVectors -try: - import nmslib -except ImportError: - raise ImportError( - "NMSLIB not installed. To use the NMSLIB indexer, please run `pip install nmslib`." - ) - -class NmslibIndexer(object): +class NmslibIndexer(): """This class allows to use `NMSLIB `_ as indexer for `most_similar` method from :class:`~gensim.models.word2vec.Word2Vec`, :class:`~gensim.models.doc2vec.Doc2Vec`, :class:`~gensim.models.fasttext.FastText` and :class:`~gensim.models.keyedvectors.Word2VecKeyedVectors` classes. @@ -102,9 +104,13 @@ def __init__(self, model, index_params=None, query_time_params=None): model : :class:`~gensim.models.base_any2vec.BaseWordEmbeddingsModel` Model, that will be used as source for index. index_params : dict, optional - index_params for NMSLIB indexer. + Indexing parameters passed through to NMSLIB: + https://github.com/nmslib/nmslib/blob/master/manual/methods.md#graph-based-search-methods-sw-graph-and-hnsw + + If not specified, defaults to `{'M': 100, 'indexThreadQty': 1, 'efConstruction': 100, 'post': 0}`. query_time_params : dict, optional query_time_params for NMSLIB indexer. + If not specified, defaults to `{'efSearch': 100}`. """ if index_params is None: @@ -158,12 +164,12 @@ def save(self, fname, protocol=2): @classmethod def load(cls, fname): - """Load a NmslibIndexer instance from a file + """Load a NmslibIndexer instance from a file. Parameters ---------- fname : str - Path to dump with NmslibIndexer. + Path previously used in `save()`. """ fname_dict = fname + '.d' @@ -172,7 +178,7 @@ def load(cls, fname): index_params = d['index_params'] query_time_params = d['query_time_params'] nmslib_instance = cls(model=None, index_params=index_params, query_time_params=query_time_params) - index = nmslib.init() + index = nmslib.init(method='hnsw', space='cosinesimil') index.loadIndex(fname) nmslib_instance.index = index nmslib_instance.labels = d['labels'] @@ -196,7 +202,7 @@ def _build_from_keyedvectors(self): self._build_from_model(self.model.vectors_norm, self.model.index2word) def _build_from_model(self, vectors, labels): - index = nmslib.init() + index = nmslib.init(method='hnsw', space='cosinesimil') index.addDataPointBatch(vectors) index.createIndex(self.index_params, print_progress=True) @@ -211,16 +217,18 @@ def most_similar(self, vector, num_neighbors): Parameters ---------- vector : numpy.array - Vector for word/document. + Vector for a word or document. num_neighbors : int - Number of most similar items + How many most similar items to look for? Returns ------- list of (str, float) - List of most similar items in format [(`item`, `cosine_distance`), ... ] + List of most similar items in the format `[(item, cosine_similarity), ... ]`. """ ids, distances = self.index.knnQueryBatch(vector.reshape(1, -1), k=num_neighbors)[0] - return [(self.labels[ids[i]], 1 - distances[i] / 2) for i in range(len(ids))] + # NMSLIB returns cosine distance (not similarity), which is simply `dist = 1 - cossim`. + # So, convert back to similarities here. + return [(self.labels[id_], 1.0 - distance) for id_, distance in zip(ids, distances)] diff --git a/gensim/similarities/termsim.py b/gensim/similarities/termsim.py index 975d584660..c0e61e1490 100644 --- a/gensim/similarities/termsim.py +++ b/gensim/similarities/termsim.py @@ -23,7 +23,7 @@ class TermSimilarityIndex(SaveLoad): """ - Retrieves most similar terms for a given term. + Base class = common interface for retrieving the most similar terms for a given term. See Also -------- @@ -34,12 +34,12 @@ class TermSimilarityIndex(SaveLoad): def most_similar(self, term, topn=10): """Get most similar terms for a given term. - Return most similar terms for a given term along with the similarities. + Return the most similar terms for a given term along with their similarities. Parameters ---------- term : str - Tne term for which we are retrieving `topn` most similar terms. + The term for which we are retrieving `topn` most similar terms. topn : int, optional The maximum number of most similar terms to `term` that will be retrieved. diff --git a/gensim/sklearn_api/tfidf.py b/gensim/sklearn_api/tfidf.py index a918ec5528..8834a31298 100644 --- a/gensim/sklearn_api/tfidf.py +++ b/gensim/sklearn_api/tfidf.py @@ -4,7 +4,7 @@ # Copyright (C) 2011 Radim Rehurek # Licensed under the GNU LGPL v2.1 - http://www.gnu.org/licenses/lgpl.html -"""Scikit learn interface for :class:`~gensim.models.tfidfmodel.TfidfModel`. +"""Scikit-learn interface for :class:`~gensim.models.tfidfmodel.TfidfModel`. Follows scikit-learn API conventions to facilitate using gensim along with scikit-learn. @@ -30,7 +30,7 @@ class TfIdfTransformer(TransformerMixin, BaseEstimator): """Base TfIdf module, wraps :class:`~gensim.models.tfidfmodel.TfidfModel`. - For more information please have a look to `tf-idf `_. + For more information see `tf-idf `_. """ def __init__(self, id2word=None, dictionary=None, wlocal=gensim.utils.identity, @@ -114,12 +114,14 @@ def __init__(self, id2word=None, dictionary=None, wlocal=gensim.utils.identity, self.pivot = pivot def fit(self, X, y=None): - """Fit the model according to the given training data. + """Fit the model from the given training data. Parameters ---------- X : iterable of iterable of (int, int) Input corpus + y : None + Ignored. TF-IDF is an unsupervised model. Returns ------- @@ -130,22 +132,22 @@ def fit(self, X, y=None): self.gensim_model = TfidfModel( corpus=X, id2word=self.id2word, dictionary=self.dictionary, wlocal=self.wlocal, wglobal=self.wglobal, normalize=self.normalize, smartirs=self.smartirs, - pivot=self.pivot, slope=self.slope + pivot=self.pivot, slope=self.slope, ) return self def transform(self, docs): - """Get the tf-idf scores in BoW representation for `docs` + """Get the tf-idf scores for `docs` in a bag-of-words representation. Parameters ---------- - docs: {iterable of list of (int, number), list of (int, number)} - Document or corpus in BoW format. + docs: {iterable of list of (int, number)} + Document or corpus in bag-of-words format. Returns ------- iterable of list (int, float) 2-tuples. - The BOW representation of each document. Will have the same shape as `docs`. + The bag-of-words representation of each input document. """ if self.gensim_model is None: @@ -153,7 +155,7 @@ def transform(self, docs): "This model has not been fitted yet. Call 'fit' with appropriate arguments before using this method." ) - # input as python lists + # Is the input a single document? if isinstance(docs[0], tuple): - docs = [docs] + docs = [docs] # Yes => convert it to a corpus (of 1 document). return [self.gensim_model[doc] for doc in docs] diff --git a/gensim/summarization/bm25.py b/gensim/summarization/bm25.py index beabbf728c..7dd7867afb 100644 --- a/gensim/summarization/bm25.py +++ b/gensim/summarization/bm25.py @@ -13,7 +13,6 @@ .. [2] Okapi BM25 on Wikipedia, https://en.wikipedia.org/wiki/Okapi_BM25 - Examples -------- @@ -27,22 +26,13 @@ ... ] >>> result = get_bm25_weights(corpus, n_jobs=-1) - -Data: ------ -.. data:: PARAM_K1 - Free smoothing parameter for BM25. -.. data:: PARAM_B - Free smoothing parameter for BM25. -.. data:: EPSILON - Constant used for negative idf of document in corpus. - """ - import logging import math -from six import iteritems -from six.moves import range from functools import partial from multiprocessing import Pool + from ..utils import effective_n_jobs PARAM_K1 = 1.5 @@ -52,8 +42,8 @@ logger = logging.getLogger(__name__) -class BM25(object): - """Implementation of Best Matching 25 ranking function. +class BM25(): + """Implementation of the BM25 (Best Matching 25) ranking function. Attributes ---------- @@ -67,6 +57,7 @@ class BM25(object): Dictionary with inversed documents frequencies for whole `corpus`. Words used as keys and frequencies as values. doc_len : list of int List of document lengths. + """ def __init__(self, corpus, k1=PARAM_K1, b=PARAM_B, epsilon=EPSILON): diff --git a/gensim/summarization/keywords.py b/gensim/summarization/keywords.py index 2c85cf0bfe..d622480196 100644 --- a/gensim/summarization/keywords.py +++ b/gensim/summarization/keywords.py @@ -3,11 +3,10 @@ # # Licensed under the GNU LGPL v2.1 - http://www.gnu.org/licenses/lgpl.html -"""This module contains functions to find keywords of the text and building graph on tokens from text. +"""This module contains functions to find keywords within a text. Examples -------- -Extract keywords from text .. sourcecode:: pycon @@ -20,34 +19,24 @@ >>> keywords(text).split('\\n') [u'natural language', u'machine', u'frequently'] - -Notes ------ -Check tags in http://www.clips.ua.ac.be/pages/mbsp-tags and use only first two letters -for `INCLUDING_FILTER` and `EXCLUDING_FILTER` - -Data: ------ -.. data:: WINDOW_SIZE - Size of window, number of consecutive tokens in processing. -.. data:: INCLUDING_FILTER - Including part of speech filters. -.. data:: EXCLUDING_FILTER - Excluding part of speech filters. - """ +from itertools import combinations as _combinations +from queue import Queue + from gensim.summarization.pagerank_weighted import pagerank_weighted as _pagerank from gensim.summarization.textcleaner import clean_text_by_word as _clean_text_by_word from gensim.summarization.textcleaner import tokenize_by_word as _tokenize_by_word from gensim.summarization.commons import build_graph as _build_graph from gensim.summarization.commons import remove_unreachable_nodes as _remove_unreachable_nodes from gensim.utils import to_unicode -from itertools import combinations as _combinations -from six.moves.queue import Queue as _Queue -from six.moves import range -from six import iteritems +# Number of consecutive tokens in processing. WINDOW_SIZE = 2 +# POS tags from http://www.clips.ua.ac.be/pages/mbsp-tags +# Use only the first two letters here. INCLUDING_FILTER = ['NN', 'JJ'] EXCLUDING_FILTER = [] @@ -94,7 +83,7 @@ def _get_words_for_graph(tokens, pos_filter=None): raise ValueError("Can't use both include and exclude filters, should use only one") result = [] - for word, unit in iteritems(tokens): + for word, unit in tokens.items(): if exclude_filters and unit.tag in exclude_filters: continue if not include_filters or not unit.tag or unit.tag in include_filters: @@ -176,7 +165,7 @@ def _init_queue(split_text): Initialized queue. """ - queue = _Queue() + queue = Queue() first_window = _get_first_window(split_text) for word in first_window[1:]: queue.put(word) @@ -321,7 +310,7 @@ def _lemmas_to_words(tokens): """ lemma_to_word = {} - for word, unit in iteritems(tokens): + for word, unit in tokens.items(): lemma = unit.token if lemma in lemma_to_word: lemma_to_word[lemma].append(word) @@ -431,12 +420,12 @@ def _get_average_score(concept, _keywords): return total / word_counter -def _format_results(_keywords, combined_keywords, split, scores): - """Formats, sorts and returns `combined_keywords` in desired format. +def _format_results(keywords, combined_keywords, split, scores): + """Format, sort and return `combined_keywords`. Parameters ---------- - _keywords : dict + keywords : dict Keywords as keys and its scores as values. combined_keywords : list of str Most ranked words and/or its combinations. @@ -453,12 +442,12 @@ def _format_results(_keywords, combined_keywords, split, scores): result: list of str If `split`, keywords only **OR** result: str - Keywords, joined by endl. + Keywords, joined by newline character. """ - combined_keywords.sort(key=lambda w: _get_average_score(w, _keywords), reverse=True) + combined_keywords.sort(key=lambda w: _get_average_score(w, keywords), reverse=True) if scores: - return [(word, _get_average_score(word, _keywords)) for word in combined_keywords] + return [(word, _get_average_score(word, keywords)) for word in combined_keywords] if split: return combined_keywords return "\n".join(combined_keywords) @@ -466,7 +455,7 @@ def _format_results(_keywords, combined_keywords, split, scores): def keywords(text, ratio=0.2, words=None, split=False, scores=False, pos_filter=('NN', 'JJ'), lemmatize=False, deacc=True): - """Get most ranked words of provided text and/or its combinations. + """Get the most ranked words of provided text and/or its combinations. Parameters ---------- @@ -522,7 +511,7 @@ def keywords(text, ratio=0.2, words=None, split=False, scores=False, pos_filter= # The results can be polluted by many variations of the same word if lemmatize: lemmas_to_word = {} - for word, unit in iteritems(tokens): + for word, unit in tokens.items(): lemmas_to_word[unit.token] = [word] else: lemmas_to_word = _lemmas_to_words(tokens) diff --git a/gensim/summarization/summarizer.py b/gensim/summarization/summarizer.py index 73a2fba26f..d0a905dd5d 100644 --- a/gensim/summarization/summarizer.py +++ b/gensim/summarization/summarizer.py @@ -10,13 +10,6 @@ Variations of the Similarity Function of TextRank for Automated Summarization, https://arxiv.org/abs/1602.03606 - -Data ----- - -.. data:: INPUT_MIN_LENGTH - Minimal number of sentences in text -.. data:: WEIGHT_THRESHOLD - Minimal weight of edge between graph nodes. Smaller weights set to zero. - Example ------- @@ -53,6 +46,8 @@ """ import logging +from math import log10 as _log10 + from gensim.utils import deprecated from gensim.summarization.pagerank_weighted import pagerank_weighted as _pagerank from gensim.summarization.textcleaner import clean_text_by_sentences as _clean_text_by_sentences @@ -60,12 +55,11 @@ from gensim.summarization.commons import remove_unreachable_nodes as _remove_unreachable_nodes from gensim.summarization.bm25 import iter_bm25_bow as _bm25_weights from gensim.corpora import Dictionary -from math import log10 as _log10 -from six.moves import range - +# Minimum number of sentences in a text. Smaller texts will log a warning. INPUT_MIN_LENGTH = 10 +# Minimal weight of edge between graph nodes. Smaller weights set to zero. WEIGHT_THRESHOLD = 1.e-3 logger = logging.getLogger(__name__) diff --git a/gensim/summarization/textcleaner.py b/gensim/summarization/textcleaner.py index 64f7af4bda..e6f7069c80 100644 --- a/gensim/summarization/textcleaner.py +++ b/gensim/summarization/textcleaner.py @@ -6,26 +6,14 @@ """This module contains functions and processors used for processing text, extracting sentences from text, working with acronyms and abbreviations. -Data ----- - -.. data:: SEPARATOR - Special separator used in abbreviations. -.. data:: RE_SENTENCE - Pattern to split text to sentences. -.. data:: AB_SENIOR - Pattern for detecting abbreviations (example: Sgt. Pepper). -.. data:: AB_ACRONYM - Pattern for detecting acronyms. -.. data:: AB_ACRONYM_LETTERS - Pattern for detecting acronyms (example: P.S. I love you). -.. data:: UNDO_AB_SENIOR - Pattern like AB_SENIOR but with SEPARATOR between abbreviation and next word. -.. data:: UNDO_AB_ACRONYM - Pattern like AB_ACRONYM but with SEPARATOR between abbreviation and next word. - """ +import re +import logging from gensim.summarization.syntactic_unit import SyntacticUnit from gensim.parsing.preprocessing import preprocess_documents from gensim.utils import tokenize, has_pattern -from six.moves import range -import re -import logging logger = logging.getLogger(__name__) @@ -33,12 +21,25 @@ if HAS_PATTERN: from pattern.en import tag +# Special separator used in abbreviations. SEPARATOR = r'@' + +# Pattern to split text to sentences. RE_SENTENCE = re.compile(r'(\S.+?[.!?])(?=\s+|$)|(\S.+?)(?=[\n]|$)', re.UNICODE) + +# Pattern for detecting abbreviations (example: Sgt. Pepper). AB_SENIOR = re.compile(r'([A-Z][a-z]{1,2}\.)\s(\w)', re.UNICODE) + +# Pattern for detecting acronyms. AB_ACRONYM = re.compile(r'(\.[a-zA-Z]\.)\s(\w)', re.UNICODE) + +# Pattern for detecting acronyms (example: P.S. I love you). AB_ACRONYM_LETTERS = re.compile(r'([a-zA-Z])\.([a-zA-Z])\.', re.UNICODE) + +# Like AB_SENIOR but with SEPARATOR between abbreviation and next word. UNDO_AB_SENIOR = re.compile(r'([A-Z][a-z]{1,2}\.)' + SEPARATOR + r'(\w)', re.UNICODE) + +# Like AB_ACRONYM but with SEPARATOR between abbreviation and next word. UNDO_AB_ACRONYM = re.compile(r'(\.[a-zA-Z]\.)' + SEPARATOR + r'(\w)', re.UNICODE) diff --git a/gensim/test/test_corpora_dictionary.py b/gensim/test/test_corpora_dictionary.py index 1791e96bb5..d911e4052d 100644 --- a/gensim/test/test_corpora_dictionary.py +++ b/gensim/test/test_corpora_dictionary.py @@ -20,8 +20,6 @@ from gensim.corpora import Dictionary from gensim.utils import to_utf8 from gensim.test.utils import get_tmpfile, common_texts -from six import PY3 -from six.moves import zip class TestDictionary(unittest.TestCase): @@ -338,12 +336,6 @@ def test_dict_interface(self): self.assertEqual(list(d.keys()), list(d.iterkeys())) self.assertEqual(list(d.values()), list(d.itervalues())) - # XXX Do we want list results from the dict members in Py3 too? - if not PY3: - self.assertTrue(isinstance(d.items(), list)) - self.assertTrue(isinstance(d.keys(), list)) - self.assertTrue(isinstance(d.values(), list)) - def test_patch_with_special_tokens(self): special_tokens = {'pad': 0, 'space': 1, 'quake': 3} corpus = [["máma", "mele", "maso"], ["ema", "má", "máma"]] diff --git a/gensim/test/test_fasttext.py b/gensim/test/test_fasttext.py index c8c9b0582c..9ace152858 100644 --- a/gensim/test/test_fasttext.py +++ b/gensim/test/test_fasttext.py @@ -1,5 +1,6 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- + from __future__ import division import gzip @@ -10,7 +11,6 @@ import subprocess import struct import sys -import six import numpy as np @@ -1146,9 +1146,6 @@ def test_out_of_vocab(self): def hash_main(alg): """Generate hash values for test from standard input.""" - - assert six.PY3, 'this only works under Py3' - hashmap = { 'cy_bytes': ft_hash_bytes, } @@ -1210,7 +1207,6 @@ def ngram_main(): minn = int(sys.argv[2]) maxn = int(sys.argv[3]) - assert six.PY3, 'this only works under Py3' assert minn <= maxn, 'expected sane command-line parameters' hashmap = { diff --git a/gensim/test/test_keyedvectors.py b/gensim/test/test_keyedvectors.py index f3e9329f75..b998ffe308 100644 --- a/gensim/test/test_keyedvectors.py +++ b/gensim/test/test_keyedvectors.py @@ -303,9 +303,7 @@ def test(self): def save_dict_to_word2vec_formated_file(fname, word2vec_dict): - - with gensim.utils.open(fname, "bw") as f: - + with gensim.utils.open(fname, "wb") as f: num_words = len(word2vec_dict) vector_length = len(list(word2vec_dict.values())[0]) diff --git a/gensim/test/test_similarities.py b/gensim/test/test_similarities.py index 3556438655..0b4ca72cab 100644 --- a/gensim/test/test_similarities.py +++ b/gensim/test/test_similarities.py @@ -8,7 +8,6 @@ Automated tests for similarity algorithms (the similarities package). """ - import logging import unittest import math @@ -25,8 +24,10 @@ from gensim.models import TfidfModel from gensim import matutils, similarities from gensim.models import Word2Vec, FastText -from gensim.test.utils import (datapath, get_tmpfile, - common_texts as texts, common_dictionary as dictionary, common_corpus as corpus) +from gensim.test.utils import ( + datapath, get_tmpfile, + common_texts as TEXTS, common_dictionary as DICTIONARY, common_corpus as CORPUS, +) from gensim.similarities import UniformTermSimilarityIndex from gensim.similarities import WordEmbeddingSimilarityIndex from gensim.similarities import SparseTermSimilarityMatrix @@ -40,23 +41,24 @@ except (ImportError, ValueError): PYEMD_EXT = False -sentences = [doc2vec.TaggedDocument(words, [i]) for i, words in enumerate(texts)] +SENTENCES = [doc2vec.TaggedDocument(words, [i]) for i, words in enumerate(TEXTS)] -class _TestSimilarityABC(object): +@unittest.skip("skipping abstract base class") +class _TestSimilarityABC(unittest.TestCase): """ Base class for SparseMatrixSimilarity and MatrixSimilarity unit tests. """ def factoryMethod(self): """Creates a SimilarityABC instance.""" - return self.cls(corpus, num_features=len(dictionary)) + return self.cls(CORPUS, num_features=len(DICTIONARY)) def testFull(self, num_best=None, shardsize=100): if self.cls == similarities.Similarity: - index = self.cls(None, corpus, num_features=len(dictionary), shardsize=shardsize) + index = self.cls(None, CORPUS, num_features=len(DICTIONARY), shardsize=shardsize) else: - index = self.cls(corpus, num_features=len(dictionary)) + index = self.cls(CORPUS, num_features=len(DICTIONARY)) if isinstance(index, similarities.MatrixSimilarity): expected = numpy.array([ [0.57735026, 0.57735026, 0.57735026, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], @@ -72,7 +74,7 @@ def testFull(self, num_best=None, shardsize=100): # HACK: dictionary can be in different order, so compare in sorted order self.assertTrue(numpy.allclose(sorted(expected.flat), sorted(index.index.flat))) index.num_best = num_best - query = corpus[0] + query = CORPUS[0] sims = index[query] expected = [(0, 0.99999994), (2, 0.28867513), (3, 0.23570226), (1, 0.23570226)][: num_best] @@ -129,10 +131,10 @@ def testEmptyQuery(self): def testChunking(self): if self.cls == similarities.Similarity: - index = self.cls(None, corpus, num_features=len(dictionary), shardsize=5) + index = self.cls(None, CORPUS, num_features=len(DICTIONARY), shardsize=5) else: - index = self.cls(corpus, num_features=len(dictionary)) - query = corpus[:3] + index = self.cls(CORPUS, num_features=len(DICTIONARY)) + query = CORPUS[:3] sims = index[query] expected = numpy.array([ [0.99999994, 0.23570226, 0.28867513, 0.23570226, 0.0, 0.0, 0.0, 0.0, 0.0], @@ -155,9 +157,9 @@ def testChunking(self): def testIter(self): if self.cls == similarities.Similarity: - index = self.cls(None, corpus, num_features=len(dictionary), shardsize=5) + index = self.cls(None, CORPUS, num_features=len(DICTIONARY), shardsize=5) else: - index = self.cls(corpus, num_features=len(dictionary)) + index = self.cls(CORPUS, num_features=len(DICTIONARY)) sims = [sim for sim in index] expected = numpy.array([ [0.99999994, 0.23570226, 0.28867513, 0.23570226, 0.0, 0.0, 0.0, 0.0, 0.0], @@ -294,27 +296,27 @@ def testMmapCompressed(self): self.assertRaises(IOError, self.cls.load, fname, mmap='r') -class TestMatrixSimilarity(unittest.TestCase, _TestSimilarityABC): +class TestMatrixSimilarity(_TestSimilarityABC): def setUp(self): self.cls = similarities.MatrixSimilarity -class TestWmdSimilarity(unittest.TestCase, _TestSimilarityABC): +class TestWmdSimilarity(_TestSimilarityABC): def setUp(self): self.cls = similarities.WmdSimilarity - self.w2v_model = Word2Vec(texts, min_count=1).wv + self.w2v_model = Word2Vec(TEXTS, min_count=1).wv def factoryMethod(self): # Override factoryMethod. - return self.cls(texts, self.w2v_model) + return self.cls(TEXTS, self.w2v_model) @unittest.skipIf(PYEMD_EXT is False, "pyemd not installed") def testFull(self, num_best=None): # Override testFull. - index = self.cls(texts, self.w2v_model) + index = self.cls(TEXTS, self.w2v_model) index.num_best = num_best - query = texts[0] + query = TEXTS[0] sims = index[query] if num_best is not None: @@ -334,8 +336,8 @@ def testNonIncreasing(self): # NOTE: this could be implemented for other similarities as well (i.e. # in _TestSimilarityABC). - index = self.cls(texts, self.w2v_model, num_best=3) - query = texts[0] + index = self.cls(TEXTS, self.w2v_model, num_best=3) + query = TEXTS[0] sims = index[query] sims2 = numpy.asarray(sims)[:, 1] # Just the similarities themselves. @@ -347,8 +349,8 @@ def testNonIncreasing(self): def testChunking(self): # Override testChunking. - index = self.cls(texts, self.w2v_model) - query = texts[:3] + index = self.cls(TEXTS, self.w2v_model) + query = TEXTS[:3] sims = index[query] for i in range(3): @@ -366,31 +368,28 @@ def testChunking(self): def testIter(self): # Override testIter. - index = self.cls(texts, self.w2v_model) + index = self.cls(TEXTS, self.w2v_model) for sims in index: self.assertTrue(numpy.alltrue(sims >= 0.0)) self.assertTrue(numpy.alltrue(sims <= 1.0)) -class TestSoftCosineSimilarity(unittest.TestCase, _TestSimilarityABC): +class TestSoftCosineSimilarity(_TestSimilarityABC): def setUp(self): self.cls = similarities.SoftCosineSimilarity - self.tfidf = TfidfModel(dictionary=dictionary) + self.tfidf = TfidfModel(dictionary=DICTIONARY) similarity_matrix = scipy.sparse.identity(12, format="lil") - similarity_matrix[dictionary.token2id["user"], dictionary.token2id["human"]] = 0.5 - similarity_matrix[dictionary.token2id["human"], dictionary.token2id["user"]] = 0.5 + similarity_matrix[DICTIONARY.token2id["user"], DICTIONARY.token2id["human"]] = 0.5 + similarity_matrix[DICTIONARY.token2id["human"], DICTIONARY.token2id["user"]] = 0.5 self.similarity_matrix = SparseTermSimilarityMatrix(similarity_matrix) def factoryMethod(self): - # Override factoryMethod. - return self.cls(corpus, self.similarity_matrix) + return self.cls(CORPUS, self.similarity_matrix) def testFull(self, num_best=None): - # Override testFull. - # Single query - index = self.cls(corpus, self.similarity_matrix, num_best=num_best) - query = dictionary.doc2bow(texts[0]) + index = self.cls(CORPUS, self.similarity_matrix, num_best=num_best) + query = DICTIONARY.doc2bow(TEXTS[0]) sims = index[query] if num_best is not None: # Sparse array. @@ -404,8 +403,8 @@ def testFull(self, num_best=None): # Corpora for query in ( - corpus, # Basic text corpus. - self.tfidf[corpus]): # Transformed corpus without slicing support. + CORPUS, # Basic text corpus. + self.tfidf[CORPUS]): # Transformed corpus without slicing support. index = self.cls(query, self.similarity_matrix, num_best=num_best) sims = index[query] if num_best is not None: @@ -426,8 +425,8 @@ def testNonIncreasing(self): """ Check that similarities are non-increasing when `num_best` is not `None`.""" # NOTE: this could be implemented for other similarities as well (i.e. in _TestSimilarityABC). - index = self.cls(corpus, self.similarity_matrix, num_best=5) - query = dictionary.doc2bow(texts[0]) + index = self.cls(CORPUS, self.similarity_matrix, num_best=5) + query = DICTIONARY.doc2bow(TEXTS[0]) sims = index[query] sims2 = numpy.asarray(sims)[:, 1] # Just the similarities themselves. @@ -436,10 +435,8 @@ def testNonIncreasing(self): self.assertTrue(cond) def testChunking(self): - # Override testChunking. - - index = self.cls(corpus, self.similarity_matrix) - query = [dictionary.doc2bow(document) for document in texts[:3]] + index = self.cls(CORPUS, self.similarity_matrix) + query = [DICTIONARY.doc2bow(document) for document in TEXTS[:3]] sims = index[query] for i in range(3): @@ -455,27 +452,25 @@ def testChunking(self): self.assertAlmostEqual(expected, chunk[0][1], places=2) def testIter(self): - # Override testIter. - - index = self.cls(corpus, self.similarity_matrix) + index = self.cls(CORPUS, self.similarity_matrix) for sims in index: self.assertTrue(numpy.alltrue(sims >= 0.0)) self.assertTrue(numpy.alltrue(sims <= 1.0)) -class TestSparseMatrixSimilarity(unittest.TestCase, _TestSimilarityABC): +class TestSparseMatrixSimilarity(_TestSimilarityABC): def setUp(self): self.cls = similarities.SparseMatrixSimilarity def testMaintainSparsity(self): """Sparsity is correctly maintained when maintain_sparsity=True""" - num_features = len(dictionary) + num_features = len(DICTIONARY) - index = self.cls(corpus, num_features=num_features) - dense_sims = index[corpus] + index = self.cls(CORPUS, num_features=num_features) + dense_sims = index[CORPUS] - index = self.cls(corpus, num_features=num_features, maintain_sparsity=True) - sparse_sims = index[corpus] + index = self.cls(CORPUS, num_features=num_features, maintain_sparsity=True) + sparse_sims = index[CORPUS] self.assertFalse(scipy.sparse.issparse(dense_sims)) self.assertTrue(scipy.sparse.issparse(sparse_sims)) @@ -483,26 +478,26 @@ def testMaintainSparsity(self): def testMaintainSparsityWithNumBest(self): """Tests that sparsity is correctly maintained when maintain_sparsity=True and num_best is not None""" - num_features = len(dictionary) + num_features = len(DICTIONARY) - index = self.cls(corpus, num_features=num_features, maintain_sparsity=False, num_best=3) - dense_topn_sims = index[corpus] + index = self.cls(CORPUS, num_features=num_features, maintain_sparsity=False, num_best=3) + dense_topn_sims = index[CORPUS] - index = self.cls(corpus, num_features=num_features, maintain_sparsity=True, num_best=3) - scipy_topn_sims = index[corpus] + index = self.cls(CORPUS, num_features=num_features, maintain_sparsity=True, num_best=3) + scipy_topn_sims = index[CORPUS] self.assertFalse(scipy.sparse.issparse(dense_topn_sims)) self.assertTrue(scipy.sparse.issparse(scipy_topn_sims)) self.assertEqual(dense_topn_sims, [matutils.scipy2sparse(v) for v in scipy_topn_sims]) -class TestSimilarity(unittest.TestCase, _TestSimilarityABC): +class TestSimilarity(_TestSimilarityABC): def setUp(self): self.cls = similarities.Similarity def factoryMethod(self): # Override factoryMethod. - return self.cls(None, corpus, num_features=len(dictionary), shardsize=5) + return self.cls(None, CORPUS, num_features=len(DICTIONARY), shardsize=5) def testSharding(self): for num_best in [None, 0, 1, 9, 1000]: @@ -511,10 +506,10 @@ def testSharding(self): def testReopen(self): """test re-opening partially full shards""" - index = similarities.Similarity(None, corpus[:5], num_features=len(dictionary), shardsize=9) - _ = index[corpus[0]] # noqa:F841 forces shard close - index.add_documents(corpus[5:]) - query = corpus[0] + index = similarities.Similarity(None, CORPUS[:5], num_features=len(DICTIONARY), shardsize=9) + _ = index[CORPUS[0]] # noqa:F841 forces shard close + index.add_documents(CORPUS[5:]) + query = CORPUS[0] sims = index[query] expected = [(0, 0.99999994), (2, 0.28867513), (3, 0.23570226), (1, 0.23570226)] expected = matutils.sparse2full(expected, len(index)) @@ -527,7 +522,7 @@ def testMmapCompressed(self): # to be mmaped! def testChunksize(self): - index = self.cls(None, corpus, num_features=len(dictionary), shardsize=5) + index = self.cls(None, CORPUS, num_features=len(DICTIONARY), shardsize=5) expected = [sim for sim in index] index.chunksize = len(index) - 1 sims = [sim for sim in index] @@ -548,11 +543,11 @@ def setUp(self): except ImportError as e: raise unittest.SkipTest("Annoy library is not available: %s" % e) - from gensim.similarities.index import AnnoyIndexer + from gensim.similarities.annoy import AnnoyIndexer self.indexer = AnnoyIndexer def testWord2Vec(self): - model = word2vec.Word2Vec(texts, min_count=1) + model = word2vec.Word2Vec(TEXTS, min_count=1) index = self.indexer(model, 10) self.assertVectorIsSimilarToItself(model.wv, index) @@ -579,7 +574,7 @@ def __iter__(self): self.assertLoadedIndexEqual(index, model) def testAnnoyIndexingOfKeyedVectors(self): - from gensim.similarities.index import AnnoyIndexer + from gensim.similarities.annoy import AnnoyIndexer keyVectors_file = datapath('lee_fasttext.vec') model = KeyedVectors.load_word2vec_format(keyVectors_file) index = AnnoyIndexer(model, 10) @@ -589,7 +584,7 @@ def testAnnoyIndexingOfKeyedVectors(self): self.assertApproxNeighborsMatchExact(model, model, index) def testLoadMissingRaisesError(self): - from gensim.similarities.index import AnnoyIndexer + from gensim.similarities.annoy import AnnoyIndexer test_index = AnnoyIndexer() self.assertRaises(IOError, test_index.load, fname='test-index') @@ -628,7 +623,7 @@ def assertIndexSaved(self, index): self.assertTrue(os.path.exists(fname + '.d')) def assertLoadedIndexEqual(self, index, model): - from gensim.similarities.index import AnnoyIndexer + from gensim.similarities.annoy import AnnoyIndexer fname = get_tmpfile('gensim_similarities.tst.pkl') index.save(fname) @@ -650,9 +645,9 @@ def setUp(self): except ImportError as e: raise unittest.SkipTest("Annoy library is not available: %s" % e) - from gensim.similarities.index import AnnoyIndexer + from gensim.similarities.annoy import AnnoyIndexer - self.model = doc2vec.Doc2Vec(sentences, min_count=1) + self.model = doc2vec.Doc2Vec(SENTENCES, min_count=1) self.index = AnnoyIndexer(self.model, 300) self.vector = self.model.dv.vectors_norm[0] @@ -680,13 +675,13 @@ def testSave(self): self.assertTrue(os.path.exists(fname + '.d')) def testLoadNotExist(self): - from gensim.similarities.index import AnnoyIndexer + from gensim.similarities.annoy import AnnoyIndexer self.test_index = AnnoyIndexer() self.assertRaises(IOError, self.test_index.load, fname='test-index') def testSaveLoad(self): - from gensim.similarities.index import AnnoyIndexer + from gensim.similarities.annoy import AnnoyIndexer fname = get_tmpfile('gensim_similarities.tst.pkl') self.index.save(fname) @@ -712,7 +707,7 @@ def setUp(self): self.indexer = NmslibIndexer def test_word2vec(self): - model = word2vec.Word2Vec(texts, min_count=1) + model = word2vec.Word2Vec(TEXTS, min_count=1) index = self.indexer(model) self.assertVectorIsSimilarToItself(model.wv, index) @@ -764,10 +759,10 @@ def assertVectorIsSimilarToItself(self, wv, index): def assertApproxNeighborsMatchExact(self, model, wv, index): vector = wv.vectors_norm[0] approx_neighbors = model.most_similar([vector], topn=5, indexer=index) - exact_neighbors = model.most_similar(positive=[vector], topn=5) + exact_neighbors = model.wv.most_similar([vector], topn=5) - approx_words = [neighbor[0] for neighbor in approx_neighbors] - exact_words = [neighbor[0] for neighbor in exact_neighbors] + approx_words = [word_id for word_id, similarity in approx_neighbors] + exact_words = [word_id for word_id, similarity in exact_neighbors] self.assertEqual(approx_words, exact_words) @@ -801,7 +796,7 @@ def setUp(self): from gensim.similarities.nmslib import NmslibIndexer - self.model = doc2vec.Doc2Vec(sentences, min_count=1) + self.model = doc2vec.Doc2Vec(SENTENCES, min_count=1) self.index = NmslibIndexer(self.model) self.vector = self.model.dv.vectors_norm[0] @@ -814,13 +809,12 @@ def test_document_is_similar_to_itself(self): def test_approx_neighbors_match_exact(self): approx_neighbors = self.model.dv.most_similar([self.vector], topn=5, indexer=self.index) - exact_neighbors = self.model.dv.most_similar( - positive=[self.vector], topn=5) + exact_neighbors = self.model.dv.most_similar([self.vector], topn=5) - approx_words = [neighbor[0] for neighbor in approx_neighbors] - exact_words = [neighbor[0] for neighbor in exact_neighbors] + approx_tags = [tag for tag, similarity in approx_neighbors] + exact_tags = [tag for tag, similarity in exact_neighbors] - self.assertEqual(approx_words, exact_words) + self.assertEqual(approx_tags, exact_tags) def test_save(self): fname = get_tmpfile('gensim_similarities.tst.pkl') @@ -1228,7 +1222,7 @@ def test_most_similar(self): # check proper integration with SparseTermSimilarityMatrix index = LevenshteinSimilarityIndex(self.dictionary, alpha=1.0, beta=1.0) - similarity_matrix = SparseTermSimilarityMatrix(index, dictionary) + similarity_matrix = SparseTermSimilarityMatrix(index, DICTIONARY) self.assertTrue(scipy.sparse.issparse(similarity_matrix.matrix)) diff --git a/gensim/test/utils.py b/gensim/test/utils.py index ffc402c13d..158c0989b8 100644 --- a/gensim/test/utils.py +++ b/gensim/test/utils.py @@ -4,7 +4,7 @@ """Module contains common utilities used in automated code tests for Gensim modules. Attributes: ------------ + module_path : str Full path to this module directory. @@ -19,7 +19,7 @@ Examples: ---------- + It's easy to keep objects in temporary folder and reuse'em if needed: .. sourcecode:: pycon diff --git a/setup.py b/setup.py index abd19aa2c7..36918726d1 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ import distutils.cmd import distutils.log import itertools -import os.path +import os import platform import shutil import sys @@ -352,7 +352,7 @@ def run(self): setup( name='gensim', - version='3.8.1', + version='4.0.0.dev0', description='Python framework for fast Vector Space Modelling', long_description=LONG_DESCRIPTION, From a81e5472c7d6fe7348194ed5d4de1c98be82c5c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20=C5=98eh=C5=AF=C5=99ek?= Date: Sun, 26 Jul 2020 22:35:25 +0200 Subject: [PATCH 08/32] migrating + regenerating changed docs --- .../sphx_glr_run_similarity_queries_001.png | Bin 74624 -> 73333 bytes .../sphx_glr_run_similarity_queries_thumb.png | Bin 62888 -> 64358 bytes .../core/run_similarity_queries.py.md5 | 2 +- .../core/run_similarity_queries.rst | 35 +-- .../auto_examples/core/sg_execution_times.rst | 15 +- docs/src/auto_examples/index.rst | 29 ++- .../images/sphx_glr_run_annoy_001.png | Bin 44252 -> 44608 bytes .../images/thumb/sphx_glr_run_annoy_thumb.png | Bin 14399 -> 14666 bytes .../auto_examples/tutorials/run_annoy.ipynb | 30 +-- docs/src/auto_examples/tutorials/run_annoy.py | 117 +++++----- .../auto_examples/tutorials/run_annoy.py.md5 | 2 +- .../src/auto_examples/tutorials/run_annoy.rst | 216 ++++++++++-------- .../tutorials/sg_execution_times.rst | 6 +- docs/src/conf.py | 6 +- docs/src/corpora/_mmreader.rst | 4 +- docs/src/gallery/tutorials/run_annoy.py | 6 +- docs/src/similarities/nmslib.rst | 8 + docs/src/summarization/commons.rst | 1 - docs/src/summarization/graph.rst | 1 - gensim/corpora/_mmreader.pyx | 4 +- gensim/corpora/mmcorpus.py | 2 +- gensim/models/word2vec.py | 17 ++ 22 files changed, 273 insertions(+), 228 deletions(-) create mode 100644 docs/src/similarities/nmslib.rst diff --git a/docs/src/auto_examples/core/images/sphx_glr_run_similarity_queries_001.png b/docs/src/auto_examples/core/images/sphx_glr_run_similarity_queries_001.png index 44b23e348147c2168b300aa0f17ee3808a9d2475..807a84c4deae16b6bbd75f8e8632fc1be32eed6a 100644 GIT binary patch literal 73333 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 literal 74624 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�y9p{ZlS>5W5c0T{ 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 D_9Ev0 diff --git a/docs/src/auto_examples/core/images/thumb/sphx_glr_run_similarity_queries_thumb.png b/docs/src/auto_examples/core/images/thumb/sphx_glr_run_similarity_queries_thumb.png index d4949c853c84d63dd663821e1ecde07f77206be1..5a8e5643266e7a20f844aabc7abc37ae3965d34e 100644 GIT binary patch literal 64358 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 literal 62888 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 QvUk8sURqhIR>CCse;;rL;{X5v diff --git a/docs/src/auto_examples/core/run_similarity_queries.py.md5 b/docs/src/auto_examples/core/run_similarity_queries.py.md5 index 044a682b37..8b64ef4c08 100644 --- a/docs/src/auto_examples/core/run_similarity_queries.py.md5 +++ b/docs/src/auto_examples/core/run_similarity_queries.py.md5 @@ -1 +1 @@ -a3eaf7347874a32d1d25a455753206dc \ No newline at end of file +54804120deb345715247f0eed42b5e0e \ No newline at end of file diff --git a/docs/src/auto_examples/core/run_similarity_queries.rst b/docs/src/auto_examples/core/run_similarity_queries.rst index 1dd4624834..01e2e8ddb1 100644 --- a/docs/src/auto_examples/core/run_similarity_queries.rst +++ b/docs/src/auto_examples/core/run_similarity_queries.rst @@ -1,12 +1,10 @@ -.. only:: html - - .. note:: - :class: sphx-glr-download-link-note +.. note:: + :class: sphx-glr-download-link-note - Click :ref:`here ` to download the full example code - .. rst-class:: sphx-glr-example-title + Click :ref:`here ` to download the full example code +.. rst-class:: sphx-glr-example-title - .. _sphx_glr_auto_examples_core_run_similarity_queries.py: +.. _sphx_glr_auto_examples_core_run_similarity_queries.py: Similarity Queries @@ -27,7 +25,6 @@ Demonstrates querying a corpus for similar documents. - Creating the Corpus ------------------- @@ -81,7 +78,6 @@ if you completed it, feel free to skip to the next section. - Similarity interface -------------------- @@ -115,7 +111,6 @@ LSI space: - For the purposes of this tutorial, there are only two things you need to know about LSI. First, it's just another transformation: it transforms vectors from one space to another. Second, the benefit of LSI is that enables identifying patterns and relationships between terms (in our case, words in a document) and topics. @@ -147,8 +142,7 @@ no random-walk static ranks, just a semantic extension over the boolean keyword .. code-block:: none - [(0, 0.4618210045327162), (1, -0.07002766527900038)] - + [(0, 0.46182100453271613), (1, 0.07002766527900031)] @@ -179,7 +173,6 @@ might also be indexing a different corpus altogether. - .. warning:: The class :class:`similarities.MatrixSimilarity` is only appropriate when the whole set of vectors fits into memory. For example, a corpus of one million documents @@ -205,7 +198,6 @@ Index persistency is handled via the standard :func:`save` and :func:`load` func - This is true for all similarity indexing classes (:class:`similarities.Similarity`, :class:`similarities.MatrixSimilarity` and :class:`similarities.SparseMatrixSimilarity`). Also in the following, `index` can be an object of any of these. When in doubt, @@ -238,7 +230,6 @@ To obtain similarities of our query document against the nine indexed documents: - Cosine measure returns similarities in the range `<-1, 1>` (the greater, the more similar), so that the first document has a score of 0.99809301 etc. @@ -275,7 +266,6 @@ order, and obtain the final answer to the query `"Human computer interaction"`: - The thing to note here is that documents no. 2 (``"The EPS user interface management system"``) and 4 (``"Relation of user perceived response time to error measurement"``) would never be returned by a standard boolean fulltext search, because they do not share any common words with ``"Human @@ -329,18 +319,17 @@ on large datasets easily, and to facilitate prototyping of new algorithms for re .. code-block:: none - /Volumes/work/workspace/gensim/trunk/docs/src/gallery/core/run_similarity_queries.py:194: UserWarning: Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure. - plt.show() - + /Volumes/work/workspace/vew/gensim3.6/lib/python3.6/site-packages/matplotlib/figure.py:445: UserWarning: Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure. + % get_backend()) .. rst-class:: sphx-glr-timing - **Total running time of the script:** ( 0 minutes 1.563 seconds) + **Total running time of the script:** ( 0 minutes 1.211 seconds) -**Estimated memory usage:** 37 MB +**Estimated memory usage:** 39 MB .. _sphx_glr_download_auto_examples_core_run_similarity_queries.py: @@ -353,13 +342,13 @@ on large datasets easily, and to facilitate prototyping of new algorithms for re - .. container:: sphx-glr-download sphx-glr-download-python + .. container:: sphx-glr-download :download:`Download Python source code: run_similarity_queries.py ` - .. container:: sphx-glr-download sphx-glr-download-jupyter + .. container:: sphx-glr-download :download:`Download Jupyter notebook: run_similarity_queries.ipynb ` diff --git a/docs/src/auto_examples/core/sg_execution_times.rst b/docs/src/auto_examples/core/sg_execution_times.rst index ef2f22d0ba..9d5de1ab32 100644 --- a/docs/src/auto_examples/core/sg_execution_times.rst +++ b/docs/src/auto_examples/core/sg_execution_times.rst @@ -5,14 +5,9 @@ Computation times ================= -**00:01.563** total execution time for **auto_examples_core** files: +**00:01.211** total execution time for **auto_examples_core** files: -+--------------------------------------------------------------------------------------------------------------+-----------+---------+ -| :ref:`sphx_glr_auto_examples_core_run_similarity_queries.py` (``run_similarity_queries.py``) | 00:01.563 | 37.4 MB | -+--------------------------------------------------------------------------------------------------------------+-----------+---------+ -| :ref:`sphx_glr_auto_examples_core_run_core_concepts.py` (``run_core_concepts.py``) | 00:00.000 | 0.0 MB | -+--------------------------------------------------------------------------------------------------------------+-----------+---------+ -| :ref:`sphx_glr_auto_examples_core_run_corpora_and_vector_spaces.py` (``run_corpora_and_vector_spaces.py``) | 00:00.000 | 0.0 MB | -+--------------------------------------------------------------------------------------------------------------+-----------+---------+ -| :ref:`sphx_glr_auto_examples_core_run_topics_and_transformations.py` (``run_topics_and_transformations.py``) | 00:00.000 | 0.0 MB | -+--------------------------------------------------------------------------------------------------------------+-----------+---------+ +- **00:01.211**: :ref:`sphx_glr_auto_examples_core_run_similarity_queries.py` (``run_similarity_queries.py``) +- **00:00.000**: :ref:`sphx_glr_auto_examples_core_run_core_concepts.py` (``run_core_concepts.py``) +- **00:00.000**: :ref:`sphx_glr_auto_examples_core_run_corpora_and_vector_spaces.py` (``run_corpora_and_vector_spaces.py``) +- **00:00.000**: :ref:`sphx_glr_auto_examples_core_run_topics_and_transformations.py` (``run_topics_and_transformations.py``) diff --git a/docs/src/auto_examples/index.rst b/docs/src/auto_examples/index.rst index 1c9bfd20c1..cd0af7130f 100644 --- a/docs/src/auto_examples/index.rst +++ b/docs/src/auto_examples/index.rst @@ -34,6 +34,7 @@ Understanding this functionality is vital for using gensim effectively. .. only:: html .. figure:: /auto_examples/core/images/thumb/sphx_glr_run_core_concepts_thumb.png + :alt: Core Concepts :ref:`sphx_glr_auto_examples_core_run_core_concepts.py` @@ -54,6 +55,7 @@ Understanding this functionality is vital for using gensim effectively. .. only:: html .. figure:: /auto_examples/core/images/thumb/sphx_glr_run_corpora_and_vector_spaces_thumb.png + :alt: Corpora and Vector Spaces :ref:`sphx_glr_auto_examples_core_run_corpora_and_vector_spaces.py` @@ -69,11 +71,12 @@ Understanding this functionality is vital for using gensim effectively. .. raw:: html -
+
.. only:: html .. figure:: /auto_examples/core/images/thumb/sphx_glr_run_topics_and_transformations_thumb.png + :alt: Topics and Transformations :ref:`sphx_glr_auto_examples_core_run_topics_and_transformations.py` @@ -89,11 +92,12 @@ Understanding this functionality is vital for using gensim effectively. .. raw:: html -
+
.. only:: html .. figure:: /auto_examples/core/images/thumb/sphx_glr_run_similarity_queries_thumb.png + :alt: Similarity Queries :ref:`sphx_glr_auto_examples_core_run_similarity_queries.py` @@ -128,6 +132,7 @@ Learning-oriented lessons that introduce a particular gensim feature, e.g. a mod .. only:: html .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_word2vec_thumb.png + :alt: Word2Vec Model :ref:`sphx_glr_auto_examples_tutorials_run_word2vec.py` @@ -148,6 +153,7 @@ Learning-oriented lessons that introduce a particular gensim feature, e.g. a mod .. only:: html .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_doc2vec_lee_thumb.png + :alt: Doc2Vec Model :ref:`sphx_glr_auto_examples_tutorials_run_doc2vec_lee.py` @@ -163,11 +169,12 @@ Learning-oriented lessons that introduce a particular gensim feature, e.g. a mod .. raw:: html -
+
.. only:: html .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_fasttext_thumb.png + :alt: FastText Model :ref:`sphx_glr_auto_examples_tutorials_run_fasttext.py` @@ -183,11 +190,12 @@ Learning-oriented lessons that introduce a particular gensim feature, e.g. a mod .. raw:: html -
+
.. only:: html .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_annoy_thumb.png + :alt: Fast Similarity Queries with Annoy and Word2Vec :ref:`sphx_glr_auto_examples_tutorials_run_annoy.py` @@ -208,6 +216,7 @@ Learning-oriented lessons that introduce a particular gensim feature, e.g. a mod .. only:: html .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_lda_thumb.png + :alt: LDA Model :ref:`sphx_glr_auto_examples_tutorials_run_lda.py` @@ -228,6 +237,7 @@ Learning-oriented lessons that introduce a particular gensim feature, e.g. a mod .. only:: html .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_distance_metrics_thumb.png + :alt: Distance Metrics :ref:`sphx_glr_auto_examples_tutorials_run_distance_metrics.py` @@ -248,6 +258,7 @@ Learning-oriented lessons that introduce a particular gensim feature, e.g. a mod .. only:: html .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_wmd_thumb.png + :alt: Word Movers' Distance :ref:`sphx_glr_auto_examples_tutorials_run_wmd.py` @@ -268,6 +279,7 @@ Learning-oriented lessons that introduce a particular gensim feature, e.g. a mod .. only:: html .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_summarization_thumb.png + :alt: Text Summarization :ref:`sphx_glr_auto_examples_tutorials_run_summarization.py` @@ -288,6 +300,7 @@ Learning-oriented lessons that introduce a particular gensim feature, e.g. a mod .. only:: html .. figure:: /auto_examples/tutorials/images/thumb/sphx_glr_run_pivoted_doc_norm_thumb.png + :alt: Pivoted Document Length Normalization :ref:`sphx_glr_auto_examples_tutorials_run_pivoted_doc_norm.py` @@ -317,11 +330,12 @@ These **goal-oriented guides** demonstrate how to **solve a specific problem** u .. raw:: html -
+
.. only:: html .. figure:: /auto_examples/howtos/images/thumb/sphx_glr_run_downloader_api_thumb.png + :alt: How to download pre-trained models and corpora :ref:`sphx_glr_auto_examples_howtos_run_downloader_api.py` @@ -337,11 +351,12 @@ These **goal-oriented guides** demonstrate how to **solve a specific problem** u .. raw:: html -
+
.. only:: html .. figure:: /auto_examples/howtos/images/thumb/sphx_glr_run_doc_thumb.png + :alt: How to Author Gensim Documentation :ref:`sphx_glr_auto_examples_howtos_run_doc.py` @@ -362,6 +377,7 @@ These **goal-oriented guides** demonstrate how to **solve a specific problem** u .. only:: html .. figure:: /auto_examples/howtos/images/thumb/sphx_glr_run_doc2vec_imdb_thumb.png + :alt: How to Apply Doc2Vec to Reproduce the 'Paragraph Vector' paper :ref:`sphx_glr_auto_examples_howtos_run_doc2vec_imdb.py` @@ -382,6 +398,7 @@ These **goal-oriented guides** demonstrate how to **solve a specific problem** u .. only:: html .. figure:: /auto_examples/howtos/images/thumb/sphx_glr_run_compare_lda_thumb.png + :alt: How to Compare LDA Models :ref:`sphx_glr_auto_examples_howtos_run_compare_lda.py` diff --git a/docs/src/auto_examples/tutorials/images/sphx_glr_run_annoy_001.png b/docs/src/auto_examples/tutorials/images/sphx_glr_run_annoy_001.png index 8356f80788a044822ba6470d863e1792885c330b..4b06f2bc2bc94a338e3f60a293843d772c63d1ba 100644 GIT binary patch literal 44608 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%0DhNS7* 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 v`nD$uMaxBrOQf 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 ay;&1;;l7XE@+{=!)7f9R>?_@SB<@efmLz5X diff --git a/docs/src/auto_examples/tutorials/images/thumb/sphx_glr_run_annoy_thumb.png b/docs/src/auto_examples/tutorials/images/thumb/sphx_glr_run_annoy_thumb.png index 842f4bf78a387fe02ee9c77afac6917aa7ba4306..beb35d5bc550d6760601ddcbd0a35ec44860a93e 100644 GIT binary patch literal 14666 zcmeHu_dnJD`#;LgNLKcytc>iHY$B9w*+TXvWMr>oWrdJr@14D~LUst*JL}+ko%idP z?;r8$c5~}?oZ~zn<9b}z{kq@pkFckz@_0BDI4CG6c!~-#8Yn2JvG7BVg#o{D(*NX% zf+BodQRdMzkF@PM_m_GnZ%!@*r5pmickd}J4QDf1>&zsY>P)C)YlpqCo1Qlm^ql^a zr#MqN_*$1{ou24^yoc;TtaJ#&MRYn1El7%poTp@*=tOe{CF?Lr?Zl5*{W)46i~n~a zFDLiq+qcGTOP2Vs{v>Yal|GUqugljlczAgG2mRd6hpSISL_{R^Pcnp^F)F51G&RTa zC3X{6S1s&jYv1;o)#uRA@5sx_qUYq~G;=+!eYCuZhIsV&@r~W)3oeuf_uahm^7l_t z1@;$1Xx}F$c8%o7V`E{_adJi_CX!}&uHH2q5UJb8^NZ)*uH#PymTEEd1FRN-A9WU?u zC`v(iBYe=J-B#cbrmSgXG_*RHdY7F1Q$a!4_Ds!Tgb^ZOX~`s!Q%_Do0c*GEgyu!D zzVT$Sfs31))A7dhN?lGh@nhmgj~-D8I|UsaIAy%~r}OMS2_`<(@2)6Ht14Z73cR;( z-)_y;#lN}umo>KjtIQO0eSN(dVM$_WQl)z~UgF#N>lb-{A}8a62eF?&Go7EGKP?A!ycN=`-f2S&;O zJC`Qx{LZ{T@iqxbXKNs)PU%b3&55FREB*u6g!0!j0`qT943?Ich5fF?a&vQ$UyPC_ zlj4ceE^Y!9T1CiV0vjE;`h`ke6+h#$prUt{~o>C#DATC!SKeLOo{ z(=;?xee*^fMbK{cQ&km7l-y%@l2=p4w{ILj(nZ(2UQ0`(vA-xb>kKD(_WXI7c|WP| z<)%@NMuCvy(#?{le-sb}5ZRG}3qJA6NnCM>iE=(ZVkkU3JkOpzbASC-VX z2LAe`{j#x2{lyFUCr|Lq&CPES5NN^+P0c&O!NIl*&FMiwH(^#nPJggCIXQ!Zf`&&& z1Ey?OKPM(Mw6x^lI2^7H!U+jHnfH#VupHtQ5a^n* zZ`q#nlUd}0u&u8bfw1jcAIpDbYinj@6`GMjGd(kdd@+{yBu&J%@3?a-@zW#Ga+CK^A4V|jTw8#njb>HhLfbac-P&J#)^ zI=|SI6h#vg2KcBB1%ecz09|AIjwdz%Pt~{Dk@A| zT=-SGPaxFQ#P)B7g@wVX(JI#OHH{JPidU0Rgn&UFJQO%Jkx@~OzrUkSeA8)%cY3RA zCWT!7#%_{_XA=?;NyD6P-@Xl>$Oe2-6;kftv(Ytr=u&}XP&3KJ#X4DIw{n~aj z^jslv+nx??U;GVIW4d=QY;n;T4y`~cUV;+3zf!Jru0|FcPHStcnWg0&5|Wkrs!tSSLqo;p+bma2W`XNOWM!KrJ zvNA4=jFwgn&egqp_u$aN80@{9ve{r1lfuOs1)<^LORbo+W`iFeei^quI6OS-d(qrB zQKZ+~+q;;XWZ1Uo@JXxi9w+CD(e<$r{BI7&nTeGZnV8VXcbC1lt0oncl-!^c6MATDJh@x@`zycurrE^im-R}hN;QP3QkVEtZEr% ztpVsLKF5VdxlK*!l!A7pZri%611asD5oA26gUD1pJp7cDQ}@p~HM`cgm-CIDGBPp_ zR|roAM#dCLKZyrdc!i%n`3D4`1q2564h|v{4FciQ*ViZHx2oap~#X_0I+Uu6*k2>#bhD&Mhq+em*o?=Zt;pmKg++?Q~_>RE4GUVjKEoCre%n ztW|hK1Oy5(F>xuZMzLX2__#GQJ9|W(^IGFm>R}=l=12LCjqr$Ui#4(arLP=Z(*(D`0d3h|;)6@E`Xis%@m0)EfNIA2ss}qZh zx#0OXA~7GodUdaL%mf|&gqV!1;?)=nvFzex%hf|uQ`3PIzL3bsTWxJ^jaL~LxCz;8;Uy8t z)-EE{D=RA~e^yrNB({PHGY6qKl2cR57LKd-UIoU*-8S^umqn&HJGi0PE_0jA19r*xR3>$Ph>`2@7)&qWU>G30r`TkDvGH)A#X@$@gsqDCKhE ze*OCO>T=hs#HMW-6nyE^;Z7&~`S`N`nqF}1= zkl$)N-zeweE6WAE^jM-~mO{hYuf0O*+FHB)XT| zJuopaJoZ{K4RV-*lJC#^UB8i&lM|zXKLuUnLH zG=nPbFK~$`yGc6&K;|nMG#P-EdQ4IPIcsJAdtt^S%VRqG z_b$DtMB2+JAA2IrkZh?OyC91|Y&8Nj_xle7nFF?J9cm1@Q5h_P7I{P^CFgq%MOV-2 ziRpI~)jvHFl$JH6eV!h8)8?mHXK;>sVQV0di96fp?x6ZhFKj{{M*U54CUKDurJvMj z-m`UFlHaXxE^zffpTCVVOHo;b7BQ&koEaun6)vm8gNTVjH|siI^U@=tGm#UT`Pp4Q zD`b>JpO>=8Lzz$%m}bX2%*QXMrB5DQ5a(xgPbDot+Fz-2BDlb;JP?Q2a& zcMpd=k~Hn4Y^hB1?evcE4+K4b`Et8w>4Ox{b@d<&B`crVpc{YS7&jjN5QSoxtySo` zmhOH!J=rYx^eLgZxcJf0(F5;)TfJYNhhjGr2oh0{OPQFJmMGtj{~Z(3FyVp+DgGnM z!ySvz0BKzpHiAoferYCtiSZz`&kYT!jPlXHT}0};&zwqnaENS@xC=HNYWo6~? z)YQEq!bQO!{KsW-J~$3O4q4EwkEE?=pYHC1bM?(*fxGv$}df=C@CF69XfAax*MCy1A&6 z=eaxCoiVj;|GVf4F|K}jMSDdM7%eS7d&i?61>6|_V9|B(f`BAe0)16s;HF(v8_q2% zTKtsQ*xw^2L3^JMIWLLxWwH{Z((*oQ;&~a0Pj*3kHJ=S{UFbSJR>8m9#hzExSB=_S z&fz^80~H)_0uu{MHX9B`;M`=h-qx8!gaJU#HI_IEgsSXnY}h9)N- z$>CZ=1UBB>{!DAL(EJ9FMqGS+AQWOiARPL&u@7w~P?l?aJ1w2deH+Kij8z%@F88R6 zk{EX$y;BZ*wXU&=au%kGc7x^mU&5T7<;$1;P`bUmy*-aAy3Poa_!j$A!#d#ZM7UEh?un za5`{udg=kC7#l10>}KYlQ#@+F%ZY~vL~WkNlVatwv#HV^nX_#~W6@I^Qj#WF4<3%P zch6M6rUcLjxRTl*0BotxnG;HOc6Lu+Uv^$z7kiZo^9>93Yv0DOEOko1hPq+k}Ig<_|msOWfk4ZVZCxBjZ^+`3s)#zLCSN>-bhTS6Z%pJoCq zqrisOyR(=(g1yREYuDP$$~6~-caB928-`m?1jzcBzTZ=YZ}xNxX)773cE~dKx71oK z)z+Fn)}y|WgE&{Al>DWo;`A)Er2qDbB7E|dpqKn$R;#n#wY8zYO?MIL<2!#? zL+tjB`fRadUP;5JbZDQQ>|OLzBYJPtar}rrb`@TtF%%h*F;-$?KU{ue5WYtUnT7fC z;OCQ#`jE4cf1Vw$%(F9EM4g(Fs(tw+r-g?mbFm2Cqukc)`!e3DhCfHAkh3Z;x_bL_ zT!G3}anZtn{ZP$e`*x?*&vLFQ7Y0;@yvX@Qo{Sm4^iJV2A9I~V7;t85k#9^%aUcCX zjdSt5RBZIn|43Ya99D`D^A<;rKtlf{p`Axb-7XP-UW*a@@0e?dsftJce+}B1~FM%VIQ>~V4wX(_9y+?tx2vYoAsOEUBdD=+6o zLqjuD*5kQ1U;9fHk_`Ky*->=M=3R>Ag=j&vJ++zemFjVR!7P-rDcdwL&-cm6r4BstYsA@EGnedaJLb4JqPaY9J7V-y-?6XBh%T=Y+x}I9 z^P1}9by7mY+&f>rOTC^hHDBbc4Uw98wtu+%grhGqk3&B3eM%UV&;`#;4b17^QWHN^ z_aLEZ`aGQr^filQO|rbGCthS6<-3RI`ZU$$r^P=uV!yguLp*nZ-e&m`k7fSr)^B-H zrKkM|Oniwj99&GBt`Ps?^z5Yn?bO%ppI2puQeoiunsf|q7uNp~yvo!Z@w4G&!VeL|V*|31=H$O}4t)D8F32X6Q z*1)8lINI~jNjy@+mO_&`?YWki>L*tI5D*wp5WFJ9IQV(gR@6JgAHLTpqe!0p7u|nbFSvZUyQSAkL+#z_y}h6=LsllSwvcZ|mF#nfDfv-_FP1C27Yg z%~)s?p+<+wz>?m%`iFMDAdBtcdseg2l!c3vJ5T<;>ppE53@%46I(>HM${IR2gH(m} zV=r5Q)O;JFu}~Pn?AuLZB@Y#BNJO_UOM_eH^x102JH?-PD9>zcSXv3=)$}&Inma^90ZO?HqN1slmHg1Un2odNg)SIaTD`UT-+-+SR@^!0>dsLCItK@+tsPd&9(0!@(`2ET261|$8=rx5+ zQ;Qj+@xd#bIfR3EnF`U7GdIoammWX6+$C5S>1P>@2!gvCU6xq7H(U@e_4XrmcT9kx z2oJ}BvIMx6O2UUczW0yUEbYZjBeCi4Jzvt{Nud|8jXS9$CTqJ3#TFeV%Mk1qv(s87 z&FA;KV`#g9u=zJ*Z^}oj>i1kMB+LX(=Avy$s`Zr~=cqznydva+)D8{7uFpGSLNN{f2;l{1M2$x`k?LHqzsJBQFc9+mVxBQZEI>7%k)9q^Rvq@6iN&|FC2ZXK*w~e}Zd4+4 zuHfl?%177)b&OIRq`2tl=-&*RK0->T!pBt2ALAB93trRSQk`#@=rr=P!@tX8Oq?&f z-!fEnP$XD#a5}02$jt%qF8Xm*(=uQG3p4dJ(v{8f%dVpDPYa&a1cyj^UYdwz8l^@1 zkPv4$$@>HH866+*geV6h#Iie@8q(+Yw_oiJ?o^p|MAonbJhaX*Olki(6^8K3w>vmk z*9zBQJUf4<^M~2$jeb$`m;Tp*Lg_fUDP@q^RT$m3Z(!r$t-!8{A@S&R(A%c^ zy1htSO+2@+ZRaB-IcwPVX-dvT`xC*}I~jXjoo*5>LXWl3329vA{Q*w#0MVHt?hSO@ z(ed%3gV1LZ-l!($+z8M05hmGpK1IlYvcb+OUvo+FnzIpowT`mZjB9*;lX*Qn-&=p;obX}lw%_a|4^UZPpFjW_*`e> z58OwNR$(0wj5<0x#hL8k0l*D=c#xADs2Va_r=EHL*aIyn1JN?WNxUU)7RGT z=fYRQtg~k?{kh@+p$V--4+}xbe+$>>~w4WkG5)5!gwt#m^QzfGTqi3Z*$x$SIAX75)_wSdJ zLyx7Uf0di#0v`b6Lz&&2h_0^g-`!n#bz*!Pv7X*|R&yg4$(n0xvPTpTDOXv}>Ob7; zTy)r*S-48fMEqgZZ}FWgY2jFZ$BDuui?OhrB3-*%jG8@e4d`~cFM<6Q9$uZVU6roq zVlbJ)|G2a0wl-;4?7+Z4Xe9(*Pj_sL7s7crytvWP;X)9#|6`o%s-&vI$Dr>6L_Hb!+_1n5d ziDhLxKuhXWSm1ejdKRzsWJg>ntN(^Wd%85LvQ)`y>z)mHTut(l9~da0dI*UQdhc+* zDXMo?n7Dr@ekYm~kQyB~Hvv$6!05^4j2vqNU6m?mZvo_2M`vf5#UKTA0c+y{!547s zWvyPKP<}QY=bS7tlFuJ2^Sky1ScY&5DAH87+7{GIK3MPH$8~JksYN^T5{Co>DQ&=l zPat)W%oUqplY(lc$;JS2Ru4s#*Blgp=$ZxJRA6XZ3>?WMHm(&uToLf}?qDGULPS(l zr`CZUmyAm$f9x!qYtdLzbh;-g(V{Q%@Z!_h`rnO>rO{kvI40-yX==}A#8ncH{IIxd za|k-@YJgvGrJ$q)+R}KrE2{a6vIpd#JttY*X+pfsKNI6`UcGun&%<*&b?{xU83V_F zq~Pe+9ja`ZbIBkw$c)fYB36v9a^Wb^n7Okd&wAj79j{6I**V5tSJxKkl(BGeb1Ew0 zYlW_7+fF7B1Ugij9_2V>yW)@2w>pl*LQYUxVd9K(bZW>JpbuR za9Cj)W!Cj>{{;c5f`i8|=#Z>zZ9CRoG@iMvt?FHUspuI_H( zxDt@}JUr#(sV$-lvqQ?P_6Ns!X9H?6|6GN~-s={@jys$km}`|7ZYLQPe-#PQiKV}! zZ4=#@#^7dSqkH&}B!BGQA`d!M-F!cEM1OW^IX~F9F;6);0xw6S}4%;WxO2k55ES-t+Z& zVQA!03&Hw)7SB&9=^)s{-O~d}PjXM~wI9>wU4>TCSsJKFC@`hf0Y= z;y@$iOm4n0_(5&m5YqepieORJ{bs0Ye!Cej>avZ|*|NeN)D|Jnc)6xHT3dD&UKxR) zgLhk7wpXyT=oM32N$nopYko2p^|yEeXXEgJNY^gXnkY8tzd;}-<>%MJy+M?@6s1gE zNv?uuPlRQ>;bZV4@-{JXN5znYvZG_!!k~=15Xm&ATuM9a*+L=b%%yue&(Gs%vOo+OT%RuK&D`+&0&4)~CRd zESz=;LW|14!4U~^$)qWeGh_K`&g-MhX{xLsbj7KSQWI?J3~Ut_)i43bM*<+ z)4D*BUha@;J(+x<&Bs~tT4#RXv23rc!EdAVYCiRsFX=!yVPayM-A^7{Hv?!H z8%uZ#Bk+Y_n)Nnc9N}#aI7FK}ScDOs(!RbDK%7G^jmyZ`@lq+$TBznN(JDMvP2d}V zcB!N<_0<;jVk*I)h1UDVp=OIRZ4mW}w{2UFa=CBQT#c9{*f*cCK>mg*J2pM7q@!~e zgkemU7NgR#Nj6+doJ`1h&}n1E_sW3oE0V4%-PZqAG~{%G@&)$D7a$MF6g*DDT3a9C z(@LnQsSyAkta(ye^z9pxQv3gyn&M)NPava#B5GWw%~DjoDsiWRXhrPyyt_PZhZ(OU z(8d5U97NJ##f^SGWZZ6;?QQ)?b7lKFgCqQ}CG-iaV?Cm>{eu1fAV{W0+Rq z3J9#l5|HVLK$``fG5JINmTIs>PQrlptG8IY4UAHtflW1e3)1@Rp<)EKa=)NXkG@ZV zN7X#vFS+|MMnFcc>?{>1`;Q+#{%U?B3fdy<6dGFB3sg1^4zr!vIv02MoDr*9w`~e& zcwCy?crVZ|qO_jf55-Peu?;$z+gHrhC_ugqgb)+vd7b{Z z?J$y5l$)v%y53%9PUvo-=_Vv3l=AXAH)wB9qHrC3%jL5cjk3PIZ4TNcRQcO9G^#H@ z@kg;nXsUZG28v7!DViy|Z2@V}(ald8`9~SEelJdRCkcXPWPbifxp_aVI{7V(SHUXp zuQ}{lc$s1iau2S;!zx6H&j$r~mp`L3_$(I-&Mx>~y#9~D{AScLKl5-9E2QK^V@AB~ zP*lmsAUrwyT!r)}tVw*s%{IZE+Te!|9()Ia4a6!27M9iOUX3V$8; zf>AAIkOqdyybgt_XVxu`v4cVnXAtzFGTox`;)D?DFFUI%e4IY^%2``;bUVs9^9rf~ zKCO3}o#p*+Vq${43&oIun_JBy+k3chO;`BYSbt1)Qta(JtH99^PntYXgxMA}{CkU( zdnYE|=@zjtGA>s?$qn*GHi7>mn+&C`V*T*YNi<^$Z-{F(hhi;2D*?y`k{HM*y&NtC zrPJw+4yDnAPf)H;wQr+Z*BNo{7-fzG=;ku$iVO!6yfMLLVrE8{RmZ}+v~o(#W^3H< zqC_6bl$2gji-xAFY(M~O-W0Z;%AYa+ZnhG#Yh-Ds#AIZ^TyYk>)^p2ckpO_n_wQ05 zhV7i2B`9@50Tu$q9z;QqvH1YFc{S$ehd^5cT(bBpbTyJF5yoquJ&c$^HS@zpV&Dz( zQsmO(^iv=lY}*Ed0hvNKRADi=G-a8Yo1Kjo(HW4<_8*lkysSsR5`~c=`LsK;s5fDc zFh09Z4d$`?#ABryj{n%$*kf~ZW`JRqAj^Z$o25~pU2S_;F2_;sB)!osD;;R!=9a3^ zN-LciC6A1`tOqa43#f8?lod={=PInDnc@bMA0KuaoprV95Fo~jH;J)?v1rT zGBTEFxKu4R1NdRK7XBFj%@*N*v*(SFcSVd*dVO!^w_ei%j&82T&$&Y#6K4frQo+I| zbiZsak8iJP^4T3>C|~-_r|A(gxM((P8=vbCWE6|y*zT8Rm0dN|aoC^~dMhqkWl{W% zT;YHeneSsXvw*9$MT|&N%InIan^7Ff42|EWUNYQcAWwjhm83&GxC@MZCRO8GrQ9WZ zniO`%mqBX!cC??^9*%-YfZFq5eyC&h>FMItX3$NHJwN-8oQw26ZPxA@3w&+wsqU82 zBLXX>c3Mr`4+2lD6=Seh)F%I&)l=~VjvwE;LqZ|bs3pK~=jsvKAI-?fsk7EA-BlL( zgP(o2$Q7v7#KTBjQQUldN>CSkj4gsGfA(Xyq>M>atL^b=+W5}rX7`|6VMk~)vB+M% zo$Va|_s9_F2u*e;?T761lPg%QNR_88AQYDXvy7j_s3r1fL}i(B&dTwXK(L8c(wy*q+I&7Qc~Z4o}m=)QZLTf8!~f0>R+(q z`mjgnyY?*b?TV+7lA}xoUBpDVgEMKqt|jml38lHy?wgnY@;tF7 zyWVuTu`tgc0(zifu@=_J`nzr{oTqmfVdH31HEK$M;~8u`vZA@CXzcn3twqE&-oDu} z;oA8%O~rMo-E)Ah^2H~k!=ln|K0*r%x-!--Ut-wFOiU(F<@bUME@PX${D2n*YLvpyQSCCoP+(|5RNE{IC2`qUzyk%5qqQk@-+C#6=B zvrPsiw2d7mYr%@d0DivIbolvgS6{g#TC{a(O)MPl))D%W-#SH_4Usv6`aUD$$9rbwT2NZu8s?VurkfoL(g$jv z){${oe4rF(szx5^FFKIC+1Tf+9Q8Nk??JiCGS=XMc2%z<&t)K zw4@GWO>xJ-7=#Zj<+tzb@Fq54h~^>?BA(W=_;F5~N&`~IO>!2!IE^Ma`>80NhZ>lQ zarEWE`N?I|=Ys?9Z)?NvBT!zAQVQ$lFN4l<4!h}NVm1)nxf+Z9xbwr(A<9UU_US&R zD`M)S{<;`3pBBgk5NFb8=IDkzuBZG`P$+$_=O~&hnc{;}c$zt6u`=uF+4sWl^;kmW zikx=4TYJ>9rMNm1y?OqQ&^Jq6>oyPhp`` zqo)-;LJRPiwAlmHa*MV>i$nioMBkm)-=b$3fWJmt&6W2& zjFmoZ>cE;3Q&M>%k%`F=L}+4NUxEVuq4@gTBJlWLul(cWsF)h)=WdA{w>AfU)yyo? zUff&K`z@F>l0|0iz;AUF8you_NH3)R`}=omATZ6NrWe_`JmUb|RWrmCH8tZQ*iA+u zI>96dAq18ba7UpaTRNbJDH4?4F@_hg($W2H)*FUOgYj?8%( z-@mIFW$rb*F#*BN33L+>ehbIWvg$|!A-JR5^&|ghJ9Qk&7V9)ABc$3&zs)svW?wO7 zd-LYaPg-hM$+-3{F*R2LV0wK1oCLbvrjiBA2jtrIF86>a1=rfh^mJbwqdaKQ-#u_w z;;oaTcXwUH)r`-tUf2AH178vd3efLgcdUISCUDnH9<%_vF7+b7F|akQfMN_*ruF8U z<|Z;(br0}`ox%YSTIbAON7NLITO--Wt*MIMzP^t?CAeTHwAV8r-6%YH(o_;r2?dKl z;?y6ys0@!KY_uCUfI)&v}qPdLWP#>QDMqQ@sD5qULiGO1O*i}bti~k6cigG zg5q!Rd=X;QckepB=}q}|SlQ4(*)X?rK4Vu!4sW%cUbt=^cG?OwTvdBh_ZPP3&O;ye zF*OysNMit2@lLnkxHu1qcSDx}6ii-YV;U?vQq3E=2no*yyA;4t9I*Z(J##@pH^Jv1 z?EQ}e=*zA7rWw=0nXWE5-|LHo!{ZXa^tBA{Xgo@Rr{EB^_q)&oX&TxM*fFm^+H-Sr zNT(@~4&b;$+NqhDgTZ+ABU2J-b~HL|BNKDt_>WzG_4>6r;1|R}QVY`3%AsBA52i%0 zT6W%16MJO#*)p*OR&@!yJkWPS(=L)8ovWM#5KY?No*V3r4Ml49<#XGKlV%=gD@g$5 zZ08$OZeZd=a3cHou&|6drL3~DxSDyd2z#GpO2m$P3(#KWz$XJx0+;9BUr(=1ikry~ zZAk5#j!D%d&X|x+X%W|OAb(>F0{wh4?0%KLHSLZDOHkp9lGTo|J18{bYW4lz8hWia)N9S-opx#J*> zkdG!IB5DI;5m;a8f!=f7oB-Cb69t{rXN^#hR4Tc!P`6}c6bXZ zzgkz7d!N{WlVY{Z^bP65hYxM1%F(0b_zL2kl7OlRpn)#|=x5dWZM;ML`4h|x{9eaBY z;0kRACl}Z>08kTu&tc@pz{CWO9@Has$Q*Na^0^u#zkVs0nl9%@e@OlU3xzaCB5weI zs~IBwyIl=X6Hg@uQwo;b7yfvWlOu&j1N8_UmlS;HVM@73t%62;0-W1WdBBSs z3qm>kgL3@)XMrZzJ3Y1nCrrv5PWOx_TVA-jJ_P;^e(SKmBpVPAAm*jKJ|QdwwqVea z3%-6eIo=pQ`uA`2*DoZy-zd;Q(q&HzR{>(-Vt}FH{AcR?yu5c%C=$7ikoOMYG=n|a z8zEHlV+=_cSLyOlL~$6@yJ-B-JpD_N1_=U`0I(3mfg5h$W^clif`;Y?NIzh@cW4TM zn+1EP$W#K z$$xj2RCq+vf0(vE2~NgGo>S4%PD|E8nscBUFCgeY=jX?N{1`5mV{B#?WHVU|8h{Ki zz#zGC7&TM*L)L@zq6&UtAZfv%{Pg*ABsT<<9rA2J)~w&jEY_)zn_#)4spRTfW%Kv6 z2>;K!cNlQYpb$ct1nN}OZ42!G$TW30BsqjkRe(n#$hh;sJBRda!#xAIs?$3#0D_On z19Fd}5&0%w+Se?xq@giYm6b?u8`3EU)_%B}0v8MjL7N%0KqeK)o%I=zTDm}_m-h3M z1V!x+05b9@IWR@{fQK@A+&VWe4o7D&6eh{(ori^Dl` zpv+86gw)he;GPhC5CkAz_Z|I7+tnCu$2hRC1D^%dG?410RwE1mtH4;#EG9-(r8|f? zJA|tjkbB=j;qzG%5s*I3DJ^{fWeJFUsAq5+33=e48wRuT9ddGync-37pfE73?Cn{> zZx0exa9&nz+qRU59L56wKN4T1zAZL8`t4NptdTbC?L1}?|8X(;g z%R0W9sdrilx3TbmEr(wMO9|$Gxc1=4DL4u&9JtE>tH35=6Y#7+lLJKrFehC10|p_-FZxy^bM3>=^wTxa^e=m0M67{d~GP7>3anXrh6!>I*63a5)#sllz@PQbQyp&0@5WZ-CZgj0*Z7gDbgK7DBVa)OP6#@ojuQU ze((EFoDY5&oO|x8_TFo+wXRTQMQI#Na!eEy6dais&s9)RZbZXBQVcZsi=*xr4-^yu zG@0j5)ZA0HX50*Qms5AHPa^7gHyU~@)hpStPV|4gbwEX@#31dQnb9eebBu35$nf1D zc=7v!pp3$`oCPr<(VTrj+s-G&QPU&IQC6T|XjYl{lBVy?zsr`=_r|El?z}vo8jJmY z#PP1??+G3VDhUo`mP~EA2H-sn5zcaUyYUo*E{Ew39$f(5-H#~vPci24{_g{F4RFmX zwFlRo4Nl$0C$?PMJ37c{Xgc2T`p$1sUKV}=e2H)_C?03@Z*1LbKs^a6bnS8FTP5$cDE7A{AL&L)?Y-}wi+zv+@ zud1vko~o!2@FnBqkIKr(+&MZrf>)HA_7G#Ep(0$j?mu`CQtZ9VMk(%_5*>{pIosJg!NKJ5vfdhZO2mm$~ieXJljuxNTFmwY3#!mfn23*b$|w zuiyXgXjA6Ji$B#(m+Ue!G6i~wxawKY@R}L{v%VxrcXt7^a1o}kPoKV!mtPvnmO~C~`-0h?!r~o@o}S)=SlN~SR5=R^ z7C31ryu7@>W@jU-tNGzgZ+OX7R8?UMlTRns*51Ui>$Jo3dEdVq4d*CaY`Zl*`>Jez zaq2MZbE4PX-AzhEvwC?lx4O_4&cMV(Ktyy~0tT0>n7VMdKCJnWxIbN7$_!YaHldN@^M!syaG78Is{|EG>=tQv`JzJY$h(r`&viTTHBfdj_F*9`#_l z-Guw4fx!SwS-|HXZ(m;@HZJb))RdgLIWv5){$27ehFM8*IzexBb5jmp6eY5cp`f5Z zNJKO^JF6%ud0V?M?qt?0ihs^K22S&=-?b0C%)igfc&tDRm)p zn^jd6cfQk<-r4!0xw-i_!i|&0?}7^scn6JN%E*YCtel*n>tE8w#>OJw9?_s%oiy25 zS$OyE`Hxz*nUy0$l9wC@z7Ai_$jpSbp}T*7A&3jr&d%;3F&1C)hlB*u`}Fj1-dj65 z4n|a!@Znk6Y@>-XQ|sCK#8hFoq2IqdrD=R_NkCjfBz^w;xx{jm)pdJX#?+J%9hW*q zAZW(61Am~C7KT(5Mshx?HbRRrmF2a zEGr$?e$g2j8G9+BaZLqyam7x*Ib0##}z`p+@Q8>cy}dj#*92`;v9Nv2ztlZdzVZ`?LD?+l< zZ18+6C@82~V}GMTf1oX#uZ~uO1`-8u5V~ydHAq?el?y$uN&e(-qMow>guXMt32rR)SW}OM&iwz2T|fz z0wkRJSxrspadE^#LPAXMZ-0SZgn6wDq$}Cju+PlQ6lhms)(~SuCO$km;_|!lruJCE z?@tr$Y4kb&UFX6E74GjudGKv4;$M@KVe0v&5Z6n~%de}awCbE$e0+Qe2?d78*@4{1%*-6Tv}AG<6;gs-crHAu zgUS_FtriqD3)RUfD7X^kPtVRirlyJxCMB@;n(+X%2nh+XxZL?CIUX>Kx&%oX>eE-1 zyqqnHeB}qb$BlgNw*Eb2;i_aI#H`R}R}$H4ZM}tVK4@84e>A28uTq$TU-$6xQi`a( zJWJ?Q`>MuTI$^!dVLSwp=`2JQ7#R3aukJ8zZt>8f-rwJU+H0rbUO7WR0;|~7sj-x_ zbSgD%W@aWFaeT;PI7&C@fL$Fz&_+w2;NhS;Q#j_f$Mu+5SLcYPK6xZ_Q;=vP`<5%7IDrS z_ss(4(rg!J4pR3igYf)J$|ueS-=S&m+?OyBbmQ8(oEkJ6p6r{wJ1b*iZl52ICJsrcD&P|qpEQW-e>0Cr-rtMg#k=`dj_TRx%DcNwV#~oj3NQ2Je8vKl;5|OYmc-Py%a3og;>09HCz!!P zPlDg}^|X=X&kt;(Cm$kJC$qAvyl%y&^M?=7pYAsk-hc0%>gf&B$;Mgl^ImOX-R_Ap z9-hAC7Ej-rMM1{z^wlPMm|eR<=$@~>tk|V{K_65A9T^AhTi3f1cOAZ7#i)nh3P~vQ z4C*+$lCBg{BOUN}TA0y`#8Y%|Q65Mb?9Q!@dWkaAvY28!HpC;MXlX)wveNc4fmHTw z6p5>??&~M(84czP60M)rW<-0%X)KLaht$+fBoURwmD*5(ahz6qf7({7zI^%f6Qdjk zCg#o4X&jFLl(n^Sr|*(I*^zYCuEMP1c49MZrq$0vn)vh0Iv#NfMo7$24CIOLG&>T( z6!sV=sBCYIWRYY>#jJ97h&+Zq}gpuQmMZM7W@;D!e+EiDz*)k>QUOsQX<^%%|BZ_{7BRewX8ZFV)m;LCQkAapQ)Xx_Vvh(|JrE2&HS1;-TOCvd_P8 z%JJOyu(Tkbf7hRSxx}))#(KE7M<*hJg!Yb3P99fhs}tqsxX^24WoHkLjY(-}#8*5G zP@VYedX<+&El$JPSj{+RiW*S8S=vGUtWffLRMJg&Y zJ;Cusj&}N#!o*p4*-2?%_bl89X+0a#Gz@%Vv*qHsg@j~XTpk0Q`SOJp&;ww3sode$ zmD0pK& zL>Il%sL4dxJ2_cRp1WXD&yU^RwGRsm)2ww|ZneIL65h6Oc)zXpXds>Urn|L!NaEIu zh9ua_5(mYbIxBtktI^vJBmhc4!M^7g86NKB`Q)kYNwIX&U~<7l3##BYhorodu@u%a zm48aZ(7;*^(X!3qr;P|=?}k`!H&rp2`5Q3?S?K!(A79X2t;KifkdpH3ZGEVv=3k-9 z33e!t-H&`Cn_Qtw#T!jZ{iCe+fzh*zCihKaVRsLfoRQB{U9>mui}c&c>a3G<@1_Rt z@7AU2JfYiGHlBM>Ol8d=ct4s*>t(MJPSf#jS`Gbvd~z2nlGLx9*M|JATQDkFO$hpT4(Z z^sgp^%ved1-@qVUlrbJ>@3~_oX0_1Zw|U%Uz524s=wB$STc4R)bIJPDegDbO`_*!{ ztS7VfnGD^;w^f}iSUxeI@^DZU`^aNBfj%#G?OPw1@%hoV43?W4%W&AO5c_Z?%k!eZ zj+G0U87_s8hIqs}8MXQ9CtkOB?yVOjarU*M@d!c9;hr8HtPqv6S_CDR!Ur<;i~Uxj zx?pVY&7Zm+Id2G{0L6Qrc%z#aWAAqJksaX0tUf(Qx%McF%_e*4?c)H578{G}k z1xPeJ%q+b#jD4g8v_>kIn}cRS?eg9_Xk2X!Z`P=mS38or!f;lYqxxfCVe8661xOl? z;^i`Wbf9ntciw~#ky_m?BrsF3oZn;aprjpukW2cAeC6rHJd?8&)|@vjNp?W6eTMoL z>9uE8XlseYRTF1ltm*HW7qcGo&e!`gi>-?9xqVawhP_CH1a-$dRON;=$C8yHRSpT?t(SZD!e19~3@uBCMUpTKTd^le3V}F#6M!{EnUGe*LzQg7D_lwib z%0wuG@=u`XX;%snrfaile0^J&hJSbTsMPogrj?V?wC2}SCj#1qqV)*k#-{4HlvBer zExw+avr7A2TjV_~#KL5^2|hTO(!vWwPq3@ZY0r{glGA~xa;QBV02lganGOeIhMpFh@zbAhI6 zZErU!)g&b)r4<*ac?;b_x#7?E$?qlQafwo&)w_Osx4M(ejx`pFaIDKtubX{&QdrpPZ68Laij`ueI)cDqq`(?90^h5VYOQF(6T%f=%^jxKyh4h0v2>jkG& zE2=;I*@g8bEC$VsPQX$?I|5x{rS{ggqln`2C|#Q04!5tEtnWp3t;usaHdi5la;Nen zljvuop=^*zsUeeYb95L}iF$tC-**Jks2@tj8!M~KZ{I>*<*VN?te$H6LzKfA-q-Gz zYMGhg6ms1t=w_E@z<2dY;!Yu{y$BYnGKTI=DBcWu%1sN^X9c@MWUTuFFiYV z=ghKueMAH{!M%I1^KIkf@kq9f+Sew`>Gf+m0180v!B1&Rg~!6N{X|0393!U!=qZ5# zA^`0bxo`4vhxDkr_J%=^wWdf zYrh;W9UE^y19q}OR#y%MCpST(PcwwHQkftB{=t#N@e$J zS6xf^`ZU^E=T3)afvf(6hP13Z?EpvoD;M+k$!LSdMn;cFv5^C=p7W&$Z@WLw)wh-Z zcYX#d)!WbN9VCp9QM1)xMwiyW(*u%y=d%ch9;^I{x!=Q~-(bavJ zzp41Fn8r58uebB0iulhe`*mY8m$=yPx9QcNR>w?h5rp$-{I_2i8qxwQ=OWGCeEXp~ zg}BhKx5e?FcEmmhtMKjN-}T&5rbn5p;h*Y@#c-=#F3jyR$*8FK3Oen8A$mO z&W?j$Einh|Yvh~6McDV2{Os*Hx8zDFyqLKx|Jc!DR;7dXLRXhkHv5xYJjcf*R;5ph zE&%7e4{%=FOq^s%>mc|MBBTBvM5X#*_1CpDu^8Ipb`cou8Y>aLAR0 zi`SXH)va^Blib%nUF)=WaNy*k&@AH_j8k7y9h6I)+toO%XjrN3alTaz%(*%6z)MR@ z^5=}c94@*#Lw+(+3gRm^PxULz}ufkVF@<~`l|9Wgxkby7^M#yz%pE?GfQw*=9HPrVj*V`y$p2`B_; zYy*P2$*)uu<~jv9xAW#hC0PnOKiRUGb0znQ9Q5)Wo}ApHq>N~4YJ!5vE4?v#@%4hW z*qV(&g^`UgLEp+Dz!#O4;-@OEM%D%Rk7P>e|5j~@C&?<|)@g1@+}PMq z&L90dRUI`rIB0SHc56=xXGd>s$x8>5L8NuHZXFXO03afbK~2~^O6W6l8)2mULd~@g zEhDu~^h4B@7{k7#$A4!Vl0SbYG%_**e3tdVW^CWDN66j6No?>Z_Z5rSoWczPs1d-D zOG-)tVfj@(f97R;%`-iJw8nBoSO+mfx!LjIg}oC$^iytb{6Lko8a{#+C|B4iJDp#t zdT${|#OPU$-ARglT5`Jt&~`2^F1-Bw_o%6ThgSrk@jpF32R_hWJ-=;k&H!yaBeJYvFF#-si*>k-7a4BE9%b@aQWAd zv489A>r{McHHrh~|`F4$ws zkbaxXMH^Jlq{l+Ys&~;>_b^PQnE?Qct;fo(+qVZN zCuQ~YsOahG`MnjsDnBysr<9VC0v35`uY)EXBN4;|Ao)y4T4Y>n6#FiQafnI~uz$GRI92BKvt#L@kXZs5u6Mq4R6WfWv*wj>o|1?=!Im|XB9J&H~ z*VP-}lfJu|skTk63JDAk4X{mNnkHq32L=T}Y2zuCTUA50?>V)1wmF{3-%FneBqAY^ z1~L<#ws%ojAO_w{TzLAq%?XCM_w(i!s-U2t-MzinXZy9Z!;2IdTGQpC>) z`yF~vfUC@DXh@BWyjxagk}vDVlTc7!Q%#&d1D)Ico&DHE+wEV|)4gFtY;SCABr^wV z5GlfA1%vq1OLEcaDdNq7wwQR8+I_!&liF_;xv}>1CMpIUnl)DDhZT?#&1t5ydp)Xo z3Bs26S(g%M5vq>lc9I>mXLrh~QXvS2=pH`Aj_GRM7|quzHM)(8in{$x4&_pae(tIy z45$@v(^Bid%eFvHdv948WPbT#C@U7KKPTJ`z}_vMF6X08mFb-Cxedra!23NkXq+B> zd`Ci*yC2KT(%s#c00@ve1SPW5hEq`EyiRcEj;a-{r?OqMVc91FLD94{lC=38;*jEE zPLQG~^YZfG=o8@M&qvmoRUjLR3B49$EENV3kxo!Fz7-Y%k!slO@_O_rf`Dcvs#xTJ zE@dsw9F!3XSpP4Xnf~qVQX1pDnJ(CC9ro!QIM8KN0wym!m-iEeJ{pIBrhhDg=f4Pr=Izk#Cjcu;C@`QJIwn z#aGVV{Sgff4F~{TU0n`tEN)q4Rw0LLw23!4Qnq2y2H!C7@WcT53t|UI1dh^rJW>kd z7{xwAKdu|?_|ERA?yRpQHoxID;!9?(D!<&1Z<1G5{?$6()7`zczD~!&5(?r`na6<{ z5aB4c+R-DUti^ZB<&Q)0WB%k2BY~B%v2lu!3udME2U*4*YWcYC{QuzS>vB5j=9U%^ z3-`L1(|>`yBq8ww2lw~!@iAz>{iFFBweEZO0dFDc8kCBP3j5tZPpWNjY|19rsJWxr zR^twt6Q%7!GVThuFvo8|(VSn@Sji|T=vi6A4i670 zw22^Lzp2y)O&Rdk1F_LpPzEH;%$NW%XkAui8YltPHvewh=62}%dJacHMFlU2Y(K9q z&w&e8bsc@FB;(b3Uc=;%%$ zPl39*966bjy;1b~>gYvGKnEc-A~!#M`V5#}kSs4$C&-OQ~$=Zy;y-d`jiyg1>uEvanzSbUWX2u~taz5Z4O5vq`8lGP z)i|Y$9VpQyC6CltiI8~EMPXR>B>Ek)y(?DF=~0<%HU&a^or28VMlk|#-SBS(JxwU9 zA{Vxz=G9KwASf7I|9e z>7S)NcawmTkzA2d_mo35*~F&k^>(feHjnQa@!~qOooGBdImv~50g3m}vjGBc2>6lu zn%tn=IA~MH&u1q1)Xk*tQ7o)(tF&U}?AHVp}G zd&{&4sGHd%NAvfNR7%w1pz1kyq#uGNqg(43DCo3eztT$vrU4MzB)%#mg&+|5B9dxH zbEp=VeOxYMsyK>0T3*JX|%VaB&s7u3aAD~|lu1v^V z`bWLu*T5&YGKE$BYa^n*1d-H1%vAo=?BWi8f|fs#qRKc=a}+M$?vcv`Aye0+dh-z) zkVS58kE42(jQXs#ik{a5-|D2Qn-**xxXZs+ebUFIRCR~Q_E8r9LF&w?bz*$yzj{re z{>>iUi56BK6Z%oCq&p9J=Mx#d(i+w{=m7@{X_kD%?d5dh{m20--dy6NvKv7*f)BCm+O?B~Z{cii0?6+Z+3zN>Jv{(no@8Ht0M{|~J zs*p%;j$RmA-I#yU2;5Mwp;`Wi8x4s|A#XXa%;fHEwRaRMS z&)N44-!A)o35p;|pm{XP88(sp zvWyAeDC>555v74$0idIAopmv?iF8DWQwXCU*4GzDN{8L6%xNyjUm3OS5sFj_9&vOgr(x%*#88T?n>;m3$?JhrS}_(;MkYf8XhE^cF^UFRT8K^2O8Pp8w-*f!sX$h#1xv)s{88}Fl>TqI+}*E3#61hw?)ZdFmU}PFTnalQ z-HzfQ$i16^&2@1x0lSEG(kv z`B~&0hsZz$Zgf~b9g<4*n@*56N)TydOW6Tr2G$QJkn@eW6KzkE)bq1zYsvCQH-1^+ zZuI^Bi%0a3U#$5+ev_jBR1|&j>DFq#m2PV`E(@?xlxi1Z6R;DPNpw;Cw6(p=fV3!*tQsnDBZ7Vpa6b$i{H z$P*kAf^ob(BWG*N0R}Eg5%*|d36(W9*LunArhX>ryS{SXyDYrj8gz=tMx#rS%;#Ci zR>Pxypz|AZV9EY1w6>~RTHrszfT9UmlF$10+di`vqf&wL_NlT}NB&?-FAq~II{f{V z-~=>nUgOpt;;LqUK}uR^YaZ&?CjdQA-*A1%y)7^?*W?~MWX6sRI$nwGvDU+1BmA;b z5zZ|zyIs-{n0IJsC@3$&^*%-ZGb zBSv)q0|-u5VUHfa``D=L_vx5_?E_QG%!C{vbR5uU%TT}Wx~txo0C7=V?AKeBygxfT z15e7H$(sZ1*eQqcaaBB^2$eZ71~Dd8{x7 z*Zzxs>Rv&*-cF?YSy}}BegK})#(&MP(Fn}w$w_Ub?`y{PdKin9F$VsV$^LX$KY!Hm z?{BW8q@)_}Gj0?RUJs9tyVX;`;(#h35+cUU{S?R%@X-LbjRNkswT+GDfq?;w+nDpL z5QY2|IjL>7)r-r^%ZKAcMrCKGr{3G+RClAHiw92^nEH@N5d|51;H?8u;)S*KUj>p( z2wTfa-`6kujd;oRh|Px2+<21vzqdEeqRQ``g*dt5absSn(72G9c**+|=D#XG zcw=Xm`}ONP916ba{ilvhh?#!GPGb+4A^FzzEaByS_ot<0vOlv;8oVmK7gi$@0mcB>oz9}iT!z!`; zSur;g>^viCKlFFoGXYXU|$j{GD{)|}GLE4PCxd~!rAFp@R z`Jyg-cgh0V05arze}6s4`ho91U+okt=03|Gt@|qiXbvRd0mhDvwKZC9?oXf~$5YzX zUD<-X+}J1v{mD__+~yDqOr)EUr0d5IfdaN5CXP?@^RJzSQimgNkNZ}`>OfZwo?0M1;W03R7OHQK7|#>|_v!7!>_+mm zL0<_NCP@6yI4IW7#W)}b^=DGym27wAr4Q4hNTAjD7cklymEz&yJ#w%WIw!w4H~^QL z^8%B3S^sca8a1qc>yB$f+uC0%yrKq!adCq~&&$@GW62K3^_Vq;+fEMfR?W>%0YCGz zbO1YY@dsVp5X{M~ZEe7r$eNfiKu;f_ieLg#=lo=+1Kb(9y7J%wh6({@AjjjsT0mC* zE;SAwPO1h=!^J$V-ygfH6}!`)xV}H?TsAc;-r(CcUGf1MXHIi}AA+%JEj2Pc+>*#+ z{)qeoAu+KdxKI}s7iAO`SAakUYuql#PeRL@AVxrMJ~TUv^w1*dfxaLdiUfW;>Yc`O z4$#Y>G>1jwtv=)x5D}3FZcn?AI94`LyU=XDIj{o6Gmvt?qnjY?R-_u~A`A#-qRCJE z=g*%aMneILw*HFKnqLDg{7_-*dn1V@{2={I@=kcNNUlr8C&z^?pSa{ zQ~tSG7w6 zqTses_0&3WeCxUCIi;lzLy>S2TP7>5;5;EC4=kJ+3QEwdRsDIRzFcW9C3bF2j!2|TMT9niy>gKrqP;d`W{ov^Gmo=2=eT$q8a5Kh6+ z*x1Tv;~QWz!>6WJ1l}3Ul1Lvqa?OBRi=-0%R#4zPS!yc{9-m}B8?eN9E%f_vBOU1w zzer=Gudf*R^#CLZUJ4+G{P=O~@v$o~4M;O6kW-m8HNV%9>!|!yIT}_9e7j&2UjZ3M z1}t51)0GfNjZ92T zL0}k#ue^|zU055;gk&zbr8r^2y_ZRI8S-BPZ&y!G%Nt&>y()k#0)`t!gmIwNjq=X4|1B0Ez1Hvn3oJngwq?Odbfadk<*ObDp*!HuJ-7iHxgoWMb=Z}wziwkw= z1XVjXJ$JnLC!<^(9s$8q5H%rZBAvES4|DbX|04*LhTdTq7w55C^>kaO^#pG>6gnto z?n7wo?8I0|t}9#RrLwXFc-Fy%dT;Swzw`FA;E3hpaANk1qM}IHCISKi0f&WKwY9a7 z3U#HliXI8le8dT3erUb8|Co2>`nQUnn){B0zdHll!J2Lnw;(A06;AGo#0J1t{hk zL+*)jOlwXrLjEq;Q#%I+n1zHU*T?_Bx8S@4Vv&G*oOh2pP26wxKj--oaFAfo|DK-@ z8S(D?{Jdfl8myH0Kw29JT@a;UT$NK-AG6Wh;lM#&&lwJWsLL3D*Gxx1s~VwQ=sM-B zN+zoujkG6{JjfR7J(PXQk7O?r$4?l5>1 zKA-@bR^qrU3v@lkojb1~AiBF{VWZqP3#&n)LmK)40gz&oVx#e22Mq^TNKC^%CIR6G zuJyIGHA8p;Y|g+pgVc$z2n~loh1)p5716@iK!h3|AD4D;;Ck}p$^YKYaB|{-gHxbW zz0EUTir;+iHX2%nN*>%Df%rxCb`Z?q5r^D4zqshsGBN}%J2Z53Nc{}pGKb_0Oj0ML z0RUG2{&~W6k8oJ_-T9VpqZ=}b%_8@@9zNtpT=l}u08?*o%H%#N5UMc)jf}|bQx&Bp zCEHqK=79+XO<`eYCkiCY>S{Nm+K;od`oLb3QBg^PFyz1V4#?D zE)5JE=gi7q>ga?64&&gkHCq1wL@?O9Nhv8?Ei2)QNT5_^q9!Z&P4LLb)~n`h>OP_* z-YigOgVr80C6x4;y4`fVw2a(b^ZUBUk9z$P;M+kSUG5N$|DIsDbw+vrzkeg3{l5>_ axaTum$~Ph$Y~W%bij1V<^P;DQ@Bare(!(bJ diff --git a/docs/src/auto_examples/tutorials/run_annoy.ipynb b/docs/src/auto_examples/tutorials/run_annoy.ipynb index 2c845e5115..2907a09934 100644 --- a/docs/src/auto_examples/tutorials/run_annoy.ipynb +++ b/docs/src/auto_examples/tutorials/run_annoy.ipynb @@ -15,7 +15,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "\nSimilarity Queries with Annoy and Word2Vec\n==========================================\n\nIntroduces the annoy library for similarity queries using a Word2Vec model.\n" + "\nFast Similarity Queries with Annoy and Word2Vec\n===============================================\n\nIntroduces the annoy library for similarity queries using a Word2Vec model.\n\n" ] }, { @@ -26,14 +26,14 @@ }, "outputs": [], "source": [ - "LOGS = False\nif LOGS:\n import logging\n logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)" + "LOGS = False # Set to True if you want to see progress in logs.\nif LOGS:\n import logging\n logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The `Annoy Approximate Nearest Neighbors Oh Yeah\n`_ library enables similarity queries with\na Word2Vec model. The current implementation for finding k nearest neighbors\nin a vector space in gensim has linear complexity via brute force in the\nnumber of indexed documents, although with extremely low constant factors.\nThe retrieved results are exact, which is an overkill in many applications:\napproximate results retrieved in sub-linear time may be enough. Annoy can\nfind approximate nearest neighbors much faster.\n\nOutline\n-------\n\n1. Download Text8 Corpus\n2. Train the Word2Vec model\n3. Construct AnnoyIndex with model & make a similarity query\n4. Compare to the traditional indexer\n5. Persist indices to disk\n6. Save memory by via memory-mapping indices saved to disk\n7. Evaluate relationship of ``num_trees`` to initialization time and accuracy\n8. Work with Google's word2vec C formats\n\n\n" + "The `Annoy \"Approximate Nearest Neighbors Oh Yeah\"\n`_ library enables similarity queries with\na Word2Vec model. The current implementation for finding k nearest neighbors\nin a vector space in gensim has linear complexity via brute force in the\nnumber of indexed documents, although with extremely low constant factors.\nThe retrieved results are exact, which is an overkill in many applications:\napproximate results retrieved in sub-linear time may be enough. Annoy can\nfind approximate nearest neighbors much faster.\n\nOutline\n-------\n\n1. Download Text8 Corpus\n2. Train the Word2Vec model\n3. Construct AnnoyIndex with model & make a similarity query\n4. Compare to the traditional indexer\n5. Persist indices to disk\n6. Save memory by via memory-mapping indices saved to disk\n7. Evaluate relationship of ``num_trees`` to initialization time and accuracy\n8. Work with Google's word2vec C formats\n\n\n" ] }, { @@ -51,7 +51,7 @@ }, "outputs": [], "source": [ - "import gensim.downloader as api\ntext8_path = api.load('text8', return_path=True)\ntext8_path" + "import gensim.downloader as api\ntext8_path = api.load('text8', return_path=True)\nprint(\"Using corpus from\", text8_path)" ] }, { @@ -69,14 +69,14 @@ }, "outputs": [], "source": [ - "from gensim.models import Word2Vec, KeyedVectors\nfrom gensim.models.word2vec import Text8Corpus\n\n# Using params from Word2Vec_FastText_Comparison\nparams = {\n 'alpha': 0.05,\n 'size': 100,\n 'window': 5,\n 'iter': 5,\n 'min_count': 5,\n 'sample': 1e-4,\n 'sg': 1,\n 'hs': 0,\n 'negative': 5\n}\nmodel = Word2Vec(Text8Corpus(text8_path), **params)\nprint(model)" + "from gensim.models import Word2Vec, KeyedVectors\nfrom gensim.models.word2vec import Text8Corpus\n\n# Using params from Word2Vec_FastText_Comparison\nparams = {\n 'alpha': 0.05,\n 'vector_size': 100,\n 'window': 5,\n 'epochs': 5,\n 'min_count': 5,\n 'sample': 1e-4,\n 'sg': 1,\n 'hs': 0,\n 'negative': 5\n}\nmodel = Word2Vec(Text8Corpus(text8_path), **params)\nprint(\"Using model\", model)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "3. Construct AnnoyIndex with model & make a similarity query\n------------------------------------------------------------\n\nAn instance of ``AnnoyIndexer`` needs to be created in order to use Annoy in gensim. The ``AnnoyIndexer`` class is located in ``gensim.similarities.index``\n\n``AnnoyIndexer()`` takes two parameters:\n\n* **model**: A ``Word2Vec`` or ``Doc2Vec`` model\n* **num_trees**: A positive integer. ``num_trees`` effects the build\n time and the index size. **A larger value will give more accurate results,\n but larger indexes**. More information on what trees in Annoy do can be found\n `here `__. The relationship\n between ``num_trees``\\ , build time, and accuracy will be investigated later\n in the tutorial. \n\nNow that we are ready to make a query, lets find the top 5 most similar words\nto \"science\" in the Text8 corpus. To make a similarity query we call\n``Word2Vec.most_similar`` like we would traditionally, but with an added\nparameter, ``indexer``. The only supported indexer in gensim as of now is\nAnnoy. \n\n\n" + "3. Construct AnnoyIndex with model & make a similarity query\n------------------------------------------------------------\n\nAn instance of ``AnnoyIndexer`` needs to be created in order to use Annoy in gensim. The ``AnnoyIndexer`` class is located in ``gensim.similarities.annoy``.\n\n``AnnoyIndexer()`` takes two parameters:\n\n* **model**: A ``Word2Vec`` or ``Doc2Vec`` model.\n* **num_trees**: A positive integer. ``num_trees`` effects the build\n time and the index size. **A larger value will give more accurate results,\n but larger indexes**. More information on what trees in Annoy do can be found\n `here `__. The relationship\n between ``num_trees``\\ , build time, and accuracy will be investigated later\n in the tutorial.\n\nNow that we are ready to make a query, lets find the top 5 most similar words\nto \"science\" in the Text8 corpus. To make a similarity query we call\n``Word2Vec.most_similar`` like we would traditionally, but with an added\nparameter, ``indexer``.\n\nApart from Annoy, Gensim also supports the NMSLIB indexer. NMSLIB is a similar library to\nAnnoy \u2013 both support fast, approximate searches for similar vectors.\n\n\n" ] }, { @@ -87,7 +87,7 @@ }, "outputs": [], "source": [ - "from gensim.similarities.index import AnnoyIndexer\n\n# 100 trees are being used in this example\nannoy_index = AnnoyIndexer(model, 100)\n# Derive the vector for the word \"science\" in our model\nvector = model.wv[\"science\"]\n# The instance of AnnoyIndexer we just created is passed \napproximate_neighbors = model.wv.most_similar([vector], topn=11, indexer=annoy_index)\n# Neatly print the approximate_neighbors and their corresponding cosine similarity values\nprint(\"Approximate Neighbors\")\nfor neighbor in approximate_neighbors:\n print(neighbor)\n\nnormal_neighbors = model.wv.most_similar([vector], topn=11)\nprint(\"\\nNormal (not Annoy-indexed) Neighbors\")\nfor neighbor in normal_neighbors:\n print(neighbor)" + "from gensim.similarities.annoy import AnnoyIndexer\n\n# 100 trees are being used in this example\nannoy_index = AnnoyIndexer(model, 100)\n# Derive the vector for the word \"science\" in our model\nvector = model.wv[\"science\"]\n# The instance of AnnoyIndexer we just created is passed\napproximate_neighbors = model.wv.most_similar([vector], topn=11, indexer=annoy_index)\n# Neatly print the approximate_neighbors and their corresponding cosine similarity values\nprint(\"Approximate Neighbors\")\nfor neighbor in approximate_neighbors:\n print(neighbor)\n\nnormal_neighbors = model.wv.most_similar([vector], topn=11)\nprint(\"\\nExact Neighbors\")\nfor neighbor in normal_neighbors:\n print(neighbor)" ] }, { @@ -112,7 +112,7 @@ }, "outputs": [], "source": [ - "# Set up the model and vector that we are using in the comparison\nmodel.init_sims()\nannoy_index = AnnoyIndexer(model, 100)\n\n# Dry run to make sure both indices are fully in RAM\nvector = model.wv.vectors_norm[0]\nmodel.wv.most_similar([vector], topn=5, indexer=annoy_index)\nmodel.wv.most_similar([vector], topn=5)\n\nimport time\nimport numpy as np\n\ndef avg_query_time(annoy_index=None, queries=1000):\n \"\"\"\n Average query time of a most_similar method over 1000 random queries,\n uses annoy if given an indexer\n \"\"\"\n total_time = 0\n for _ in range(queries):\n rand_vec = model.wv.vectors_norm[np.random.randint(0, len(model.wv.vocab))]\n start_time = time.process_time()\n model.wv.most_similar([rand_vec], topn=5, indexer=annoy_index)\n total_time += time.process_time() - start_time\n return total_time / queries\n\nqueries = 10000\n\ngensim_time = avg_query_time(queries=queries)\nannoy_time = avg_query_time(annoy_index, queries=queries)\nprint(\"Gensim (s/query):\\t{0:.5f}\".format(gensim_time))\nprint(\"Annoy (s/query):\\t{0:.5f}\".format(annoy_time))\nspeed_improvement = gensim_time / annoy_time\nprint (\"\\nAnnoy is {0:.2f} times faster on average on this particular run\".format(speed_improvement))" + "# Set up the model and vector that we are using in the comparison\nmodel.init_sims()\nannoy_index = AnnoyIndexer(model, 100)\n\n# Dry run to make sure both indexes are fully in RAM\nvector = model.wv.vectors_norm[0]\nmodel.wv.most_similar([vector], topn=5, indexer=annoy_index)\nmodel.wv.most_similar([vector], topn=5)\n\nimport time\nimport numpy as np\n\ndef avg_query_time(annoy_index=None, queries=1000):\n \"\"\"Average query time of a most_similar method over 1000 random queries.\"\"\"\n total_time = 0\n for _ in range(queries):\n rand_vec = model.wv.vectors_norm[np.random.randint(0, len(model.wv))]\n start_time = time.process_time()\n model.wv.most_similar([rand_vec], topn=5, indexer=annoy_index)\n total_time += time.process_time() - start_time\n return total_time / queries\n\nqueries = 1000\n\ngensim_time = avg_query_time(queries=queries)\nannoy_time = avg_query_time(annoy_index, queries=queries)\nprint(\"Gensim (s/query):\\t{0:.5f}\".format(gensim_time))\nprint(\"Annoy (s/query):\\t{0:.5f}\".format(annoy_time))\nspeed_improvement = gensim_time / annoy_time\nprint (\"\\nAnnoy is {0:.2f} times faster on average on this particular run\".format(speed_improvement))" ] }, { @@ -137,7 +137,7 @@ }, "outputs": [], "source": [ - "fname = '/tmp/mymodel.index'\n\n# Persist index to disk\nannoy_index.save(fname)\n\n# Load index back\nimport os.path\nif os.path.exists(fname):\n annoy_index2 = AnnoyIndexer()\n annoy_index2.load(fname)\n annoy_index2.model = model\n\n# Results should be identical to above\nvector = model.wv[\"science\"]\napproximate_neighbors2 = model.wv.most_similar([vector], topn=11, indexer=annoy_index2)\nfor neighbor in approximate_neighbors2:\n print(neighbor)\n \nassert approximate_neighbors == approximate_neighbors2" + "fname = '/tmp/mymodel.index'\n\n# Persist index to disk\nannoy_index.save(fname)\n\n# Load index back\nimport os.path\nif os.path.exists(fname):\n annoy_index2 = AnnoyIndexer()\n annoy_index2.load(fname)\n annoy_index2.model = model\n\n# Results should be identical to above\nvector = model.wv[\"science\"]\napproximate_neighbors2 = model.wv.most_similar([vector], topn=11, indexer=annoy_index2)\nfor neighbor in approximate_neighbors2:\n print(neighbor)\n\nassert approximate_neighbors == approximate_neighbors2" ] }, { @@ -151,7 +151,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "6. Save memory via memory-mapping indices saved to disk\n-------------------------------------------------------\n\nAnnoy library has a useful feature that indices can be memory-mapped from\ndisk. It saves memory when the same index is used by several processes.\n\nBelow are two snippets of code. First one has a separate index for each\nprocess. The second snipped shares the index between two processes via\nmemory-mapping. The second example uses less total RAM as it is shared.\n\n\n" + "6. Save memory via memory-mapping indexes saved to disk\n-------------------------------------------------------\n\nAnnoy library has a useful feature that indices can be memory-mapped from\ndisk. It saves memory when the same index is used by several processes.\n\nBelow are two snippets of code. First one has a separate index for each\nprocess. The second snipped shares the index between two processes via\nmemory-mapping. The second example uses less total RAM as it is shared.\n\n\n" ] }, { @@ -169,7 +169,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Bad example: two processes load the Word2vec model from disk and create there\nown Annoy indices from that model.\n\n\n" + "Bad example: two processes load the Word2vec model from disk and create their\nown Annoy index from that model.\n\n\n" ] }, { @@ -187,7 +187,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Good example: two processes load both the Word2vec model and index from disk\nand memory-map the index\n\n\n" + "Good example: two processes load both the Word2vec model and index from disk\nand memory-map the index.\n\n\n" ] }, { @@ -259,7 +259,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "From the above, we can see that the initialization time of the annoy indexer\nincreases in a linear fashion with num_trees. Initialization time will vary\nfrom corpus to corpus, in the graph above the lee corpus was used\n\nFurthermore, in this dataset, the accuracy seems logarithmically related to\nthe number of trees. We see an improvement in accuracy with more trees, but\nthe relationship is nonlinear. \n\n\n" + "From the above, we can see that the initialization time of the annoy indexer\nincreases in a linear fashion with num_trees. Initialization time will vary\nfrom corpus to corpus, in the graph above the lee corpus was used\n\nFurthermore, in this dataset, the accuracy seems logarithmically related to\nthe number of trees. We see an improvement in accuracy with more trees, but\nthe relationship is nonlinear.\n\n\n" ] }, { @@ -277,7 +277,7 @@ }, "outputs": [], "source": [ - "# To export our model as text\nmodel.wv.save_word2vec_format('/tmp/vectors.txt', binary=False)\n\nfrom smart_open import open\n# View the first 3 lines of the exported file\n\n# The first line has the total number of entries and the vector dimension count. \n# The next lines have a key (a string) followed by its vector.\nwith open('/tmp/vectors.txt') as myfile:\n for i in range(3):\n print(myfile.readline().strip())\n\n# To import a word2vec text model\nwv = KeyedVectors.load_word2vec_format('/tmp/vectors.txt', binary=False)\n\n# To export our model as binary\nmodel.wv.save_word2vec_format('/tmp/vectors.bin', binary=True)\n\n# To import a word2vec binary model\nwv = KeyedVectors.load_word2vec_format('/tmp/vectors.bin', binary=True)\n\n# To create and save Annoy Index from a loaded `KeyedVectors` object (with 100 trees)\nannoy_index = AnnoyIndexer(wv, 100)\nannoy_index.save('/tmp/mymodel.index')\n\n# Load and test the saved word vectors and saved annoy index\nwv = KeyedVectors.load_word2vec_format('/tmp/vectors.bin', binary=True)\nannoy_index = AnnoyIndexer()\nannoy_index.load('/tmp/mymodel.index')\nannoy_index.model = wv\n\nvector = wv[\"cat\"]\napproximate_neighbors = wv.most_similar([vector], topn=11, indexer=annoy_index)\n# Neatly print the approximate_neighbors and their corresponding cosine similarity values\nprint(\"Approximate Neighbors\")\nfor neighbor in approximate_neighbors:\n print(neighbor)\n\nnormal_neighbors = wv.most_similar([vector], topn=11)\nprint(\"\\nNormal (not Annoy-indexed) Neighbors\")\nfor neighbor in normal_neighbors:\n print(neighbor)" + "# To export our model as text\nmodel.wv.save_word2vec_format('/tmp/vectors.txt', binary=False)\n\nfrom smart_open import open\n# View the first 3 lines of the exported file\n\n# The first line has the total number of entries and the vector dimension count.\n# The next lines have a key (a string) followed by its vector.\nwith open('/tmp/vectors.txt') as myfile:\n for i in range(3):\n print(myfile.readline().strip())\n\n# To import a word2vec text model\nwv = KeyedVectors.load_word2vec_format('/tmp/vectors.txt', binary=False)\n\n# To export our model as binary\nmodel.wv.save_word2vec_format('/tmp/vectors.bin', binary=True)\n\n# To import a word2vec binary model\nwv = KeyedVectors.load_word2vec_format('/tmp/vectors.bin', binary=True)\n\n# To create and save Annoy Index from a loaded `KeyedVectors` object (with 100 trees)\nannoy_index = AnnoyIndexer(wv, 100)\nannoy_index.save('/tmp/mymodel.index')\n\n# Load and test the saved word vectors and saved annoy index\nwv = KeyedVectors.load_word2vec_format('/tmp/vectors.bin', binary=True)\nannoy_index = AnnoyIndexer()\nannoy_index.load('/tmp/mymodel.index')\nannoy_index.model = wv\n\nvector = wv[\"cat\"]\napproximate_neighbors = wv.most_similar([vector], topn=11, indexer=annoy_index)\n# Neatly print the approximate_neighbors and their corresponding cosine similarity values\nprint(\"Approximate Neighbors\")\nfor neighbor in approximate_neighbors:\n print(neighbor)\n\nnormal_neighbors = wv.most_similar([vector], topn=11)\nprint(\"\\nExact Neighbors\")\nfor neighbor in normal_neighbors:\n print(neighbor)" ] }, { @@ -304,7 +304,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.1" + "version": "3.6.5" } }, "nbformat": 4, diff --git a/docs/src/auto_examples/tutorials/run_annoy.py b/docs/src/auto_examples/tutorials/run_annoy.py index 76aef05788..a2feca72a7 100644 --- a/docs/src/auto_examples/tutorials/run_annoy.py +++ b/docs/src/auto_examples/tutorials/run_annoy.py @@ -1,17 +1,17 @@ r""" -Similarity Queries with Annoy and Word2Vec -========================================== +Fast Similarity Queries with Annoy and Word2Vec +=============================================== Introduces the annoy library for similarity queries using a Word2Vec model. """ -LOGS = False +LOGS = False # Set to True if you want to see progress in logs. if LOGS: import logging logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO) ############################################################################### -# The `Annoy Approximate Nearest Neighbors Oh Yeah +# The `Annoy "Approximate Nearest Neighbors Oh Yeah" # `_ library enables similarity queries with # a Word2Vec model. The current implementation for finding k nearest neighbors # in a vector space in gensim has linear complexity via brute force in the @@ -19,10 +19,10 @@ # The retrieved results are exact, which is an overkill in many applications: # approximate results retrieved in sub-linear time may be enough. Annoy can # find approximate nearest neighbors much faster. -# +# # Outline # ------- -# +# # 1. Download Text8 Corpus # 2. Train the Word2Vec model # 3. Construct AnnoyIndex with model & make a similarity query @@ -31,14 +31,14 @@ # 6. Save memory by via memory-mapping indices saved to disk # 7. Evaluate relationship of ``num_trees`` to initialization time and accuracy # 8. Work with Google's word2vec C formats -# +# ############################################################################### # 1. Download Text8 corpus # ------------------------ import gensim.downloader as api text8_path = api.load('text8', return_path=True) -text8_path +print("Using corpus from", text8_path) ############################################################################### # 2. Train the Word2Vec model @@ -51,9 +51,9 @@ # Using params from Word2Vec_FastText_Comparison params = { 'alpha': 0.05, - 'size': 100, + 'vector_size': 100, 'window': 5, - 'iter': 5, + 'epochs': 5, 'min_count': 5, 'sample': 1e-4, 'sg': 1, @@ -61,37 +61,39 @@ 'negative': 5 } model = Word2Vec(Text8Corpus(text8_path), **params) -print(model) +print("Using model", model) ############################################################################### # 3. Construct AnnoyIndex with model & make a similarity query # ------------------------------------------------------------ -# -# An instance of ``AnnoyIndexer`` needs to be created in order to use Annoy in gensim. The ``AnnoyIndexer`` class is located in ``gensim.similarities.index`` -# +# +# An instance of ``AnnoyIndexer`` needs to be created in order to use Annoy in gensim. The ``AnnoyIndexer`` class is located in ``gensim.similarities.annoy``. +# # ``AnnoyIndexer()`` takes two parameters: -# -# * **model**: A ``Word2Vec`` or ``Doc2Vec`` model +# +# * **model**: A ``Word2Vec`` or ``Doc2Vec`` model. # * **num_trees**: A positive integer. ``num_trees`` effects the build # time and the index size. **A larger value will give more accurate results, # but larger indexes**. More information on what trees in Annoy do can be found # `here `__. The relationship # between ``num_trees``\ , build time, and accuracy will be investigated later -# in the tutorial. -# +# in the tutorial. +# # Now that we are ready to make a query, lets find the top 5 most similar words # to "science" in the Text8 corpus. To make a similarity query we call # ``Word2Vec.most_similar`` like we would traditionally, but with an added -# parameter, ``indexer``. The only supported indexer in gensim as of now is -# Annoy. -# -from gensim.similarities.index import AnnoyIndexer +# parameter, ``indexer``. +# +# Apart from Annoy, Gensim also supports the NMSLIB indexer. NMSLIB is a similar library to +# Annoy – both support fast, approximate searches for similar vectors. +# +from gensim.similarities.annoy import AnnoyIndexer # 100 trees are being used in this example annoy_index = AnnoyIndexer(model, 100) # Derive the vector for the word "science" in our model vector = model.wv["science"] -# The instance of AnnoyIndexer we just created is passed +# The instance of AnnoyIndexer we just created is passed approximate_neighbors = model.wv.most_similar([vector], topn=11, indexer=annoy_index) # Neatly print the approximate_neighbors and their corresponding cosine similarity values print("Approximate Neighbors") @@ -99,7 +101,7 @@ print(neighbor) normal_neighbors = model.wv.most_similar([vector], topn=11) -print("\nNormal (not Annoy-indexed) Neighbors") +print("\nExact Neighbors") for neighbor in normal_neighbors: print(neighbor) @@ -117,7 +119,7 @@ model.init_sims() annoy_index = AnnoyIndexer(model, 100) -# Dry run to make sure both indices are fully in RAM +# Dry run to make sure both indexes are fully in RAM vector = model.wv.vectors_norm[0] model.wv.most_similar([vector], topn=5, indexer=annoy_index) model.wv.most_similar([vector], topn=5) @@ -126,19 +128,16 @@ import numpy as np def avg_query_time(annoy_index=None, queries=1000): - """ - Average query time of a most_similar method over 1000 random queries, - uses annoy if given an indexer - """ + """Average query time of a most_similar method over 1000 random queries.""" total_time = 0 for _ in range(queries): - rand_vec = model.wv.vectors_norm[np.random.randint(0, len(model.wv.vocab))] + rand_vec = model.wv.vectors_norm[np.random.randint(0, len(model.wv))] start_time = time.process_time() model.wv.most_similar([rand_vec], topn=5, indexer=annoy_index) total_time += time.process_time() - start_time return total_time / queries -queries = 10000 +queries = 1000 gensim_time = avg_query_time(queries=queries) annoy_time = avg_query_time(annoy_index, queries=queries) @@ -152,7 +151,7 @@ def avg_query_time(annoy_index=None, queries=1000): # run to run and is particular to this data set, BLAS setup, Annoy # parameters(as tree size increases speedup factor decreases), machine # specifications, among other factors. -# +# # .. Important:: # Initialization time for the annoy indexer was not included in the times. # The optimal knn algorithm for you to use will depend on how many queries @@ -162,7 +161,7 @@ def avg_query_time(annoy_index=None, queries=1000): # results. If you are making many queries however, the time it takes to # initialize the annoy indexer will be made up for by the incredibly fast # retrieval times for queries once the indexer has been initialized -# +# # .. Important:: # Gensim's 'most_similar' method is using numpy operations in the form of # dot product whereas Annoy's method isnt. If 'numpy' on your machine is @@ -171,17 +170,17 @@ def avg_query_time(annoy_index=None, queries=1000): # Cookbook # `_ # for more details. -# +# ############################################################################### # 5. Persisting indices to disk # ----------------------------- -# +# # You can save and load your indexes from/to disk to prevent having to # construct them each time. This will create two files on disk, *fname* and # *fname.d*. Both files are needed to correctly restore all attributes. Before # loading an index, you will have to create an empty AnnoyIndexer object. -# +# fname = '/tmp/mymodel.index' # Persist index to disk @@ -199,25 +198,25 @@ def avg_query_time(annoy_index=None, queries=1000): approximate_neighbors2 = model.wv.most_similar([vector], topn=11, indexer=annoy_index2) for neighbor in approximate_neighbors2: print(neighbor) - + assert approximate_neighbors == approximate_neighbors2 ############################################################################### # Be sure to use the same model at load that was used originally, otherwise you # will get unexpected behaviors. -# +# ############################################################################### -# 6. Save memory via memory-mapping indices saved to disk +# 6. Save memory via memory-mapping indexes saved to disk # ------------------------------------------------------- -# +# # Annoy library has a useful feature that indices can be memory-mapped from # disk. It saves memory when the same index is used by several processes. -# +# # Below are two snippets of code. First one has a separate index for each # process. The second snipped shares the index between two processes via # memory-mapping. The second example uses less total RAM as it is shared. -# +# # Remove verbosity from code below (if logging active) if LOGS: @@ -228,9 +227,9 @@ def avg_query_time(annoy_index=None, queries=1000): import psutil ############################################################################### -# Bad example: two processes load the Word2vec model from disk and create there -# own Annoy indices from that model. -# +# Bad example: two processes load the Word2vec model from disk and create their +# own Annoy index from that model. +# model.save('/tmp/mymodel.pkl') @@ -253,8 +252,8 @@ def f(process_id): ############################################################################### # Good example: two processes load both the Word2vec model and index from disk -# and memory-map the index -# +# and memory-map the index. +# model.save('/tmp/mymodel.pkl') @@ -280,12 +279,12 @@ def f(process_id): ############################################################################### # 7. Evaluate relationship of ``num_trees`` to initialization time and accuracy # ----------------------------------------------------------------------------- -# +# import matplotlib.pyplot as plt ############################################################################### # Build dataset of Initialization times and accuracy measures: -# +# exact_results = [element[0] for element in model.wv.most_similar([model.wv.vectors_norm[0]], topn=100)] @@ -323,20 +322,20 @@ def f(process_id): # From the above, we can see that the initialization time of the annoy indexer # increases in a linear fashion with num_trees. Initialization time will vary # from corpus to corpus, in the graph above the lee corpus was used -# +# # Furthermore, in this dataset, the accuracy seems logarithmically related to # the number of trees. We see an improvement in accuracy with more trees, but -# the relationship is nonlinear. -# +# the relationship is nonlinear. +# ############################################################################### # 7. Work with Google word2vec files # ---------------------------------- -# +# # Our model can be exported to a word2vec C format. There is a binary and a # plain text word2vec format. Both can be read with a variety of other # software, or imported back into gensim as a ``KeyedVectors`` object. -# +# # To export our model as text model.wv.save_word2vec_format('/tmp/vectors.txt', binary=False) @@ -344,7 +343,7 @@ def f(process_id): from smart_open import open # View the first 3 lines of the exported file -# The first line has the total number of entries and the vector dimension count. +# The first line has the total number of entries and the vector dimension count. # The next lines have a key (a string) followed by its vector. with open('/tmp/vectors.txt') as myfile: for i in range(3): @@ -377,17 +376,17 @@ def f(process_id): print(neighbor) normal_neighbors = wv.most_similar([vector], topn=11) -print("\nNormal (not Annoy-indexed) Neighbors") +print("\nExact Neighbors") for neighbor in normal_neighbors: print(neighbor) ############################################################################### # Recap # ----- -# +# # In this notebook we used the Annoy module to build an indexed approximation # of our word embeddings. To do so, we did the following steps: -# +# # 1. Download Text8 Corpus # 2. Train Word2Vec Model # 3. Construct AnnoyIndex with model & make a similarity query @@ -395,4 +394,4 @@ def f(process_id): # 5. Save memory by via memory-mapping indices saved to disk # 6. Evaluate relationship of ``num_trees`` to initialization time and accuracy # 7. Work with Google's word2vec C formats -# +# diff --git a/docs/src/auto_examples/tutorials/run_annoy.py.md5 b/docs/src/auto_examples/tutorials/run_annoy.py.md5 index 12698c89db..d8f5d208ca 100644 --- a/docs/src/auto_examples/tutorials/run_annoy.py.md5 +++ b/docs/src/auto_examples/tutorials/run_annoy.py.md5 @@ -1 +1 @@ -2309f2c10b619eda67d7d6611a881441 \ No newline at end of file +a18f2e2cf524dea755eb70bb385bf7fe \ No newline at end of file diff --git a/docs/src/auto_examples/tutorials/run_annoy.rst b/docs/src/auto_examples/tutorials/run_annoy.rst index fbb3c1536f..424c21bda0 100644 --- a/docs/src/auto_examples/tutorials/run_annoy.rst +++ b/docs/src/auto_examples/tutorials/run_annoy.rst @@ -7,15 +7,16 @@ .. _sphx_glr_auto_examples_tutorials_run_annoy.py: -Similarity Queries with Annoy and Word2Vec -========================================== +Fast Similarity Queries with Annoy and Word2Vec +=============================================== Introduces the annoy library for similarity queries using a Word2Vec model. + .. code-block:: default - LOGS = False + LOGS = False # Set to True if you want to see progress in logs. if LOGS: import logging logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO) @@ -26,7 +27,7 @@ Introduces the annoy library for similarity queries using a Word2Vec model. -The `Annoy Approximate Nearest Neighbors Oh Yeah +The `Annoy "Approximate Nearest Neighbors Oh Yeah" `_ library enables similarity queries with a Word2Vec model. The current implementation for finding k nearest neighbors in a vector space in gensim has linear complexity via brute force in the @@ -56,11 +57,19 @@ Outline import gensim.downloader as api text8_path = api.load('text8', return_path=True) - text8_path + print("Using corpus from", text8_path) + +.. rst-class:: sphx-glr-script-out + + Out: + + .. code-block:: none + + Using corpus from /Users/kofola3/gensim-data/text8/text8.gz @@ -78,9 +87,9 @@ For more details, see :ref:`sphx_glr_auto_examples_tutorials_run_word2vec.py`. # Using params from Word2Vec_FastText_Comparison params = { 'alpha': 0.05, - 'size': 100, + 'vector_size': 100, 'window': 5, - 'iter': 5, + 'epochs': 5, 'min_count': 5, 'sample': 1e-4, 'sg': 1, @@ -88,7 +97,7 @@ For more details, see :ref:`sphx_glr_auto_examples_tutorials_run_word2vec.py`. 'negative': 5 } model = Word2Vec(Text8Corpus(text8_path), **params) - print(model) + print("Using model", model) @@ -100,41 +109,44 @@ For more details, see :ref:`sphx_glr_auto_examples_tutorials_run_word2vec.py`. .. code-block:: none - Word2Vec(vocab=71290, size=100, alpha=0.05) + Using model Word2Vec(vocab=71290, size=100, alpha=0.05) + 3. Construct AnnoyIndex with model & make a similarity query ------------------------------------------------------------ -An instance of ``AnnoyIndexer`` needs to be created in order to use Annoy in gensim. The ``AnnoyIndexer`` class is located in ``gensim.similarities.index`` +An instance of ``AnnoyIndexer`` needs to be created in order to use Annoy in gensim. The ``AnnoyIndexer`` class is located in ``gensim.similarities.annoy``. ``AnnoyIndexer()`` takes two parameters: -* **model**: A ``Word2Vec`` or ``Doc2Vec`` model +* **model**: A ``Word2Vec`` or ``Doc2Vec`` model. * **num_trees**: A positive integer. ``num_trees`` effects the build time and the index size. **A larger value will give more accurate results, but larger indexes**. More information on what trees in Annoy do can be found `here `__. The relationship between ``num_trees``\ , build time, and accuracy will be investigated later - in the tutorial. + in the tutorial. Now that we are ready to make a query, lets find the top 5 most similar words to "science" in the Text8 corpus. To make a similarity query we call ``Word2Vec.most_similar`` like we would traditionally, but with an added -parameter, ``indexer``. The only supported indexer in gensim as of now is -Annoy. +parameter, ``indexer``. + +Apart from Annoy, Gensim also supports the NMSLIB indexer. NMSLIB is a similar library to +Annoy – both support fast, approximate searches for similar vectors. .. code-block:: default - from gensim.similarities.index import AnnoyIndexer + from gensim.similarities.annoy import AnnoyIndexer # 100 trees are being used in this example annoy_index = AnnoyIndexer(model, 100) # Derive the vector for the word "science" in our model vector = model.wv["science"] - # The instance of AnnoyIndexer we just created is passed + # The instance of AnnoyIndexer we just created is passed approximate_neighbors = model.wv.most_similar([vector], topn=11, indexer=annoy_index) # Neatly print the approximate_neighbors and their corresponding cosine similarity values print("Approximate Neighbors") @@ -142,7 +154,7 @@ Annoy. print(neighbor) normal_neighbors = model.wv.most_similar([vector], topn=11) - print("\nNormal (not Annoy-indexed) Neighbors") + print("\nExact Neighbors") for neighbor in normal_neighbors: print(neighbor) @@ -157,30 +169,31 @@ Annoy. .. code-block:: none Approximate Neighbors + ('science', 0.9998779296875) + ('actuarial', 0.5997203588485718) + ('multidisciplinary', 0.5991933047771454) + ('sciences', 0.5958340764045715) + ('scientific', 0.5955467224121094) + ('astrobiology', 0.5923857390880585) + ('popularizer', 0.5910311937332153) + ('nanomedicine', 0.5902301669120789) + ('astronautics', 0.5890269577503204) + ('poststructuralism', 0.5872606933116913) + ('crichton', 0.5863060653209686) + + Exact Neighbors ('science', 1.0) - ('astrobiology', 0.5924032926559448) - ('transhumanist', 0.5916061401367188) - ('bimonthly', 0.5861886739730835) - ('sciences', 0.5851120948791504) - ('robotics', 0.5844891369342804) - ('nanomedicine', 0.5836333632469177) - ('protoscience', 0.5796476304531097) - ('biostatistics', 0.5791448056697845) - ('astronautics', 0.5787959098815918) - ('scientific', 0.5772265493869781) - - Normal (not Annoy-indexed) Neighbors - ('science', 1.0) - ('fiction', 0.7320358157157898) - ('popularizer', 0.6709892153739929) - ('astrobiology', 0.6677298545837402) - ('transhumanist', 0.6664289236068726) - ('technology', 0.660341739654541) - ('bimonthly', 0.6575203537940979) - ('sciences', 0.655735969543457) - ('multidisciplinary', 0.6556889414787292) - ('robotics', 0.6547014713287354) - ('nanomedicine', 0.6532777547836304) + ('fiction', 0.7604568004608154) + ('actuarial', 0.679552435874939) + ('multidisciplinary', 0.678708016872406) + ('sciences', 0.6732996702194214) + ('scientific', 0.672835111618042) + ('astrobiology', 0.6677011847496033) + ('popularizer', 0.6654890179634094) + ('nanomedicine', 0.6641773581504822) + ('astronautics', 0.6622022986412048) + ('poststructuralism', 0.6592925786972046) + The closer the cosine similarity of a vector is to 1, the more similar that @@ -199,7 +212,7 @@ within the 10 most similar words. model.init_sims() annoy_index = AnnoyIndexer(model, 100) - # Dry run to make sure both indices are fully in RAM + # Dry run to make sure both indexes are fully in RAM vector = model.wv.vectors_norm[0] model.wv.most_similar([vector], topn=5, indexer=annoy_index) model.wv.most_similar([vector], topn=5) @@ -208,19 +221,16 @@ within the 10 most similar words. import numpy as np def avg_query_time(annoy_index=None, queries=1000): - """ - Average query time of a most_similar method over 1000 random queries, - uses annoy if given an indexer - """ + """Average query time of a most_similar method over 1000 random queries.""" total_time = 0 for _ in range(queries): - rand_vec = model.wv.vectors_norm[np.random.randint(0, len(model.wv.vocab))] + rand_vec = model.wv.vectors_norm[np.random.randint(0, len(model.wv))] start_time = time.process_time() model.wv.most_similar([rand_vec], topn=5, indexer=annoy_index) total_time += time.process_time() - start_time return total_time / queries - queries = 10000 + queries = 1000 gensim_time = avg_query_time(queries=queries) annoy_time = avg_query_time(annoy_index, queries=queries) @@ -239,10 +249,11 @@ within the 10 most similar words. .. code-block:: none - Gensim (s/query): 0.02169 - Annoy (s/query): 0.00034 + Gensim (s/query): 0.00879 + Annoy (s/query): 0.00036 + + Annoy is 24.36 times faster on average on this particular run - Annoy is 63.71 times faster on average on this particular run **This speedup factor is by no means constant** and will vary greatly from @@ -299,7 +310,7 @@ loading an index, you will have to create an empty AnnoyIndexer object. approximate_neighbors2 = model.wv.most_similar([vector], topn=11, indexer=annoy_index2) for neighbor in approximate_neighbors2: print(neighbor) - + assert approximate_neighbors == approximate_neighbors2 @@ -312,24 +323,25 @@ loading an index, you will have to create an empty AnnoyIndexer object. .. code-block:: none - ('science', 1.0) - ('astrobiology', 0.5924032926559448) - ('transhumanist', 0.5916061401367188) - ('bimonthly', 0.5861886739730835) - ('sciences', 0.5851120948791504) - ('robotics', 0.5844891369342804) - ('nanomedicine', 0.5836333632469177) - ('protoscience', 0.5796476304531097) - ('biostatistics', 0.5791448056697845) - ('astronautics', 0.5787959098815918) - ('scientific', 0.5772265493869781) + ('science', 0.9998779296875) + ('actuarial', 0.5997203588485718) + ('multidisciplinary', 0.5991933047771454) + ('sciences', 0.5958340764045715) + ('scientific', 0.5955467224121094) + ('astrobiology', 0.5923857390880585) + ('popularizer', 0.5910311937332153) + ('nanomedicine', 0.5902301669120789) + ('astronautics', 0.5890269577503204) + ('poststructuralism', 0.5872606933116913) + ('crichton', 0.5863060653209686) + Be sure to use the same model at load that was used originally, otherwise you will get unexpected behaviors. -6. Save memory via memory-mapping indices saved to disk +6. Save memory via memory-mapping indexes saved to disk ------------------------------------------------------- Annoy library has a useful feature that indices can be memory-mapped from @@ -358,8 +370,8 @@ memory-mapping. The second example uses less total RAM as it is shared. -Bad example: two processes load the Word2vec model from disk and create there -own Annoy indices from that model. +Bad example: two processes load the Word2vec model from disk and create their +own Annoy index from that model. @@ -392,7 +404,7 @@ own Annoy indices from that model. Good example: two processes load both the Word2vec model and index from disk -and memory-map the index +and memory-map the index. @@ -496,6 +508,15 @@ Plot results: :class: sphx-glr-single-img +.. rst-class:: sphx-glr-script-out + + Out: + + .. code-block:: none + + /Volumes/work/workspace/vew/gensim3.6/lib/python3.6/site-packages/matplotlib/figure.py:445: UserWarning: Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure. + % get_backend()) + From the above, we can see that the initialization time of the annoy indexer @@ -504,7 +525,7 @@ from corpus to corpus, in the graph above the lee corpus was used Furthermore, in this dataset, the accuracy seems logarithmically related to the number of trees. We see an improvement in accuracy with more trees, but -the relationship is nonlinear. +the relationship is nonlinear. 7. Work with Google word2vec files @@ -525,7 +546,7 @@ software, or imported back into gensim as a ``KeyedVectors`` object. from smart_open import open # View the first 3 lines of the exported file - # The first line has the total number of entries and the vector dimension count. + # The first line has the total number of entries and the vector dimension count. # The next lines have a key (a string) followed by its vector. with open('/tmp/vectors.txt') as myfile: for i in range(3): @@ -558,7 +579,7 @@ software, or imported back into gensim as a ``KeyedVectors`` object. print(neighbor) normal_neighbors = wv.most_similar([vector], topn=11) - print("\nNormal (not Annoy-indexed) Neighbors") + print("\nExact Neighbors") for neighbor in normal_neighbors: print(neighbor) @@ -573,33 +594,34 @@ software, or imported back into gensim as a ``KeyedVectors`` object. .. code-block:: none 71290 100 - the -0.086056426 0.15772334 -0.14391488 -0.10746263 -0.0036995178 -0.117373854 0.03937252 -0.14037031 -0.1252817 0.07694562 -0.021327982 0.007244886 0.16763417 -0.1226697 0.21137153 -0.063393526 -0.032362897 -0.0059070205 0.020281527 0.12367236 -0.025050493 -0.09774958 -0.24607891 -0.0064472477 -0.03055981 -0.4010833 -0.27916044 0.029562823 -0.071846716 -0.014671225 0.1420381 -0.053756475 -0.0855766 -0.090253495 0.60468906 0.09920296 0.35082236 -0.14631268 0.26485506 -0.08550774 0.09919222 -0.12538795 0.03159077 0.083675735 -0.13480936 0.043789566 -0.08674448 -0.079143874 0.05721798 0.023238886 -0.34467545 0.1550529 -0.18082479 -0.18602926 -0.18052024 0.074512914 0.15894942 -0.09034081 0.011110278 -0.15301983 -0.07879341 0.0013416538 -0.04413061 0.042708833 0.07895842 0.276121 0.11723857 0.18091062 0.07765438 0.023454918 0.07083069 0.001930411 0.2261552 -0.053920075 -0.14016616 -0.09455421 0.056401417 -0.06034534 -0.012578158 0.08775011 -0.089770935 -0.111630015 0.11005583 -0.091560066 0.0717941 -0.19018368 -0.049423326 0.29770434 0.17694262 -0.14268364 -0.1372601 0.14867909 -0.12172974 -0.07506602 0.09508915 -0.10644571 0.16355318 -0.1895201 0.04572383 -0.05629312 - of -0.24958447 0.33094105 -0.067723416 -0.15613635 0.15851182 -0.20777571 0.067617305 -0.14223038 -0.19351995 0.17955166 -0.01125617 -0.11227111 0.22649609 -0.07805858 0.08556426 0.10083455 -0.19243951 0.14512464 0.01395792 0.17216091 -0.008735538 -0.037496135 -0.3364987 0.03891899 0.036126327 -0.23090963 -0.22778185 0.09917219 0.12856483 0.0838603 0.17832059 0.021860743 -0.07048738 -0.18962148 0.5110143 0.07669086 0.2822584 -0.12050834 0.25681993 -0.021447591 0.21239889 -0.14476615 0.11061543 0.05422637 -0.02524366 0.08702608 -0.16577256 -0.20307428 0.011992565 -0.060010254 -0.3261019 0.2446808 -0.16701153 -0.079560414 -0.18528645 0.068947345 0.012339692 -0.06444969 -0.2089124 0.05786413 0.123009294 0.061585456 -0.042849902 0.16915381 0.03432279 0.13971788 0.25727242 0.09388416 0.1682245 -0.094005674 0.07307955 0.1292721 0.3170865 0.07673286 -0.07462851 -0.10278059 0.23569265 0.035961017 -0.06366512 0.034729835 -0.1799267 -0.12194269 0.19733816 -0.07210646 0.19601586 -0.09816554 -0.13614751 0.35114622 0.08043916 -0.10852109 -0.16087142 0.1783411 0.0321268 -0.14652534 0.026698181 -0.11104949 0.15343753 -0.28783563 0.08911155 -0.17888589 + the 0.040282175 0.2165622 -0.11749034 -0.07902362 0.051659793 -0.19823891 0.06806079 0.13111936 0.06739034 0.28645086 -0.05745192 -0.26289585 0.22901897 0.16851662 0.06712559 0.074796304 -0.035081368 -0.16047138 0.21728243 0.054436874 0.15153275 0.04205451 0.25825807 0.06590562 0.003011158 0.004102882 -0.100709945 -0.43598634 0.06541784 0.1916927 -0.031570192 0.29551303 -0.09695051 0.16501299 0.19717866 -0.058377385 -0.28637803 0.05174591 -0.16937277 0.059432484 -0.10389606 -0.20887667 -0.05919355 0.04137692 -0.15064004 -0.09648997 -0.22527762 0.033556122 -0.101461716 0.02389651 -0.08515353 0.042458646 -0.17026003 -0.08010368 -0.06399739 -0.078073114 -0.21165106 0.19857563 0.16560182 -0.17774524 -0.27337983 -0.05858462 0.3014273 0.25362 -0.19963813 0.03708622 0.2326357 0.1216157 -0.008749145 -0.036809318 -0.049642608 -0.15324257 0.05383394 0.47451496 -0.4227195 -0.31459892 -0.15150371 -0.14932543 0.063661754 -0.10880057 -0.021235414 0.02103542 -0.16286005 0.09865164 -0.02635211 0.11226083 -0.11042501 0.3655904 -0.12234078 -0.1566903 0.02300252 -0.030776313 0.22856043 0.0644399 0.11757082 -0.08796379 0.23301896 0.018121734 -0.060471278 0.013380485 + of -0.117521346 0.25582337 0.099465266 -0.08187441 0.0003451583 -0.3138303 0.017125094 -0.02423271 0.008411589 0.23745868 -0.030340558 -0.0042213113 0.16474192 0.17288761 0.18377638 0.09036244 -0.20894344 -0.044563673 0.14401074 -0.0023740537 0.069194905 0.16009597 0.3646139 0.04876363 0.04529528 0.04463972 -0.11413204 -0.46372798 0.09147736 0.19938193 -0.0743411 0.3425023 -0.1404897 0.13559413 0.091858536 -0.046490498 -0.07325774 0.036205 -0.13261133 0.060684923 -0.2155932 -0.18659447 0.06216802 0.15724409 -0.0615914 -0.1047893 -0.21563342 0.03399876 -0.14627206 0.13622384 -0.038415514 0.040357746 -0.0950334 -0.1240751 -0.025667595 -0.0762319 -0.19063687 0.42665502 0.26953915 -0.095091894 0.033522405 -0.06997937 0.32336366 0.17219204 -0.17910816 -0.17552538 0.15011984 0.005003567 0.14006145 0.0067128018 -0.0964597 -0.15371965 0.07887949 0.38889432 -0.41947517 -0.14448255 -0.39335525 -0.14048906 0.05884099 -0.0022921925 -0.10194997 0.20200975 -0.20999992 0.12407939 -0.084994085 0.13595223 -0.16718066 0.3076714 -0.1003335 -0.13627231 0.15710355 -0.097152695 0.18041256 -0.013511332 -0.06089443 -0.02832937 0.1863955 0.094825216 0.073157795 0.030848853 Approximate Neighbors ('cat', 1.0) - ('cats', 0.5971987545490265) - ('felis', 0.5874168574810028) - ('albino', 0.5703404247760773) - ('marten', 0.5679939687252045) - ('leopardus', 0.5678345859050751) - ('barsoomian', 0.5672095417976379) - ('prionailurus', 0.567060798406601) - ('ferret', 0.5667355954647064) - ('eared', 0.566079169511795) - ('sighthound', 0.5649237632751465) - - Normal (not Annoy-indexed) Neighbors - ('cat', 0.9999998807907104) - ('cats', 0.6755023002624512) - ('felis', 0.6595503091812134) - ('albino', 0.6307852268218994) - ('marten', 0.6267415881156921) - ('leopardus', 0.6264660954475403) - ('barsoomian', 0.6253848075866699) - ('prionailurus', 0.6251273155212402) - ('ferret', 0.6245640516281128) - ('eared', 0.6234253644943237) - ('sighthound', 0.6214173436164856) + ('polydactyl', 0.5950324535369873) + ('kitten', 0.5930328965187073) + ('sighthound', 0.5881928503513336) + ('leopardus', 0.585923820734024) + ('prionailurus', 0.5840010941028595) + ('pug', 0.5792734324932098) + ('cats', 0.5770905315876007) + ('eared', 0.5770178437232971) + ('badger', 0.5747911930084229) + ('albino', 0.5721485614776611) + + Exact Neighbors + ('cat', 1.0) + ('polydactyl', 0.6720025539398193) + ('kitten', 0.6687554717063904) + ('meow', 0.6622823476791382) + ('sighthound', 0.6608296632766724) + ('leopardus', 0.6570817828178406) + ('prionailurus', 0.6538898348808289) + ('pug', 0.6459784507751465) + ('proboscis', 0.6438583731651306) + ('cats', 0.6422951221466064) + ('eared', 0.6421721577644348) + Recap @@ -620,9 +642,9 @@ of our word embeddings. To do so, we did the following steps: .. rst-class:: sphx-glr-timing - **Total running time of the script:** ( 11 minutes 41.168 seconds) + **Total running time of the script:** ( 15 minutes 0.569 seconds) -**Estimated memory usage:** 807 MB +**Estimated memory usage:** 794 MB .. _sphx_glr_download_auto_examples_tutorials_run_annoy.py: @@ -650,4 +672,4 @@ of our word embeddings. To do so, we did the following steps: .. rst-class:: sphx-glr-signature - `Gallery generated by Sphinx-Gallery `_ + `Gallery generated by Sphinx-Gallery `_ diff --git a/docs/src/auto_examples/tutorials/sg_execution_times.rst b/docs/src/auto_examples/tutorials/sg_execution_times.rst index 8e72a01a07..b632424cd6 100644 --- a/docs/src/auto_examples/tutorials/sg_execution_times.rst +++ b/docs/src/auto_examples/tutorials/sg_execution_times.rst @@ -5,10 +5,9 @@ Computation times ================= -**14:57.464** total execution time for **auto_examples_tutorials** files: +**15:00.569** total execution time for **auto_examples_tutorials** files: -- **14:57.464**: :ref:`sphx_glr_auto_examples_tutorials_run_word2vec.py` (``run_word2vec.py``) -- **00:00.000**: :ref:`sphx_glr_auto_examples_tutorials_run_annoy.py` (``run_annoy.py``) +- **15:00.569**: :ref:`sphx_glr_auto_examples_tutorials_run_annoy.py` (``run_annoy.py``) - **00:00.000**: :ref:`sphx_glr_auto_examples_tutorials_run_distance_metrics.py` (``run_distance_metrics.py``) - **00:00.000**: :ref:`sphx_glr_auto_examples_tutorials_run_doc2vec_lee.py` (``run_doc2vec_lee.py``) - **00:00.000**: :ref:`sphx_glr_auto_examples_tutorials_run_fasttext.py` (``run_fasttext.py``) @@ -16,3 +15,4 @@ Computation times - **00:00.000**: :ref:`sphx_glr_auto_examples_tutorials_run_pivoted_doc_norm.py` (``run_pivoted_doc_norm.py``) - **00:00.000**: :ref:`sphx_glr_auto_examples_tutorials_run_summarization.py` (``run_summarization.py``) - **00:00.000**: :ref:`sphx_glr_auto_examples_tutorials_run_wmd.py` (``run_wmd.py``) +- **00:00.000**: :ref:`sphx_glr_auto_examples_tutorials_run_word2vec.py` (``run_word2vec.py``) diff --git a/docs/src/conf.py b/docs/src/conf.py index c0c4cfba15..e5970031d1 100644 --- a/docs/src/conf.py +++ b/docs/src/conf.py @@ -54,16 +54,16 @@ # General information about the project. project = u'gensim' -copyright = u'2009-now, Radim Řehůřek ' +copyright = u'2009-now, Radim Řehůřek ' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = '3.8' +version = '4.0' # The full version, including alpha/beta/rc tags. -release = '3.8.1' +release = '4.0.0.dev0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/src/corpora/_mmreader.rst b/docs/src/corpora/_mmreader.rst index b2802453b2..242e1d2c8f 100644 --- a/docs/src/corpora/_mmreader.rst +++ b/docs/src/corpora/_mmreader.rst @@ -1,5 +1,5 @@ -:mod:`corpora._mmreader` -- Reader for corpus in the Matrix Market format. -========================================================================== +:mod:`corpora._mmreader` -- Read corpus in the Matrix Market format +=================================================================== .. automodule:: gensim.corpora._mmreader :synopsis: Reader for corpus in the Matrix Market format. diff --git a/docs/src/gallery/tutorials/run_annoy.py b/docs/src/gallery/tutorials/run_annoy.py index 22808b8521..a2feca72a7 100644 --- a/docs/src/gallery/tutorials/run_annoy.py +++ b/docs/src/gallery/tutorials/run_annoy.py @@ -51,9 +51,9 @@ # Using params from Word2Vec_FastText_Comparison params = { 'alpha': 0.05, - 'size': 100, + 'vector_size': 100, 'window': 5, - 'iter': 5, + 'epochs': 5, 'min_count': 5, 'sample': 1e-4, 'sg': 1, @@ -131,7 +131,7 @@ def avg_query_time(annoy_index=None, queries=1000): """Average query time of a most_similar method over 1000 random queries.""" total_time = 0 for _ in range(queries): - rand_vec = model.wv.vectors_norm[np.random.randint(0, len(model.wv.vocab))] + rand_vec = model.wv.vectors_norm[np.random.randint(0, len(model.wv))] start_time = time.process_time() model.wv.most_similar([rand_vec], topn=5, indexer=annoy_index) total_time += time.process_time() - start_time diff --git a/docs/src/similarities/nmslib.rst b/docs/src/similarities/nmslib.rst new file mode 100644 index 0000000000..dc45c738d4 --- /dev/null +++ b/docs/src/similarities/nmslib.rst @@ -0,0 +1,8 @@ +:mod:`similarities.nmslib` -- Approximate Vector Search using NMSLIB +==================================================================== + +.. automodule:: gensim.similarities.nmslib + :synopsis: Fast Approximate Nearest Neighbor Similarity with the NMSLIB package + :members: + :inherited-members: + diff --git a/docs/src/summarization/commons.rst b/docs/src/summarization/commons.rst index 0e952cad9a..b131002dd0 100644 --- a/docs/src/summarization/commons.rst +++ b/docs/src/summarization/commons.rst @@ -2,7 +2,6 @@ ============================================================================== .. automodule:: gensim.summarization.commons - :synopsis: Common graph functions :synopsis: Common graph functions used in TextRank summarization :members: :inherited-members: diff --git a/docs/src/summarization/graph.rst b/docs/src/summarization/graph.rst index 142f3eb491..29167cc377 100644 --- a/docs/src/summarization/graph.rst +++ b/docs/src/summarization/graph.rst @@ -2,7 +2,6 @@ ================================================================== .. automodule:: gensim.summarization.graph - :synopsis: Graph :synopsis: Graph utilities used in the TextRank summarization algorithm :members: :inherited-members: diff --git a/gensim/corpora/_mmreader.pyx b/gensim/corpora/_mmreader.pyx index 1fff966760..60cc4378e7 100644 --- a/gensim/corpora/_mmreader.pyx +++ b/gensim/corpora/_mmreader.pyx @@ -18,7 +18,7 @@ from libc.stdio cimport sscanf logger = logging.getLogger(__name__) -cdef class MmReader(object): +cdef class MmReader(): """Matrix market file reader (fast Cython version), used internally in :class:`~gensim.corpora.mmcorpus.MmCorpus`. Wrap a term-document matrix on disk (in matrix-market format), and present it @@ -27,7 +27,7 @@ cdef class MmReader(object): Attributes ---------- num_docs : int - Number of documents in market matrix file. + Number of documents in the market matrix file. num_terms : int Number of terms. num_nnz : int diff --git a/gensim/corpora/mmcorpus.py b/gensim/corpora/mmcorpus.py index 3650f75e11..656cd1a480 100644 --- a/gensim/corpora/mmcorpus.py +++ b/gensim/corpora/mmcorpus.py @@ -25,7 +25,7 @@ class MmCorpus(matutils.MmReader, IndexedCorpus): Notable instance attributes: Attributes - ------------------ + ---------- num_docs : int Number of documents in the market matrix file. num_terms : int diff --git a/gensim/models/word2vec.py b/gensim/models/word2vec.py index fee4c0873a..f598d634be 100755 --- a/gensim/models/word2vec.py +++ b/gensim/models/word2vec.py @@ -807,6 +807,23 @@ def update_weights(self): # do not suppress learning for already learned words self.wv.vectors_lockf = np.ones(1, dtype=REAL) # 0.0 values suppress word-backprop-updates; 1.0 allows + def init_sims(self, replace=False): + """ + Precompute L2-normalized vectors. + + Parameters + ---------- + replace : bool + If True, forget the original vectors and only keep the normalized ones to save RAM. + + """ + # init_sims() resides in KeyedVectors because it deals with input layer mainly, but because the + # hidden layer is not an attribute of KeyedVectors, it has to be deleted in this class. + # The normalizing of input layer happens inside of KeyedVectors. + if replace and hasattr(self, 'syn1'): + del self.syn1 + self.wv.init_sims(replace=replace) + def _do_train_epoch(self, corpus_file, thread_id, offset, cython_vocab, thread_private_mem, cur_epoch, total_examples=None, total_words=None, **kwargs): work, neu1 = thread_private_mem From 78fe1c437a6dbee044d3b6134567c82c26872ae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20=C5=98eh=C5=AF=C5=99ek?= Date: Sun, 26 Jul 2020 22:56:15 +0200 Subject: [PATCH 09/32] fix forgotten iteritems --- gensim/summarization/bm25.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gensim/summarization/bm25.py b/gensim/summarization/bm25.py index 7dd7867afb..f3dc67c77a 100644 --- a/gensim/summarization/bm25.py +++ b/gensim/summarization/bm25.py @@ -113,7 +113,7 @@ def _initialize(self, corpus): frequencies[word] += 1 self.doc_freqs.append(frequencies) - for word, freq in iteritems(frequencies): + for word, freq in frequencies.items(): if word not in nd: nd[word] = 0 nd[word] += 1 @@ -124,7 +124,7 @@ def _initialize(self, corpus): # collect words with negative idf to set them a special epsilon value. # idf can be negative if word is contained in more than half of documents negative_idfs = [] - for word, freq in iteritems(nd): + for word, freq in nd.items(): idf = math.log(self.corpus_size - freq + 0.5) - math.log(freq + 0.5) self.idf[word] = idf idf_sum += idf From a0e40ca335cacdbd020a2a77a982f808310ac9f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20=C5=98eh=C5=AF=C5=99ek?= Date: Sun, 26 Jul 2020 23:14:58 +0200 Subject: [PATCH 10/32] remove extra `model.wv` --- gensim/test/test_similarities.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gensim/test/test_similarities.py b/gensim/test/test_similarities.py index 0b4ca72cab..4840d30031 100644 --- a/gensim/test/test_similarities.py +++ b/gensim/test/test_similarities.py @@ -660,8 +660,7 @@ def testDocumentIsSimilarToItself(self): def testApproxNeighborsMatchExact(self): approx_neighbors = self.model.dv.most_similar([self.vector], topn=5, indexer=self.index) - exact_neighbors = self.model.dv.most_similar( - positive=[self.vector], topn=5) + exact_neighbors = self.model.dv.most_similar([self.vector], topn=5) approx_words = [neighbor[0] for neighbor in approx_neighbors] exact_words = [neighbor[0] for neighbor in exact_neighbors] @@ -759,7 +758,7 @@ def assertVectorIsSimilarToItself(self, wv, index): def assertApproxNeighborsMatchExact(self, model, wv, index): vector = wv.vectors_norm[0] approx_neighbors = model.most_similar([vector], topn=5, indexer=index) - exact_neighbors = model.wv.most_similar([vector], topn=5) + exact_neighbors = model.most_similar([vector], topn=5) approx_words = [word_id for word_id, similarity in approx_neighbors] exact_words = [word_id for word_id, similarity in exact_neighbors] From 4cf4da0040e937491d1497351bb028037f6c1411 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20=C5=98eh=C5=AF=C5=99ek?= Date: Sun, 26 Jul 2020 23:42:32 +0200 Subject: [PATCH 11/32] split overlong doc line --- gensim/similarities/nmslib.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gensim/similarities/nmslib.py b/gensim/similarities/nmslib.py index b0fc246214..a48cafe581 100644 --- a/gensim/similarities/nmslib.py +++ b/gensim/similarities/nmslib.py @@ -69,8 +69,9 @@ approximate results retrieved in sub-linear time may be enough. NMSLIB can find approximate nearest neighbors much faster, similar to Spotify's Annoy library. -Compared to :py:class:`~gensim.similarities.annoy.Annoy`, NMSLIB has more parameters to control the build and query time and accuracy. -NMSLIB often achieves faster and more accurate nearest neighbors search than Annoy. +Compared to :py:class:`~gensim.similarities.annoy.Annoy`, NMSLIB has more parameters to +control the build and query time and accuracy. NMSLIB often achieves faster and more accurate +nearest neighbors search than Annoy. """ From 161ad5538b8aeed936ef73fb8ea301762cec08b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20=C5=98eh=C5=AF=C5=99ek?= Date: Mon, 27 Jul 2020 09:31:30 +0200 Subject: [PATCH 12/32] get rid of six in doc2vec --- gensim/models/doc2vec.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/gensim/models/doc2vec.py b/gensim/models/doc2vec.py index bd7633db41..61733812a0 100644 --- a/gensim/models/doc2vec.py +++ b/gensim/models/doc2vec.py @@ -74,8 +74,6 @@ from dataclasses import dataclass from numpy import zeros, float32 as REAL, vstack, integer, dtype import numpy as np -from six.moves import range -from six import string_types, integer_types, itervalues from gensim import utils, matutils # utility fnc for pickling, common scipy operations etc from gensim.utils import deprecated @@ -609,7 +607,7 @@ def infer_vector(self, doc_words, alpha=None, min_alpha=None, epochs=None, steps The inferred paragraph vector for the new document. """ - if isinstance(doc_words, string_types): + if isinstance(doc_words, str): # a common mistake; fail with a nicer error raise TypeError("Parameter doc_words of infer_vector() must be a list of strings (not a single string).") alpha = alpha or self.alpha @@ -661,7 +659,7 @@ def __getitem__(self, tag): The vector representations of each tag as a matrix (will be 1D if `tag` was a single tag) """ - if isinstance(tag, string_types + integer_types + (integer,)): + if isinstance(tag, (str, int, integer,)): if tag not in self.wv: return self.dv[tag] return self.wv[tag] @@ -898,13 +896,13 @@ def build_vocab_from_freq(self, word_freq, keep_raw_vocab=False, corpus_count=No If true, the new provided words in `word_freq` dict will be added to model's vocab. """ - logger.info("Processing provided word frequencies") + logger.info("processing provided word frequencies") # Instead of scanning text, this will assign provided word frequencies dictionary(word_freq) - # to be directly the raw vocab + # to be directly the raw vocab. raw_vocab = word_freq logger.info( - "collected %i different raw word, with total frequency of %i", - len(raw_vocab), sum(itervalues(raw_vocab)) + "collected %i different raw words, with total frequency of %i", + len(raw_vocab), sum(raw_vocab.values()), ) # Since no documents are provided, this is to control the corpus_count @@ -929,11 +927,11 @@ def _scan_vocab(self, corpus_iterable, progress_per, trim_rule): doctags_list = [] for document_no, document in enumerate(corpus_iterable): if not checked_string_types: - if isinstance(document.words, string_types): + if isinstance(document.words, str): logger.warning( "Each 'words' should be a list of words (usually unicode strings). " "First 'words' here is instead plain %s.", - type(document.words) + type(document.words), ) checked_string_types += 1 if document_no % progress_per == 0: @@ -948,7 +946,7 @@ def _scan_vocab(self, corpus_iterable, progress_per, trim_rule): for tag in document.tags: # Note a document tag during initial corpus scan, for structure sizing. - if isinstance(tag, integer_types + (integer,)): + if isinstance(tag, (int, integer,)): max_rawint = max(max_rawint, tag) else: if tag in doctags_lookup: From 31d2b876cf0b101b31d61c08ab2c3605086bf96e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20=C5=98eh=C5=AF=C5=99ek?= Date: Mon, 27 Jul 2020 11:56:57 +0200 Subject: [PATCH 13/32] increase test timeout for Visdom server --- gensim/test/test_lda_callback.py | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/gensim/test/test_lda_callback.py b/gensim/test/test_lda_callback.py index 621dd8f369..e5234dfe38 100644 --- a/gensim/test/test_lda_callback.py +++ b/gensim/test/test_lda_callback.py @@ -36,23 +36,16 @@ def setUp(self): self.port = 8097 def testCallbackUpdateGraph(self): - - # Popen have no context-manager in 2.7, for this reason - try/finally. - try: - # spawn visdom.server - proc = subprocess.Popen(['python', '-m', 'visdom.server', '-port', str(self.port)]) - + with subprocess.Popen(['python', '-m', 'visdom.server', '-port', str(self.port)]) as proc: # wait for visdom server startup (any better way?) - time.sleep(3) - viz = Visdom(server=self.host, port=self.port) + for attempt in range(5): + time.sleep(1.0) # seconds + if viz.check_connection(): + break assert viz.check_connection() - - # clear screen viz.close() - self.model.update(self.corpus) - finally: proc.kill() From bc95bcb509bdc49241346163a519252394bdc3bd Mon Sep 17 00:00:00 2001 From: Gordon Mohr Date: Wed, 29 Jul 2020 15:06:49 -0700 Subject: [PATCH 14/32] add 32/64 bits report --- ISSUE_TEMPLATE.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 8fa0214517..ec31c5964f 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -22,6 +22,7 @@ Please provide the output of: ```python import platform; print(platform.platform()) import sys; print("Python", sys.version) +import struct; print("Bits", 8 * struct.calcsize("P")) import numpy; print("NumPy", numpy.__version__) import scipy; print("SciPy", scipy.__version__) import gensim; print("gensim", gensim.__version__) From c834e067652993909f96a3fb1cb34610f4abbd73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20=C5=98eh=C5=AF=C5=99ek?= Date: Thu, 30 Jul 2020 12:43:26 +0200 Subject: [PATCH 15/32] add deprecations for init_sims() --- gensim/models/doc2vec.py | 18 +++++++++++++++--- gensim/models/fasttext.py | 24 ++++++++++++++++-------- gensim/models/keyedvectors.py | 8 +++++--- gensim/models/word2vec.py | 21 ++++++++++++++------- 4 files changed, 50 insertions(+), 21 deletions(-) diff --git a/gensim/models/doc2vec.py b/gensim/models/doc2vec.py index 61733812a0..6df8fa20a9 100644 --- a/gensim/models/doc2vec.py +++ b/gensim/models/doc2vec.py @@ -745,14 +745,26 @@ def save_word2vec_format(self, fname, doctag_vec=False, word_vec=True, prefix='* write_header=write_header, append=append, sort_attr='doc_count') + @deprecated( + "Gensim 4.0.0 implemented internal optimizations that make calls to init_sims() unnecessary. " + "init_sims() is now obsoleted and will be completely removed in future versions." + ) def init_sims(self, replace=False): - """Pre-compute L2-normalized vectors. + """ + Precompute L2-normalized vectors. Obsoleted. + + If you need a single unit-normalized vector for some key, call + `:meth:`~gensim.models.keyedvectors.KeyedVectors.get_vector` instead: + ``doc2vec_model.dv.get_vector(key, use_norm=True)``. + + To refresh norms after you performed some atypical out-of-band vector tampering, + call `:meth:`~gensim.models.keyedvectors.KeyedVectors.fill_norms()` instead. Parameters ---------- replace : bool - If True - forget the original vectors and only keep the normalized ones to saved RAM (also you can't - continue training if call it with `replace=True`). + If True, forget the original trained vectors and only keep the normalized ones. + You lose information if you do this. """ self.dv.init_sims(replace=replace) diff --git a/gensim/models/fasttext.py b/gensim/models/fasttext.py index 8b8dfab407..f6dad2e540 100644 --- a/gensim/models/fasttext.py +++ b/gensim/models/fasttext.py @@ -286,6 +286,7 @@ from gensim.models.word2vec import Word2Vec from gensim.models.keyedvectors import KeyedVectors from gensim import utils +from gensim.utils import deprecated try: from gensim.models.fasttext_inner import ( # noqa: F401 train_batch_any, @@ -747,22 +748,29 @@ def train(self, corpus_iterable=None, corpus_file=None, total_examples=None, tot queue_factor=queue_factor, report_delay=report_delay, callbacks=callbacks) self.wv.adjust_vectors() + @deprecated( + "Gensim 4.0.0 implemented internal optimizations that make calls to init_sims() unnecessary. " + "init_sims() is now obsoleted and will be completely removed in future versions." + ) def init_sims(self, replace=False): """ - Precompute L2-normalized vectors. + Precompute L2-normalized vectors. Obsoleted. + + If you need a single unit-normalized vector for some key, call + `:meth:`~gensim.models.keyedvectors.KeyedVectors.get_vector` instead: + ``fasttext_model.wv.get_vector(key, use_norm=True)``. + + To refresh norms after you performed some atypical out-of-band vector tampering, + call `:meth:`~gensim.models.keyedvectors.KeyedVectors.fill_norms()` instead. Parameters ---------- replace : bool - If True, forget the original vectors and only keep the normalized ones to save RAM. + If True, forget the original trained vectors and only keep the normalized ones. + You lose information if you do this. """ - # init_sims() resides in KeyedVectors because it deals with input layer mainly, but because the - # hidden layer is not an attribute of KeyedVectors, it has to be deleted in this class. - # The normalizing of input layer happens inside of KeyedVectors. - if replace and hasattr(self, 'syn1'): - del self.syn1 - self.wv.init_sims(replace) + self.wv.init_sims(replace=replace) def clear_sims(self): """Remove all L2-normalized word vectors from the model, to free up memory. diff --git a/gensim/models/keyedvectors.py b/gensim/models/keyedvectors.py index 7c386ac038..9007ec724b 100644 --- a/gensim/models/keyedvectors.py +++ b/gensim/models/keyedvectors.py @@ -530,7 +530,7 @@ def fill_norms(self, force=False): Ensure per-vector norms are available. Any code which modifies vectors should ensure the accompanying norms are - either recalculated or 'None', to trigger full recalc later. + either recalculated or 'None', to trigger a full recalculation later. """ if self.norms is None or force: @@ -1345,7 +1345,7 @@ def evaluate_word_pairs(self, pairs, delimiter='\t', restrict_vocab=300000, self.log_evaluate_word_pairs(pearson, spearman, oov_ratio, pairs) return pearson, spearman, oov_ratio - @deprecated("use fill_norms instead") + @deprecated("use fill_norms() instead") def init_sims(self, replace=False): """Precompute data helpful for bulk similarity calculations. @@ -1353,13 +1353,15 @@ def init_sims(self, replace=False): Parameters ---------- + replace : bool, optional If True - forget the original vectors and only keep the normalized ones. Warnings -------- + You **cannot sensibly continue training** after doing a replace on a model's - internal KeyedVectors, and a replace is no longer necessary to save RAM. + internal KeyedVectors, and a replace is no longer necessary to save RAM. Do not use this method. """ self.fill_norms() diff --git a/gensim/models/word2vec.py b/gensim/models/word2vec.py index f598d634be..8275f936d1 100755 --- a/gensim/models/word2vec.py +++ b/gensim/models/word2vec.py @@ -807,21 +807,28 @@ def update_weights(self): # do not suppress learning for already learned words self.wv.vectors_lockf = np.ones(1, dtype=REAL) # 0.0 values suppress word-backprop-updates; 1.0 allows + @deprecated( + "Gensim 4.0.0 implemented internal optimizations that make calls to init_sims() unnecessary. " + "init_sims() is now obsoleted and will be completely removed in future versions." + ) def init_sims(self, replace=False): """ - Precompute L2-normalized vectors. + Precompute L2-normalized vectors. Obsoleted. + + If you need a single unit-normalized vector for some key, call + `:meth:`~gensim.models.keyedvectors.KeyedVectors.get_vector` instead: + ``word2vec_model.wv.get_vector(key, use_norm=True)``. + + To refresh norms after you performed some atypical out-of-band vector tampering, + call `:meth:`~gensim.models.keyedvectors.KeyedVectors.fill_norms()` instead. Parameters ---------- replace : bool - If True, forget the original vectors and only keep the normalized ones to save RAM. + If True, forget the original trained vectors and only keep the normalized ones. + You lose information if you do this. """ - # init_sims() resides in KeyedVectors because it deals with input layer mainly, but because the - # hidden layer is not an attribute of KeyedVectors, it has to be deleted in this class. - # The normalizing of input layer happens inside of KeyedVectors. - if replace and hasattr(self, 'syn1'): - del self.syn1 self.wv.init_sims(replace=replace) def _do_train_epoch(self, corpus_file, thread_id, offset, cython_vocab, thread_private_mem, cur_epoch, From 172e37f9a0c03215690f4bbed05b4ec1ea1fd1ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20=C5=98eh=C5=AF=C5=99ek?= Date: Thu, 30 Jul 2020 13:00:46 +0200 Subject: [PATCH 16/32] remove vectors_norm + add link to migration guide to deprecation warnings --- gensim/models/doc2vec.py | 3 ++- gensim/models/fasttext.py | 3 ++- gensim/models/keyedvectors.py | 32 +++++++++++++++++++++----------- gensim/models/word2vec.py | 3 ++- 4 files changed, 27 insertions(+), 14 deletions(-) diff --git a/gensim/models/doc2vec.py b/gensim/models/doc2vec.py index 6df8fa20a9..8a9cb3a778 100644 --- a/gensim/models/doc2vec.py +++ b/gensim/models/doc2vec.py @@ -747,7 +747,8 @@ def save_word2vec_format(self, fname, doctag_vec=False, word_vec=True, prefix='* @deprecated( "Gensim 4.0.0 implemented internal optimizations that make calls to init_sims() unnecessary. " - "init_sims() is now obsoleted and will be completely removed in future versions." + "init_sims() is now obsoleted and will be completely removed in future versions. " + "See https://github.com/RaRe-Technologies/gensim/wiki/Migrating-from-Gensim-3.x-to-4#init_sims" ) def init_sims(self, replace=False): """ diff --git a/gensim/models/fasttext.py b/gensim/models/fasttext.py index f6dad2e540..99a8ecef5b 100644 --- a/gensim/models/fasttext.py +++ b/gensim/models/fasttext.py @@ -750,7 +750,8 @@ def train(self, corpus_iterable=None, corpus_file=None, total_examples=None, tot @deprecated( "Gensim 4.0.0 implemented internal optimizations that make calls to init_sims() unnecessary. " - "init_sims() is now obsoleted and will be completely removed in future versions." + "init_sims() is now obsoleted and will be completely removed in future versions. " + "See https://github.com/RaRe-Technologies/gensim/wiki/Migrating-from-Gensim-3.x-to-4#init_sims" ) def init_sims(self, replace=False): """ diff --git a/gensim/models/keyedvectors.py b/gensim/models/keyedvectors.py index 9007ec724b..cfff5a0c86 100644 --- a/gensim/models/keyedvectors.py +++ b/gensim/models/keyedvectors.py @@ -165,19 +165,18 @@ import sys import itertools import warnings -from itertools import chain from numbers import Integral -from numpy import dot, float32 as REAL, \ - double, array, zeros, vstack, \ - ndarray, sum as np_sum, prod, argmax, dtype, ascontiguousarray, \ - frombuffer +from numpy import ( + dot, float32 as REAL, double, array, zeros, vstack, + ndarray, sum as np_sum, prod, argmax, dtype, ascontiguousarray, frombuffer, +) import numpy as np +from scipy import stats from gensim import utils, matutils # utility fnc for pickling, common scipy operations etc from gensim.corpora.dictionary import Dictionary from gensim.utils import deprecated -from scipy import stats logger = logging.getLogger(__name__) @@ -519,9 +518,17 @@ def rank(self, key1, key2): """Rank of the distance of `key2` from `key1`, in relation to distances of all keys from `key1`.""" return len(self.closer_than(key1, key2)) + 1 - # backward compatibility; some would be annotated `@deprecated` if that stacked with @property/.setter @property def vectors_norm(self): + raise ValueError( + "The vectors_norm attribute became a get_normed_vectors() method in Gensim 4.0.0. " + "See https://github.com/RaRe-Technologies/gensim/wiki/Migrating-from-Gensim-3.x-to-4#init_sims" + ) + + def get_normed_vectors(self): + # TODO: what's the way for users to get from a matrix index (integer) to the + # corresponding key (string)? + # Shouldn't we return this as a mapping (dict), or even a new KeyedVectors instance? self.fill_norms() return self.vectors / self.norms[..., np.newaxis] @@ -1215,8 +1222,8 @@ def evaluate_word_analogies(self, analogies, restrict_vocab=300000, case_insensi total = { 'section': 'Total accuracy', - 'correct': list(chain.from_iterable(s['correct'] for s in sections)), - 'incorrect': list(chain.from_iterable(s['incorrect'] for s in sections)), + 'correct': list(itertools.chain.from_iterable(s['correct'] for s in sections)), + 'incorrect': list(itertools.chain.from_iterable(s['incorrect'] for s in sections)), } oov_ratio = float(oov) / quadruplets_no * 100 @@ -1345,7 +1352,10 @@ def evaluate_word_pairs(self, pairs, delimiter='\t', restrict_vocab=300000, self.log_evaluate_word_pairs(pearson, spearman, oov_ratio, pairs) return pearson, spearman, oov_ratio - @deprecated("use fill_norms() instead") + @deprecated( + "Use fill_norms() instead. " + "See https://github.com/RaRe-Technologies/gensim/wiki/Migrating-from-Gensim-3.x-to-4#init_sims" + ) def init_sims(self, replace=False): """Precompute data helpful for bulk similarity calculations. @@ -1454,7 +1464,7 @@ def save_word2vec_format(self, fname, fvocab=None, binary=False, total_vec=None, if not (i == val): break index_id_count += 1 - keys_to_write = chain(range(0, index_id_count), store_order_vocab_keys) + keys_to_write = itertools.chain(range(0, index_id_count), store_order_vocab_keys) with utils.open(fname, mode) as fout: if write_header: diff --git a/gensim/models/word2vec.py b/gensim/models/word2vec.py index 8275f936d1..ca7bb720df 100755 --- a/gensim/models/word2vec.py +++ b/gensim/models/word2vec.py @@ -809,7 +809,8 @@ def update_weights(self): @deprecated( "Gensim 4.0.0 implemented internal optimizations that make calls to init_sims() unnecessary. " - "init_sims() is now obsoleted and will be completely removed in future versions." + "init_sims() is now obsoleted and will be completely removed in future versions. " + "See https://github.com/RaRe-Technologies/gensim/wiki/Migrating-from-Gensim-3.x-to-4#init_sims" ) def init_sims(self, replace=False): """ From 3919b68d001d6b876cb77d8e3c989bbad99b8e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20=C5=98eh=C5=AF=C5=99ek?= Date: Thu, 30 Jul 2020 13:43:26 +0200 Subject: [PATCH 17/32] rename vectors_norm everywhere, update tests, regen docs --- .../images/sphx_glr_run_annoy_001.png | Bin 44608 -> 48021 bytes .../images/thumb/sphx_glr_run_annoy_thumb.png | Bin 14666 -> 15673 bytes .../auto_examples/tutorials/run_annoy.ipynb | 4 +- docs/src/auto_examples/tutorials/run_annoy.py | 9 +- .../auto_examples/tutorials/run_annoy.py.md5 | 2 +- .../src/auto_examples/tutorials/run_annoy.rst | 159 ++++++++++-------- .../tutorials/sg_execution_times.rst | 30 ++-- docs/src/gallery/tutorials/run_annoy.py | 9 +- gensim/models/doc2vec.py | 4 +- gensim/models/fasttext.py | 13 +- gensim/models/keyedvectors.py | 30 ++-- gensim/models/word2vec.py | 4 +- gensim/similarities/annoy.py | 4 +- gensim/similarities/nmslib.py | 9 +- gensim/test/test_fasttext.py | 4 +- gensim/test/test_keras_integration.py | 2 +- gensim/test/test_similarities.py | 14 +- gensim/test/test_word2vec.py | 16 +- 18 files changed, 168 insertions(+), 145 deletions(-) diff --git a/docs/src/auto_examples/tutorials/images/sphx_glr_run_annoy_001.png b/docs/src/auto_examples/tutorials/images/sphx_glr_run_annoy_001.png index 4b06f2bc2bc94a338e3f60a293843d772c63d1ba..1c3020babc0b8d1c9e89a333b5fc2d6cb5854f56 100644 GIT binary patch literal 48021 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
He<oWWODfrO~$J|s__BP zvZI_sp15!3%BZM(y0bUH>%RPrN&OD8fpM_4>VvijBJ>nX4%*r+G-Yr{)N{6>8u`9J}ai3%EZYr_cb-Cy9 z{Gs@K5O(i-*dvOf$0jB}VO5tXDVt!7hb4(JV?4H7 zK-hFv!le%j5idrPZFn|KvH5@>TC7@yN;%|&4SblCS1a4JZisgH4`_qkpdb+E{ET3POS{a5+Q4T=6IG84 z)qqT5Gg?6kDjYJn1-n7Y$VhCxT*ap~t_`KQs)+;he>AxwNz=l{?WOMIrjatiTDBaq zU%V9`x203WhLa7#Uo8rjpRa=dH;z=^q@N23Vdz^F;Gm(r#XhkTizVs9%4Gdyp;ylB;@gWhLA%2*LG6E5VMD7M`_(0wx zq!-{Hf$#DEAPhLg#XK_N*17UwmUbkcCo>G^AAbp@kPTPcqO!c>w&emd^2w}(h{pqe z`>GXvc8TGq8X>i4emfpnjlcboV!?_xnY8~lh!tJ`um+b4Q4z%Asrb3=+O!0JF)%O? zmNwvxzsWl4~uKina6=X zDkiGJaTZTaT^+E&*!#I!jyzzb1ITnbI=+=-yq9MKiq+S7Yhts zfo1?xAt1jXe%KmCkB?Hge;*SCqkbBm$)Ta44kN2#p;t*&$DTmdHdq-^mHvQj>{?mp zhu5dywPr)wf|f-L`%_A`?CbN|E+G6^%#D@ur-07Uho5q}T&>*+mr&qqwdHu`vTH@9 zf>obUs-<0PDM_IBB25bp4i1o6a0m%oK+V_~GKoeMKxja>~3kREEUiWIlV4Sm7VvYGQr6in-QiEp>*u`s$Bt^6JntkAY)L<;jDz;Yx%1Lgi9mW+akXfAlQ6cNiHWRPKu%?_?Ysu7r^i-0!O6g1K*y#ETq;GzSJAUdxM z{j5-inJEd^l`v4%iWJk5Z^ncztO1cOmXRg|{PwL$2oO9r^fL(kD<((36wVvX8`mGli}* z3MC^W11V>^KHx$t`a@e=UZi<@G;w-tSnA_Qq{@=M1cr84kdyH3vv8Q~agK?heLjLN zg%tg=^q=JJQRvL$1=UkwG(Lti!93t?!VFp!6zljk$9y-gApA^I>i= zh)N|kzb`_=2+8sgQz3WXu%Tt|U;PHEdod{8fb>Y~0RcT2=zK;*Z#BIwFF#jUGU}fZ zFNmaEJ8v4W#fy<6y;TU0K){7E29P=K_LVqX0$s3Aet{5OSJ|LRW>2sFd!rz#-rtD0 z`q#Zm;GC$(!DFIJF#_+n*WF{(lU^YhuW_6HhLve9&WN6iOeVowR z+M0}wokh^jGpOFYPQSH|n4M+buTB^3MrKJtMK7mPh*4~yn+TZ{3M4KkF%lq<_S1?Y z6em=n`!Nx*)5Bj!OadgRYKFfii9MQW6=*Va=MBrQtW47MPaL@>=2H5YTowvCtPoFG zz~)fzWTsh`tMdIw?*i(q5RojLPPddhK;}^@+PX%qCae4fx?I{FAKW~y!A6fgzzN`C zFEIYyEu*UaDYRx3eG9v^t(UmmAJeb=Vj{s=0r)}%D$ulJPikwTE9u!v#NilJW0_aX zqz2XkxO?t{#V%#eQkZn_QqetVN1>dpSD*V45eJo%$wVldTAdMeVZq^K7Rjm;x65Y0 zrXf0v;gy(qV%Q$shRfY=S(muaA3FUYk8OY*7fr=!Zf2-G%4T|%cvh@ulir20YN01; z=HNSv`_(`0*FQ`3y*Egfj6>LsBi=oM(@?Ra{W@r|m#7%+ghlD8zHIM0Bg}mYm!D7= zb(y!l?3ep_r4|`{VkhY$d{DZ^QB8bb?oiVgl0{ArI886mnnQAE=eFY zQjsJ<1%H*3B5iWG}Wh+n+u{@bV5wf`_kM%@t&r7Saw zj^EdyGQ6?JscO=Ihy|~x4_G;9$wZRneea4(lsY!XlU;9WND8unH#d0w1%I>YH|!Q|3ie<&AR~#&oWm9Pf7* zz1h+d0sAw`;dpxqQs489xFefWYjE%!$FZ$S+0DP|0;Mdo)pIc#HW2t(>-4+o@ePjy zrUfr}mbF&{M852jlVc}0Z5Vee9eUAbJpX|T;;v$%Kr|cA>_?<>q-c0YHp(XTn z5({$RE6aaB7aGls_9`_%i@4UYjUHXTS6|mENx+4lbG8#wBwrf^x%W5eYGraUQ6+n7 zMmz0MI2+FV4uUL#lxJ>~s11t4;zVl5I1>r=QV8*F*WgU(WP&9be5(=y1~VSNOwuLD z!ASU3PH3{uy~QxG@){jdNB`uS<^wIC%rQe6gP!2G9ElS~fbW-f2vC z>U%&yQR#GAw!DVa$?^@*E6@!Y?=@C4PNPszgf~w&Fu(ll4&B)MdX|-FjHiyIX>`>X zK`2S`0r&Mpm2Jy;vn308)44MM_pGnI?lPuboz&M$yoH77@W>8c^B*Xz5q&GU>J>hU z>X&LrOVG`CC8gKEL{X?7#as}ugOxJ&{fXf3@uu%YVntdX$1|jf^Iy%Ev?u= z=(3jaK`(mG)v$hD>oXe4=fY@_qxMzFO9MOPZ^Dvr&y2ClAsL8Y0XLx+cPo&%k~V#iLx!FS6)@i7@+3dx{WJySxhTGgEYhg9kf zQjhRFxd^R|P>C*lQdtIwMCDs7f_z6>h}eskKjgwNZ~Le5+rUM}7rrC0a^qhXbq_#LZTdNf<>)|=#bv_?~ z771|tcSM@ZA41SChBpV_4G*I^Z#?Z><|(HVs*}P;xtHm3!K-#6;&`?InH;h@WEs?N z1EGI0BckPn{1`u|NyEJ&lk9^UMSfVe<+*P$0HG;-DixF$sD|OevEgd^^2{ErmxFJ3 zEAoPKA(|#@R(r*LeA_4#AZ{2| zL&hrP`@-}Tdw^X;BCQhhOH^mAl4@v`7(=UMxz&R_Jp1>Vj z_D`!ivBz6P4^AvD8GXF+{H`o$CFTXQR3kheF2a)|8t65Vq7Q-u*^)%YvoK$3HzG-> zydSg;4IhW{wshw6hL73Rs&|*Fx;48jcMfB1a8!TtzCw-ZR^0#wPu7rX|M`pHQxz5# zp)+w*mEPxI|NTqinLSkmz-Tb>M2#y&6(!++^q0P|(tT23?;Z#~`GzRZa0xLV5y99{}p0v_NR?DY!Uy zKW+Kns^7-;+DOOlM-o0{fHBH5Tdc`O6ySU*v$SW;!pYaO*@VpfQsMH)C;)n570{M(K)8_ zdZ_mah}7SQ*5PxTs*$l>0fuu10$*Q@GZiiFYaThRV}cECvY@p(TZRu}V?ZM6=-Wg9 zQ|}x1KIr<9k&Ay@U1{%8vkZIPfP!iRCECtoiVXYod7r`Jwy1f*SaUUF_tfYMJ=Bd* z3Po;unn372kg>A@s<^@)TsJA%SIrPUsUk)}1ML8-!dN8%j}$3&r_+FAe{A&&hYd!J za$jxn^6EBO{$`4Ub~TS@;*SlPV=n*+P*5fT9ieBJ4|gAA+Dr zKHHz~NexUSE}Ya{t|@J26;V-WjlkZw8x_Ny_miWtU13@Wx5mKk=mchb-B*g+_~8H# zsvbrfi=5^kz+ojArGE^kwA>FCvyf>y^;>M7?|`-=QY>_7#o`h$gR(8+75sT?yQxN1 zL)ZhQrW*bB!o#}aev=msfQ$@c8Vd&pE($qJ^ml9CWU@X0RnHX$1&-ZxiA2}o3Ecz3 zPBaukvcLTxao%(iaS%-Rnwgt>xOhm;^{^fWIH#tjVEjkB&Q}U%&;osr571DcDfz=m z4$y7s;INd?Ez@+Yctf=)pUpD~a4?u4X5y0$8fbesh&D@KJ(*J?Vyp<+fd|xA4>&de zN7^h#%6LEr2PN(q0d=5|c{h`oSb`Qwc-TViEJeI=|2T%X3pXwn+R&qK{8H)kY}?x* zSF~c%Zx@u5TtcQyx)Oz;Q(?c<#{u)s%*dRIvXK#!PMJ+ONTU7P^_>5QCTg|ED#+gQ z#FI`kEei0K=qNGjwPTQj?#p=eC4N5W#cVi~37;(x9~PL?zoa<9r&~sVjO@ZVGaSJD zj+o5Z5PI6iUFLPHQiapRTTuLWMcVXmZS8O%;#X8QRgmzCzy1M(wK(>m6Gkdp;p80uPH z-}aP(F=V7V1_f{nj|B?Pc*hzvfS;GCTIi5Lxfw17O0SNto!m&jZ3^cCsl@D=G&uWx zc7$N^r7Kyyci#t;1vnVGCd!~%^Me*6%CK7w(hf`+yyxN+vbCPFxB#03#GfQj?FP$~ z93Al0fd5w+8V)1GA)A!lT`T5^nY1i{em z>gYtkp-V-R?2?jepmhuk#q05g>UHDhfAa>6%PJg`hqa^>=d^d7E~A&e4Wa{Y;jhTR zBmOG}lBj$iM&c7RE+!@voFEB-K|C1Bg@ZKibkg1x-N&1VIrO{R+YY_J>{~1&U)*oq z|MiTJc5-bk3K@ygg^?&DOUrN=WknP$ls}x|orD3bh4GrIob-$R5hUmi!+J;*bFg8G zIz~Jnp?k_B08Kq`3g;cC0Huy}a#B@wvp7s{E-tPT%U-M-E$^0L>~(*mi5NK!V<3AO z8s;#%QTC5Sf>zpztHyj8VLT9GrqJA?xn$2E{r- zw==9 zqB|z^WS300*0mg1IA~9M#(nPG(VRbJ^y~gWsTS}99T!7k;k_HitMnnGL9DBdZu)K< z=u4ahPtdfQ(|E%IJC*_oRY)mG&@wr3)LxYQxTtWI`Tb>PTuY(7y*o@vm>g4VqO&_< z=2756-qMBcMC#*v>eXZV?z7`_Njfa#zu@qkf`Wn(oWhQm5`8*+ZN>FE94>@oZJ}_W zP!MKY@zo;qMrz+Ij$XHB{q2Ey9mn(Q?@Hm%?<`#I%~-jAt<+9dk(bX?nZwhDLqPA~ z>_%U{Zaf^45Q0M^fVgcS!@FRr%FEjh6+1nu{whh~Z+>vgYS}rb2swLVOr_=B-P`*H z2K)q_=DO4#TyZoZXfm4qC1pA#>2v**3mJ_E(^nyAnNhM zWOVbyL>kOF7r}`R+p1NO8;?AGy8br{pha>^{?7sRvj!)_RW_kP*{Y%&&s_7&U0~j# zGGeys%@Ca%1+mukbpp%#DL3?;Nl0IzKPm9vX~1UG+wstsy+rzIxzzqppjPH(U{!94 z7ItZU0jBRQ`Hs95N$gX-GGhNWuWKrsAb&>u_!J6DW4@AQF7$V~2K9V-EDWpPo96)x zVQ6iQABaU|8N7?DV~^gmFmjay(%|mA@>pYj6mo?F z%MSW_o(x8P@JPmn-AvDs(f>pQD^eg(*amd2}h^Nw{E9j z(vo3lJXSjNaI&U@$tQyno-k`;#>>a^o3P%{>o$pIZ_l(m3yY($?sU)RYjYSPwAIe$ zWHuuCT31bW_T!AXdvDKPf;Ij&bM5mbYGY)zm3X1OlZ^LvQ5!d^zFy0pwR3<_ z<;XpM1(W+L94CicxGN&=tHeAGZvAb^VG56Se-Fs-rYdDcWN|6)Sel-_bJO;B19(92 z_KIYxt_Hu0z5JlPP6(EEG7#tjwpBTXLcc1;t3x~@LxWAoGS%X8{I9UEkT=HIJ-(~h z!^S=IcC%c#Od={QOt0x}E|H^%P<+@@Ey1cr&ypB?y!Gtkv*XdB4}|>gp`+BXOMmPx zv#>lFeg9|6yJQgu#Ybcj_|`R&ob;9T5B89-uo&w{m479_EKs7JIp^IAJ!qg{hh51P zAP5S-xA%Je+5$bf+}`c}JY-X5{m(X_pr-a8RJb{xO6SBIaN{#u7Z~rEzL>%v?0mfr8@_80$4#Kt#*Ums>W)rY@ZECvV= zLwSBdOv?OZBA;Iazmd`M@aV6Kul=v&<^Rx}e3`2B>~qu6Q^c-N9H(CBm}PUvzVz$~?B`GTa_CO8UJ!j@a@H&9 z;^e9=vYVB0Ib6GM5|`g;TA=oB51tu0M(FDbq~gpu=i5X*+(#kLlf92>MmP2xS?fpg zH)`w34-5BdMsYSAn|eA4DXa2}UPy+%spC1q1aH}$6J8k1`xxQ}Z>ATWf;+$O*d~BF zanMp3XHKpouiKp0r(Yc^RXZd z(`Y-NFlTMv@+?3K&jRFPtSfW0z?K`h6V;D&w!L!vnzg~Nl|wm8%d(n=FG?CNYec{nx}ZgWmX?vq5ZqtKRr({)6g2E*Pd6FzDGR$L!b%*LrSIl^E2LM zJfv?4KTa^-FLEWhM4EGHmp#RN)LiDvo~Z9xp{`yV5H| zM7$7Xvi#p20W%G~>j zPLDjU<*v2~9n+p~+>PN7$&+GJV#8HQq8q(BzDLWo53d!dwoID>rasC>Ah<=uWJk8F zIjyB_ETo*l=0#|3B(hh{rnE$dk)F@;BY}_?F^6 zd^#Do0F!xMdr9HQnH);7#H9PRy;uK9I{9wJ|KX;7k_Q;N%l zOAwS-AVoG-gN2qj#cbw%FWu?=_e*_$Z3t$T3Y|(vvZ*KUuA=yo`u{OkT7NcVQ}zoN z=+hP6S#Kh{0?wgFyLLXTn_GP)vfv@Qh|O~@KU}}w5=LCEzbOu^sPsZjHvQzSlpB0Y z7@q3a>vK1>!_wG!UCHxc{htQ4*55CVu6x zEY09~2zi2^Ajpq0)RB$ySMui(6UBV_&_+<7)T=r8l3safSDCIp@s~W?5>S<(%Mza z8ch~vSQ>b(3d3*oXsBAR?SwOV!O_vgK8L$ku3sN%{PQ?7Z`AvvHyM6?dn#$)#$E{$ z>h0^jPuzi_*|e-(K4X}XDdBFy{SsO%to^xK>=F`5ey4{MAw6wvZEs>?kl)6D zAN}|6u=o8{Nxn=4icKw4wKV3xcpLT3LXE3Yfws-(??sB-eX% zYTbhaDNF$u4y?_<@7s9~$8qxXDqq(f&GLa3@(g%8iT{TWmr-(ZauLnt>C3d8~Yq*OiuUEN5{R zkWG4Y8z&ETX!F-SJ~&&;M{~{M28cqIKhrUzCI7+Mn)}Ym&ffMs8T>j0;5?+I>YE$Q zb`;*!z*YT6lsOAl19{MLzaK#t84(SsCF!m+x1%r&+gbxc1^!L4?OD}W0O$JBRzCM17ObY$|OI~^R@7|&^?uv{{ z>J2;5)?Hf*gr~n+ez?LB3?(3P?#>K;2@(bd#?hJws5H}XD)JAEs!dkTr&gI&LG$1E zXZo$?*4F9S*;^1Ai4rcHFnh==IUlEMYYg(mErY#znbSnK37_%`zo;;Uke8_`Z9qcM z_&=Fryq6sZj_~RiKb$U>a9itwBXy1ci>>dD$GUIdzbJJ_DizASD-9#c&TJqnij2r8 z5wa?KOBz;LNl1n4P4-F>%E(U0%E}JezvH9l`F(%i*X#Gk{dzsmeP6EY^LdYR9OrQ! zr^`ZD6<9e0qY0hHTgr^G2-O{km>4n$n#qFAL3CE6&=!c8RK z$)@KdOS``-T8b4V8qLDPI|b^;niGh(2GM7-;F}I`FSNDCfQ~dUG(;#wG(tfN_t@u2 zeVVB8>WH!%A&KMlq_}wQ&;_X*-|V)^o{BoRnkcc7;N(J_YIYMyLJ^(8$aVGcQ3&7g zp{s1mPL`|obvFwPr-+T3s7Trc=FZb0Ka`XlcUI759SeOK z{#&iS5RyRW|6HNDF{3d}!f-_0J+IElE#Di9-g;}`Dt$V!{RnrLXOnwpc-uxgTyt2J zQggConfvwY*Cc1?M-cyT>6JvFVR`m{*hI2cofz%QN z(j$t`%fRLP41G1%+(^jv{Ft27vo8!*lZttxnb*JXKNfpvtJH?Yu6g=DnS6a$YCS3? z>`~suTUsp-A3jV==Y_`hTVM)G0Bks?skskoXvb^|aR_dpi4gJ|uRl#!u{b49x#Gqr zT**3;+wI5+3AeY9#0t&fgE-vBC#-sZgvG^mq`9!{Dp_|NY#g{q22MgTZ%acrVz1;+ zb$6%geZrkq^3QJ?-E7*WNj!q$eh=Dx`(&?QKS)ADEYU%Jy4=d}Va26n!Sj9$mFO?~ z0`v;~t#xYk#h2McaqDTL+5{U8qG6~sWcgHhm_qa}J(ls^78}{~IU_gLs_AB`=9z^7 z9&zr{29$SIbf5E*-vSCO_PgO6zghcJ0Iv3u zP;a@ayoODLTH5q*ze6--7$?)li@yls}|KDU4D$^U6ef=Z_VA z*VzbNRGi=LO-JXv3|0|`g^->4v$RBRH8UW$w$xVIeNmfORq$=Obc>#Is3k&PYqL94 zEZ~X(@jZtg$L;0u+&xT8pCN(p9$GX&?nKclc%r`^>qXB*Pj4Z#Jx{1Wka_IZCA4HL zwgeAm5FijM-3NEN0^)@S!*O3KMt7AOW_6_6JHtN`?a&`SNWo6N2c}y6`7;|of3VYJ zaVQ$@*9zjcm=Y)UABhg<;Gy-xa1NH#WY@&4ElKuT%yKdB8|@zGjjT&AW*%PSS}4xl z7Eb-le^fr}+uFu;k$;2hve#*ID+t9S?HTMdB($3CeV4D^H%x_DK^Lp?g6A=2? zC=#+aB0&Ka>)QFO?njsTRR~as5&`#~&C(v<1M!WFaR1EWJE{2y+5Z<)p;0BC z4-t(6_*qrfC zS4!Glx4Ty_@K>l&<@!AOByB=JLwSDKf4u9FzTVCaTlze@oq|h9Na&;Q{t8f*38e}~ zL9-v|o`n{Q2TV1gl;b%6OYY*ur(q7#QXDzX4}-AMjPA>w556K`+qfWHi^EliBEEb+ z{HB0sr`^|obP(nXD|UE+UiglnB>TQa;Kd>F%{sU}W_GiE;k4qq?B93JnmA2KT5l6z z67p*RY(ps(Wr|ZE1$1M5X@W#@8)KAv`lRshkDQ8%tg3&UK(aR1Z0X}iWb#u5*_$1@bs4cG)?#t*Q1*{}eK-vAzCarjl)|6Vul@Suvxjo1^ zl=wEPB?CFx_HXvGL~4R}2<@z=}a^QF=S)Ld5&7mb&GgxzR3pwzhb= zTA+t_e_Y-o$Y`C&YPRt}O<^i!cSIr;Uy6mnR`idJDO|mZa2HOH)p^Qezs{pampPQ; z%J2HvX8al2llRTMh%YaPZUA4_GuPkCN8(Q!RDLD6NL=Yp!Q`z_ZTgJbl*4#Vo0Z-A z+@`E6Sw=-5J=`=Bjj(c)?TTp2G-X5`{E>D2UbJ8k_NhB@&r z&lTDAU4A#7hg4yBx#w1>M5)*pq2nE4z>7vNyr2HQEorHb1}iR{&*=CuC;4u`pH3jf zA6cZ~b3`)s8SX7=W5n`N7|N54q3<4U@T%?i5$nLv(3>*!2M>n4_icG-Z|PFb|0{IT zCp^tZDf$K{?)YV)!dr7xgO9-hk`N990q2EXSA><~ zg1|!0a9ekkSQsv++K>|j&=g2Ex5W`dYxJlIU>8+8MO>y^%wZvs?oO!Vh z7coDe$BFg@UyI(AZp0Mwz9tmO3cS3$Rw9wo{)>x?VO@RzB6F|X?e3R+Qhwsc>m4=@ z*G}&h4F57pK+67RMZ!yos;l}}bri#{0`OBg5;nt5&&pcQZ1>#*X$;uwP|(;7UxwCb z(3>|-%j@LMsL#WTqE^DxTV&dP4i<(d*dJEeHaFbp3BiCzsLg0HOV=bQQ03V@Zdf9s zgbb|EEwrWJn7OUZvLgEbeMnJ?BO=Iz{(0f_KW8K+n$vzNAUy%l)j#3b-$o|LEKw09 z*{$@lg1{3Acsaduu7q7>zx4U@vydh`>G<22@azy&IRjlM9I`;sZI%K33GMJe(U_`@^xrx4$Zac-K-8g?EI(qA^LeDAsYZ$ z)VhY(=b)#OA@U~p8X}ZKLOpWSlFAI1XEy*@*~h%G?k%Z0qPzF(Q7hXWKsh4G*w+#8 z)Efpy{7}*!HxbW2!HT?hnVC)nRR-`~N$!eL84%F5;HL0OF_qxY`=iGrr14UB-#PVE z&r}+awOU zv6q)6A_B|DdH{qjioUUb<)TB{Uh(gu^N!o>VIQLE*tidS{%N9Ec=GZ~-`SU*#YdYu zoOo9=1v|Ycc$a$xW7pttI^IEZ13mB+5Z;W}EfztZ(~sK^X%}}wi>V0mL+a;)d4E>< zP$Z|mkihj0amPaj2k(Ul#b=0PY1w}^%DT31i(okQ!-{J%LI+j0#oin`Y1*xX?D_2S z)W1Jh^&YB(-x-2^U6tN`YEh{`Ah~9B{47;eR)^XBKMuS5hU5?mOY4RXSq0h)jMj;*S$XQ){vB9MbZmo-iLyYvVC$2YU~N!W324dNrU?{<5(o_j|U zm?cNZnwzN2RLhy;smsMsK2=&ZEy20he!opRrYK1@ZU;33KT(S#;u=KXI<`uXtAz}0 zB*jP!SLa?kh6;Cpt9YA@%0tWtI0z9)fkCnf+xp)3r<7E?>u;tfF4=y3VfmNS`pO&p z=j{6nHx(_oFr|!9e9blS+daPS7Pq5y#}r57npDgkEvRN7HY^-H1-^K)PT{-Y-Es~Y z(+&GiHv!s?nK@y|q6D#mM~@$$jAo~yp<8#3*t%XEhOg&O7^&*Jq_fZE);Sq#>a9N# zc&-aO9?AN!RQjzMs1jdGf-13wy0$BjPh~oFC+7Dix%`ajujCW!e11A`kZ*VmH@5;J zs75f@o^y*H!AYqZ%|hWsL9MR^pkTi3onZU0GFbbeW2KP}32h4|Q9XYH$>iJi4Eg}WVV-!UL96j=y z!rILnE^T;bHh44fwLkqNsN0QX4rM>atd&tuofN#O~b9 z;G2Ej`u$}8*7-=qq1Z~N=Sy4f+MQ~_@3LPIwVQ|mHWbP{*`9GITE;K)-+{)-jzUEA>QRv6MDSUQ8^u=CwT^*H* zo}m3ZWel>)Z+7lpbk=@ja*E&PqLh627b8M3ERb58fUARJHoxo9vgGLI3@X!Y>^?Brcq_w=@pF?)T!3F!kD>i6_5gWn%#i zJO42j^()y;^UAt}FGBeCJqQGcqaO%TF@(ko_V?hiWARc;oZK#M9E@vO2VTnQO~z_h zBsz<|@!WV?ZdH|@{odl_oDvdi-V4%FsULg!{|sfitlTsxU;bD&{7rFxGt;Cbeb5Z}?_cYb5TLm?6TIAJIv~mb7rDXpDgCAn& z(h5wMUg1dbzD@QJfS7n@W+u0&D}o@-3B_XvLsVsyBwz+o((UI4%>4+2y^=#$=PNJ2 zJN<+id08{s7B`3Jgg$4+^+m5P)0Dl#X>CU_pa?vb3#g+4jRM4p+o(d{g9M}a$2J=w^U37aj_(eW)GomF>RGIJAbaxw-bvn6w_WS2HzLCo~UlL&558uXh~&&@(%&7j*A>S7|VV5uoq}q7h~mVUkIAZTU%QP zgnzPJy~7oP${Kl5m$8a!lQ68&os+TdhWkF!y50Zy;X`o#9HUgsZ{kyhH!au%N5s@z zx~@!Vp5KxkZ>Y5_7|zbc()M32fFDu4xn`pmSU+?E;ra}7-K~;|ug&EgFYxE^Aq!61;b37Msp@5HDbaUx}G%hy7= zPliK8&1l_d^oNVN0C8gj!ouW$PkG#<@(OpT`Cqo<1@A1x1BpWol?<_jS1Ybbe{g2#$;YQ}R^Q#%ykqK(#nZ(@VMNLxqROEJt-uq} z`)LwR8>NbW@D`WLD{ObLlVwDCQz2z?$l^)g(1**eN{WMNv+uH|rt9nrXn$G9<8G-u z6N3t2gqXu__fTEO$AAu|;h*{@ChCxtS;ilSh%Ho|Zg)(>fyt69Jfj(L^F<4M6+O5Q1Z9e!K%$*>h1FihePGo14@0 zqLAVRJ$*_lLn4FnaWqgYuOS&385Oj%qAKvaaC~rJ09tdp14mjrtW3xj9{dg6f>8Xs zo_MZ$zwhd=o7*>mbyKxzd`v4a+SZ-kQev0imo2loY*T~t2E^?%l-Jc|A>tm0{CZVE z>(ZpFKtL_2TQlGd6hA*liiU!`I8`S)2_02sXaozpt%=FWVbu%w?Amp4K;XcE18j#6 zuUdoyktW)Sr|1|G-;}D=-55xpym5vsvd!GyKm1s&e7jZ5nl*O)7`=Pj|Djc!JfPO{s z`-r0Hq7&~et6Sf%CcF9UN5Qm7sY=p;99sA0ux|pSo2RZG_r~AXQ2KUK$235%lb46X;dTY zLkA7pvnO|?9}(P-;@%{+xwcX2uEKV6BGX^^{9V>asf4&aVVO2#>iFX?@OKJ;M4@TM zKC=R{qj!r1U?d=;M$kql*mFRIh|fVnlhj`7CW+h!!l)x}*SD}cFz%$^n_jR{BMo_u zAbx$hblm{;00R5M9UQHCEqi$OOKMP2@%%1=rt`{y+0ADUE$u*mU2cCtzZJtDd*h$k zkAj)80$$Rw;nPU=ZX*&`Nz)ZqiV!Y`wEKM@A1Y|~|BK|*ci+i-*nvHJ_uh|+Vg=m! z7V!2rk8~zk;UMY04l2MR**kY`uyP(5DlQ(*Md=R6l?+VHXJaL)ngExhO%5}&`$%ie z$0MBH+|rI1t`Y0HnhbXLoiGTEKmS^XYK;9<`Bwa&?XVot0QQNyi1?iB#Q%>mr@Hhk z(8lDq+E{@{!9O?xAurgY?jdvDOflm9RMzk=H(zL#ME6H8v8~wq!7$eV0&h$RrsLAI zY8et27ssz20hG%XD|P)DHGNy@DAVgMA{M{H7way7st|!J5dH~Q<%_Y3R81a0w?MylqiMrc)LZ-WU~g3nj27~y^i#7t$vms#}Pr+%m{0$wKMZV4ju zarwiBl_fFOb%ukz{S#;5QwZShk!B6xCh>*u1~Pmk#V}qkpeg_&eL_R&G2X%mBxtya zyea4no4s_Nk;98$yuths&(d@Ub44vM1tj(DG~@2E8D8~toc*bY5M&cCgB+GjS!a$0Lv{X@<&Lzq1$|Z7bH8&2rwFG+CDy`?cjj& zs6%lx2-gQ77(K537Dzwuo|u^M^2$^I0)$^ExGswL0BV$b2@A@j&Js{#Hq++Rac6)F zbg;#R3iIh%>%w^-AjFAlcFdOwyOaQK=M6s7e&p+$eJmuHBDA%1boZsXL{T+xfiBab zNC7F7a?n~SeKbfHUhrQ7>VUu~u6-O+Py$g`%R)suyhaE@z7VLiS2cfh*@)^L+tl>W z=ytOcs~+n7@jq{&+#f(${@F$<_BuP4zQ6{Ab&&Md>}H>}$nCp@&ioJH8em;D&HZtL zpxFEZm%*x?9RAHkFJy~{$zxFq(jGa2&YCS>=e~*xhqx@qEDV1P}CY*o5T~O zqko=XF2l*9$Bo#0R4L+^m@Q}zP-U)4LG9|CIhYGjW&bmpltw5=gYPf>(h^P{vg^sZ z#RXICsKLp}$`TWGG|ZYHCn_mfdQgZaUxLbx=}`T(hLme+GV{La;FrjH%|JG_&q|nE z)MDS3dWq#^ipMcrf7mCucEp|0Oc%=8RJ6hSP&x9P*J}z|w?9)0Ck`Uig4zuUIG0Il z@_r0&s;15n0J|EoOcf&91eI9%-U4;pJjB_(lauw2Xb$a@bQQy38kD37L=VEnF%;jW z6^-_7;k2V)VJs@uiEsU}i{@kpViA+CG1Z1uhYlS&Wj*|qc%1gB@VPWV$T0+1gdavF zo!EK|xuN(Ma9JqmV5s40Bs z2$h|NXfA&$QFa4E7x`pfo-k~rHj;e#5vca+PAlPqY|rsqzKkAwBXT>v5nk#-QpWCTAX zN^cEiiA6TME}PKGkq?yBBOOeNb!A4LO4RpK2zrf*(cWeH5ilr-))Hu&-at)8L);Dm z6_w*MQe4@6!1qcnq!pckSmgJJHeDw_#FtQvzmjM21s9M&lW|N7i0_7f_AN10uZ{s-yqiuk=pLMvrVWVD|wJH8m-Ky4j*{W`WQ5V!$2Q%z)cnqongiiC~cn;Y0dikZK}Tn(n;i-Hf3~}VL4zXF2_6?{NE{L0rv&g z<_S;mwov`NhcFmJJ>m~mh4SbrA)bQsRexT3m@JMgl5z8%OI>XQ5Bi{C-38ioLa_AO zzU{yypuBNmZ*CL-(v+A65#hYGF|?plz<=*r>_BwAykhbfOA#Q+XW>Gy4b+4Gu6rz(P>M9 zDQ6x<#Z{WXcGYmJ%IF{0DF}wAJ!#zVFUG%&;I<;g5KAkXp^S1}NBn)5y#FmDm@87>qbeLh{fHIhGi1vR^_VkR}tGp*Rd9tpbw0%6LvJ=T` z>PK9Mj;xzhxsLO*v;9yMCShDb2*y=)6W8nh;HijYe{qV_rAFTn-o)^Kej(t4kI%Mh zTlOMJCFm{0fD8QWIW4UhEz>dgkAHLZO}@I7I%)aq0kKbikKYSeV(8!QfzT2$PmY*^ zcJTx+`hLnbe#HE-q=KnB3+g@DR867AGyz|qK7D!`*N$vzW~L9|CW%NB(B7uK|AIV9 zhR#L#cJBl3mNJwe+J-BAb&wh>Irdr7#k(l8A&ZyJ*_vv4<`{X@g6iS_P zB?wu5euhv`#~w9o6h?Lh>>jXYa4w9~U()X}IzSgkz^*`NDuEI`^7sGQc%IdeKoqX# zJw=py5(3Ui{c_t1_?JezTXPaX*TQL|3COGuCRaaumK=F2WPwN*k=4MTKWrLdJ8;0G zz-H`4qu-<8r_T)%*kW(?kM+tAZBZjUfQkt*9xkqFTiK_8L))N+gW}BqTy9^z+geuT z2q<;2hO^_{_o&XF6EU5(C74{-PymBNj*ma~jO)r-FbpW4#Kpt_XYsG-JrT`F!+wC1 z$G@Z?_O<{L9wJ*+acCd6{WY(rVQv4zV=M6wmm*v2wY6uP!K0qPc1EgoDrQ>g&sY6L4zP$FOHyj-{w!B}t%Isz88ce~%)IDP|5&sEAYJIsh< z1$xFy(TO}yj1k=HfFvx{vwA-&Ngui@mFho@5>^yt*OIQg-UG9zF3-(1c%cJ7fKk6@ z?|X&lWCT0sak7Z~4`O6*hmhsCbty8L#0;Jjev)qcNIN){_E@Sa@PV%1ivb8cDxj+|CyJS*KRJ>d?uU; z(AxKZRJoUlxl@?(@V*KGWiMtG9sKv-)3@{=2VX;(r~U3h=0a)q8wOYE#vjM<`XJv+?YhR^&O91!4f10A!V#w7gW_lv4 z@U3yKYOEqc|7`St$mXkp42aYfO8A?0?b>x(U;l?;u0oY`%rCi9Q5CJxV8%xi0hqiR z2!fhL_P2WtG&I`YPpXj+3v*?ei$BA^yREMZGwpy*ct+NM&b-VJ^z;mK4 zfBpU<5f&w>r=)k7?R#*$WflnXj)&2CT`*jljNyteD_)%uV1*ae1+DYo^#aS1#RuT2 zHf9ki6pUw~)!a{$+RWjftFz7S zIe#DNL6ZhSlB~(O{-mrR5TjoL;V6ihpq~hm!@3@Qy6~s>he_rgW{~1y9Lz5m?xM-K z2gU*{JR;Z!a1ph1W|m)Lwn+jk$@tb?V8e;2h~0*_p87Ki`Qspf`k@DQVLcoK(Q1ov zNL=$h2Q(I{D=RxEE$O}E!hQaFXd%=+;8?$dS@sLV`aTtCq71!Z01kw{-8pZf6+P7x z4}+JALK+d^AUxfNf(+4Gdcj2K&>>F**0Ymt>*0|5%%8IV-)I1dC^o}JV@QJ{f`khr zdaksgf#o~5Dx>~)4zMXfOpp1_IluRPk7M8CqZk!)6sm3*$cRZm6)58?qZ&q3IN|&r zZJS|MQXl7h&i#hCmdSkfQ~Joot`ymyJnzrci-=t?whK#tr;6FGq0nyfU{$VVj}j<) z0sR310Yv8}(txn9xqIiTf8NVUa}-EbBHB+j!W2n_Ddyj@AA?AL5d&S&D2mzy2AT09 zlO_manA-6Lk($NVXMeI{j0R~2`jyaeN#H@3O`%kVdR=&HH_HDYes0yywJ83T51)kr zsoVbf=hz)FHn#gQF)^I)LO}(`#IW9en6jo!b!*fLoHN8}8v1}|9W**=xcON{?<@Hb z4$|cmtq{cXBnqlxnDZV47aulrax1a^Vpe0;pjTa6MBBvvr_Y~%+M_I14wLQJ;iy$9 zfM+ENBbK11zRlL&&*gWjeDRkvI44cT*911OtIPkqUAbqD;T%Z*DVE1eC9Com|80IgF~Q!)MzoIppUCmu;joN)02KYs?IYka^4 z2JwxIAEz7mttUJ%E9<@X_3PJ7R@et$BFM>3(4U?^z&v(6_g1kSoF5;NQ!frh9p&TO z;|`)Z^dd7y3kMGu%3P1u?%q;z4N^Cr3vjg2bFB zlMAop^{4Brs%?Z#kjp)LP1fd02#;UQ1)ZEYGI3j%78gwtU&-!&H-lW8o2LBowDn(; zUirJCyop2*qAS6>mEw4bKY`OywRgj~6{8!-S2Oz%V;F4|M^tvtFe$lui*9=LMFk(0 zckl9*K@4fr@$NGTv#&5YtCk3qpYN_W%D{fuGNS9?uVeGt8}wY>DAf~e{TI!@{{~`S z2EgF(DmZ4kwqmfWtge5`H~zk)%Zbw6_S%`v%ci2%hz|nOr!NA7sH0BAAv2-IA|T9=$LGND*wG4EkFRT zG55_*-FfC5cZTRr+Tx_WVIa>Uc~mcUoFjqw_Vzvv&D{^NH>SS7(Sery{xfY43K)p^ zPDPM~>$yZc5e*zX9EX7Eu);HfGL8H3XMMcO&OTV}{o1tC*G&huy^c9e{#rrqw7jq8 zuFPN?+Rcow_I8fmOM4WudgW=QQ0myXE6pw;kG#z_ZXee_Q$u-Rubi>UJ&*f=Qt})z zb&IQHzA__ud-A6y}7>bJfY z*>I%9tDiM{J|Q=H!-kDS8qJyXA9u4kNkK;<<@}7GO2+WFV?sh22wR&0n<+WItmwUH zV>7qEbOKS_@7&VW3rJF1z%Kp`bf(RI6`12NdNz`$BQX2R7}@B}^&{?%#vgBn&sCJ5 zAL>^e{rQDJp`QDjNvBgf^i)!h=T`>C_;dB5!hDV#PV`h?#_SZ)~nl-985ay2*(Ur3@1$eASE3lLuQlGe*1Kw z^_d&#FS2^@Mmax==F1YPLCtAG@lnaazqGUz8!>u}=Ewfb`B2kurELmV)v?McdhqqX|&fr-4z z`Hg3u+;8x^$AB?!VTekVM2c6_ov;r$`qKU^m`tsxgJpvpiXMXak6$8*HNdbJQ#8RW zjp?l?VnB>37-DhXZ*rbGbp@tBRomJ+TbqweJ$!M|$h=!4Cf#6JchSCZP=k>~ia0x8 zUhz%UN=ia^$J{MOBO4~{xIk`lnIkwJ!GVEq!YxZWn0f5vg}Uvd$4Z@k55EQwnPb_b ziaVM9egJ;_pC`s-G>0-0PYZ~+) z`PB^E5I2*NP8at*Gi0Epr7gfLnyzV;nS#ecD(Uyf6>n&)=C1-n1LKep~0NccABKa!S_ z(VCehOA6jN*pq51y0InZ;ijXLB3GEVk=(abjPPq^^xJz>ZUKwCSui)*hMSYK2~*16 zBHWchq%|`)mvVch<7Sk2e;dSK5;9(JaB?cZJW^6oscLFICx!+3F$l=Rihav4c*x>B zb;f46;S2_|->%Xo6Z^RCI_)Vqeq5zVrsS6s1?e<%XHlB$!yOul8Bw`?(dSb9H(?ou zo{`^z;Ti47ieobY3rWEL6qA3JV+sPCVQ@W2m3iA-(MPp0or^;ALy*lOmD$xvF?ri{f?o7H7`m^qWR% zQzm1mYhk}3o7|=?+n=8N8B;}=-`rKMvOVJ>7ZV?@<>&@l4-JmnP%P`>{tP{v6fW>s zuKeYOSBU&kFYUgSJuR_yz+vq2Ro&Qb^B1EfLm>f;fdU&rUR`l_#mIqMx zPkbVipiYWJ!N@!x;CW|U@$#&f;7p4`wA1ZsatvGf2KG@BNm8Gq1eP&>ji>&xWO z*|#Tg`JweYk=-N`wfdzivAlOE*)Hkhy+eG6{vhZim1-Kv|342&t&qpz3RPa^pom$Y5{Q8^xd zC1Nv9trs~}`fG2FIF_{qN0)4iCu}3#F-r2If8S}`-os{F=uUFd#W>=p*~P9Vi1z3v zHM8#g)LHwwbo*rL$!#aqt6+r6YdJZZ=2v!~Vp2KCnGOS?x>wWPZ-7ZG`7wJ^NSNN6 zkFMP>1m@3D4}bqUimf;;nN~8&Li?sc23^5e-fOSR$juIl$DPhC&evL2;MhyU^h)T+ zZ?(2~{Uif2lDomPn=DU1DiPIBtjj?0vf<9@Wgm2uC~G2Z*son)kR zDg)nJ6zc0cu1fqvI;|63M$R?=(eBDp?NGR(ueC!Q9q|+ti?d0%Z;`+LBwWsyHk_HA zR_S?nZDXIyd-bZ_r4u7%+!oEURMdY3v-!zAYV=Jitgh;;{iaVM{SZ?BC0wwSs2u*5 za%%1!;S#8KQqbvpRM4s|McK8DgtN{ZmTP)o)5si}6I9WgE{sJN4w!t$TI&3CmDnwE z3c8C`Gd{J}w`v&7+f|QAvhs-AxhU)Gr#G?TB9W|iwz=Zp9sd+m^9~_ zs}|edWfd_0b#vo!w)oR)hFT90XEph(2SxKi1K*d+j^Vm1f~tYmYR`HlB^E|O{l-axZ>uq{TTb6TvwRcgZ@X%$nMD{NXvrp9S^;^F#7FB$C*rQU6W6GNTQ=vc2VG ze~kdX_WQ8Di5JV7u_xQeyh3M!p4s!t$M~N7rHS@I&(QQGN)o9SyJm6SxAD-dkg=Ow zzKGXWlmD3bhSLBmwPDC9ckEENvPwq|nuB=+ZPS^VynxW;!17c@&kzV#v4FOy_BcJD z6?N?Rmr{%T;;QUFU;ynj8hzS}NwX%%-5aq{% z?uHSu7Xo9DoNEwZIYEs8oPHVO)mi|R9#=BAEZoVg-nypZa4P1$ZF2k;Qkkh)-KM-V z7T3a9B1fYEk;Fp!v(ns|F1-H6S|cXA*slw;AQMbyqv!;Ax2Kt2$$ zeKZw!-f2#a)MjaVog30OI<*5Ftmo96t>f=)g6_{I;JX*7s zb|OLyhV;=92`2!((JHD-iu?O4arUe@2q^@GW*ma~;l&mxFTeCc7T_l{dPZXYC_J_qI-KbBn) z009R#cPl15W&`bY0cDnQ+qOoO;S-Ttb8vAf;yZ~lZwNpLpsgdRw)OYzymvQGd?*}OI7mI#hj+$nmkz@ zW>!NYiTNQDJE*oKvHX-x&}u8G%mS8@@Av0WZNgR3U04ygYj2m-j~^4#4zanYrWDZ z=$In;1-Iu13}P6Uq;4VnAP$(jR=RUl<7(QH-G){F^?;m8*zc%hPjc5o|9CayS1gMa z6okDa<-E!+lGncL!zQ;a;~L?oNu@GaxA%R=7ai@?{Mkmr#`;>=%G!vi?v6HR&jvN<`VS z?+0}jOcPx>xHaOY{uLL_&LS+^>Eku+I{(UfKY3dQ6YuYwyo1#KrQp}O7bkA!P(Hbw zs35iHOL0yVxpQ%fKLtX`#%Ws3+bQR`ln})!-6yB|<3$^`Y}5H&K;-JB6y1}r<-;13 z5BO~)0876vns{aIWO>F`nRA`UC2gfVD41sFeu`aqu~5vB7%|%OI!w1P{|UqLEGIeX zw2R%!O!>Pn4AT!WzRk?rEpk)f&$Q0yWr@$&T4Sp=t772-`cP_eQp4#L=f!`M2v5&R z$;EGP89UKzu-?ID5ED?WH8OImf1v-%0y3S3i^-Dj$bB{}8BgabrwcOug3-hz#Lq@Q+bNn3?J=pT+gCOCvYVc4Dy9|7J z{Zqf8hohfA^At2mi$ShvEdQMYT_R;R$yEn`~ zuf2DTY23u>zdDmKhPAy<1JBRDg8zR-CR(ztCdQbziKKt)owkP!2j;K_#z4)K;R)u8 z6#7TXIymIl)Yj@OK$^nz=)YzuxR^oRi@HAV25PHnUlR#>QeSj3agMkKmbSb%=4RbY zDytJSrD)BUS5i{PGmL=*W^TjQoDn#~aUmj0i}=%?Dupz^u?r4JMK%ptGZ>~5M(oLt zOB5)!-)Cdz;Ys`053`hNaFiGJ5kt=lEKvT>d9i2yPJH%RgY|rs1WA^QPfMS47sWN+Eu>ScyuH1HpFMlKVXN!^ zYpad-&G^(+6iJ**10r_a1Xq^Q8!sq;z$6_%vaen_iclE!N)% z0EcTYfJHn1^;W-Qk`w2A7Hs-aTjxy+dB#6+PVC7kxtgim)=k5^bwUpDJpA1^{IVd= z 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 CLek3s literal 44608 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%0DhNS7* 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 to download the full example code -.. rst-class:: sphx-glr-example-title + Click :ref:`here ` to download the full example code + .. rst-class:: sphx-glr-example-title -.. _sphx_glr_auto_examples_tutorials_run_annoy.py: + .. _sphx_glr_auto_examples_tutorials_run_annoy.py: Fast Similarity Queries with Annoy and Word2Vec @@ -27,6 +29,7 @@ Introduces the annoy library for similarity queries using a Word2Vec model. + The `Annoy "Approximate Nearest Neighbors Oh Yeah" `_ library enables similarity queries with a Word2Vec model. The current implementation for finding k nearest neighbors @@ -73,6 +76,7 @@ Outline + 2. Train the Word2Vec model --------------------------- @@ -113,6 +117,7 @@ For more details, see :ref:`sphx_glr_auto_examples_tutorials_run_word2vec.py`. + 3. Construct AnnoyIndex with model & make a similarity query ------------------------------------------------------------ @@ -169,30 +174,31 @@ Annoy – both support fast, approximate searches for similar vectors. .. code-block:: none Approximate Neighbors - ('science', 0.9998779296875) - ('actuarial', 0.5997203588485718) - ('multidisciplinary', 0.5991933047771454) - ('sciences', 0.5958340764045715) - ('scientific', 0.5955467224121094) - ('astrobiology', 0.5923857390880585) - ('popularizer', 0.5910311937332153) - ('nanomedicine', 0.5902301669120789) - ('astronautics', 0.5890269577503204) - ('poststructuralism', 0.5872606933116913) - ('crichton', 0.5863060653209686) + ('science', 1.0) + ('multidisciplinary', 0.608674556016922) + ('astrobiology', 0.5977040827274323) + ('interdisciplinary', 0.5937487781047821) + ('bioethics', 0.5934497117996216) + ('astronautics', 0.5890172123908997) + ('astrophysics', 0.58620685338974) + ('psychohistory', 0.5828591883182526) + ('sciences', 0.5820683240890503) + ('actuarial', 0.5794413983821869) + ('scientific', 0.578777939081192) Exact Neighbors ('science', 1.0) - ('fiction', 0.7604568004608154) - ('actuarial', 0.679552435874939) - ('multidisciplinary', 0.678708016872406) - ('sciences', 0.6732996702194214) - ('scientific', 0.672835111618042) - ('astrobiology', 0.6677011847496033) - ('popularizer', 0.6654890179634094) - ('nanomedicine', 0.6641773581504822) - ('astronautics', 0.6622022986412048) - ('poststructuralism', 0.6592925786972046) + ('fiction', 0.7297012209892273) + ('multidisciplinary', 0.6937288641929626) + ('astrobiology', 0.6763160228729248) + ('interdisciplinary', 0.6699198484420776) + ('bioethics', 0.6694337725639343) + ('vernor', 0.6654549837112427) + ('vinge', 0.6640741229057312) + ('astronautics', 0.6621862649917603) + ('astrophysics', 0.6575504541397095) + ('technology', 0.6531316637992859) + @@ -213,7 +219,8 @@ within the 10 most similar words. annoy_index = AnnoyIndexer(model, 100) # Dry run to make sure both indexes are fully in RAM - vector = model.wv.vectors_norm[0] + normed_vectors = model.wv.get_normed_vectors() + vector = normed_vectors[0] model.wv.most_similar([vector], topn=5, indexer=annoy_index) model.wv.most_similar([vector], topn=5) @@ -224,7 +231,7 @@ within the 10 most similar words. """Average query time of a most_similar method over 1000 random queries.""" total_time = 0 for _ in range(queries): - rand_vec = model.wv.vectors_norm[np.random.randint(0, len(model.wv))] + rand_vec = normed_vectors[np.random.randint(0, len(model.wv))] start_time = time.process_time() model.wv.most_similar([rand_vec], topn=5, indexer=annoy_index) total_time += time.process_time() - start_time @@ -249,10 +256,11 @@ within the 10 most similar words. .. code-block:: none - Gensim (s/query): 0.00879 - Annoy (s/query): 0.00036 + Gensim (s/query): 0.00654 + Annoy (s/query): 0.00055 + + Annoy is 11.88 times faster on average on this particular run - Annoy is 24.36 times faster on average on this particular run @@ -323,17 +331,18 @@ loading an index, you will have to create an empty AnnoyIndexer object. .. code-block:: none - ('science', 0.9998779296875) - ('actuarial', 0.5997203588485718) - ('multidisciplinary', 0.5991933047771454) - ('sciences', 0.5958340764045715) - ('scientific', 0.5955467224121094) - ('astrobiology', 0.5923857390880585) - ('popularizer', 0.5910311937332153) - ('nanomedicine', 0.5902301669120789) - ('astronautics', 0.5890269577503204) - ('poststructuralism', 0.5872606933116913) - ('crichton', 0.5863060653209686) + ('science', 1.0) + ('multidisciplinary', 0.608674556016922) + ('astrobiology', 0.5977040827274323) + ('interdisciplinary', 0.5937487781047821) + ('bioethics', 0.5934497117996216) + ('astronautics', 0.5890172123908997) + ('astrophysics', 0.58620685338974) + ('psychohistory', 0.5828591883182526) + ('sciences', 0.5820683240890503) + ('actuarial', 0.5794413983821869) + ('scientific', 0.578777939081192) + @@ -370,6 +379,7 @@ memory-mapping. The second example uses less total RAM as it is shared. + Bad example: two processes load the Word2vec model from disk and create their own Annoy index from that model. @@ -403,6 +413,7 @@ own Annoy index from that model. + Good example: two processes load both the Word2vec model and index from disk and memory-map the index. @@ -438,6 +449,7 @@ and memory-map the index. + 7. Evaluate relationship of ``num_trees`` to initialization time and accuracy ----------------------------------------------------------------------------- @@ -453,6 +465,7 @@ and memory-map the index. + Build dataset of Initialization times and accuracy measures: @@ -460,7 +473,7 @@ Build dataset of Initialization times and accuracy measures: .. code-block:: default - exact_results = [element[0] for element in model.wv.most_similar([model.wv.vectors_norm[0]], topn=100)] + exact_results = [element[0] for element in model.wv.most_similar([normed_vectors[0]], topn=100)] x_values = [] y_values_init = [] @@ -471,7 +484,7 @@ Build dataset of Initialization times and accuracy measures: start_time = time.time() annoy_index = AnnoyIndexer(model, x) y_values_init.append(time.time() - start_time) - approximate_results = model.wv.most_similar([model.wv.vectors_norm[0]], topn=100, indexer=annoy_index) + approximate_results = model.wv.most_similar([normed_vectors[0]], topn=100, indexer=annoy_index) top_words = [result[0] for result in approximate_results] y_values_accuracy.append(len(set(top_words).intersection(exact_results))) @@ -481,6 +494,7 @@ Build dataset of Initialization times and accuracy measures: + Plot results: @@ -505,6 +519,7 @@ Plot results: .. image:: /auto_examples/tutorials/images/sphx_glr_run_annoy_001.png + :alt: num_trees vs initalization time, num_trees vs accuracy :class: sphx-glr-single-img @@ -519,6 +534,7 @@ Plot results: + From the above, we can see that the initialization time of the annoy indexer increases in a linear fashion with num_trees. Initialization time will vary from corpus to corpus, in the graph above the lee corpus was used @@ -594,33 +610,34 @@ software, or imported back into gensim as a ``KeyedVectors`` object. .. code-block:: none 71290 100 - the 0.040282175 0.2165622 -0.11749034 -0.07902362 0.051659793 -0.19823891 0.06806079 0.13111936 0.06739034 0.28645086 -0.05745192 -0.26289585 0.22901897 0.16851662 0.06712559 0.074796304 -0.035081368 -0.16047138 0.21728243 0.054436874 0.15153275 0.04205451 0.25825807 0.06590562 0.003011158 0.004102882 -0.100709945 -0.43598634 0.06541784 0.1916927 -0.031570192 0.29551303 -0.09695051 0.16501299 0.19717866 -0.058377385 -0.28637803 0.05174591 -0.16937277 0.059432484 -0.10389606 -0.20887667 -0.05919355 0.04137692 -0.15064004 -0.09648997 -0.22527762 0.033556122 -0.101461716 0.02389651 -0.08515353 0.042458646 -0.17026003 -0.08010368 -0.06399739 -0.078073114 -0.21165106 0.19857563 0.16560182 -0.17774524 -0.27337983 -0.05858462 0.3014273 0.25362 -0.19963813 0.03708622 0.2326357 0.1216157 -0.008749145 -0.036809318 -0.049642608 -0.15324257 0.05383394 0.47451496 -0.4227195 -0.31459892 -0.15150371 -0.14932543 0.063661754 -0.10880057 -0.021235414 0.02103542 -0.16286005 0.09865164 -0.02635211 0.11226083 -0.11042501 0.3655904 -0.12234078 -0.1566903 0.02300252 -0.030776313 0.22856043 0.0644399 0.11757082 -0.08796379 0.23301896 0.018121734 -0.060471278 0.013380485 - of -0.117521346 0.25582337 0.099465266 -0.08187441 0.0003451583 -0.3138303 0.017125094 -0.02423271 0.008411589 0.23745868 -0.030340558 -0.0042213113 0.16474192 0.17288761 0.18377638 0.09036244 -0.20894344 -0.044563673 0.14401074 -0.0023740537 0.069194905 0.16009597 0.3646139 0.04876363 0.04529528 0.04463972 -0.11413204 -0.46372798 0.09147736 0.19938193 -0.0743411 0.3425023 -0.1404897 0.13559413 0.091858536 -0.046490498 -0.07325774 0.036205 -0.13261133 0.060684923 -0.2155932 -0.18659447 0.06216802 0.15724409 -0.0615914 -0.1047893 -0.21563342 0.03399876 -0.14627206 0.13622384 -0.038415514 0.040357746 -0.0950334 -0.1240751 -0.025667595 -0.0762319 -0.19063687 0.42665502 0.26953915 -0.095091894 0.033522405 -0.06997937 0.32336366 0.17219204 -0.17910816 -0.17552538 0.15011984 0.005003567 0.14006145 0.0067128018 -0.0964597 -0.15371965 0.07887949 0.38889432 -0.41947517 -0.14448255 -0.39335525 -0.14048906 0.05884099 -0.0022921925 -0.10194997 0.20200975 -0.20999992 0.12407939 -0.084994085 0.13595223 -0.16718066 0.3076714 -0.1003335 -0.13627231 0.15710355 -0.097152695 0.18041256 -0.013511332 -0.06089443 -0.02832937 0.1863955 0.094825216 0.073157795 0.030848853 + the 0.16007873 -0.061821494 0.16403554 0.20444521 -0.33250368 -0.18388326 -0.11518438 0.26039606 -0.09880219 -0.114337094 -0.24393205 -0.16671345 0.010349793 0.22049113 0.014908477 -0.10886409 -0.050133377 0.014529925 0.0066863606 -0.14707142 0.0400251 0.07787519 -0.18831152 -0.13362508 0.282132 -0.050551824 0.13475767 -0.06569664 0.0031677599 0.07820668 -0.35095257 0.30480665 -0.033180837 -0.048362087 0.04275413 -0.05222876 -0.071952015 -0.035658896 0.07901254 -0.10421657 -0.10299242 0.06549932 0.24401794 -0.15140945 0.029012768 0.04028114 -0.22667517 -0.14450285 -0.23805015 0.08867654 -0.18326522 -0.04525019 0.106588475 -0.00038971985 0.2078292 -0.31376663 0.19781663 0.17066158 0.16820915 -0.047588248 0.20909792 -0.0993302 0.11492583 0.07690898 0.026019907 -0.24461384 -0.15658146 -0.097338416 0.13501963 0.038800433 -0.10874414 0.016372694 0.08403854 0.16431145 0.25076985 -0.10206646 -0.12634891 0.047575567 -0.04372017 0.056058753 -0.06418228 -0.1375621 0.14441249 -0.37270537 -0.12438262 -0.084386 -0.0616519 -0.04610768 -0.1488726 -0.2879129 0.02876804 -0.0783338 0.049880445 -0.2890527 0.052437592 -0.11808442 0.09637225 0.17164731 -0.03777877 0.10314265 + of 0.12728788 -0.07128835 0.22709015 0.21735586 -0.26458326 -0.14139651 -0.21792462 0.08618337 0.08907982 -0.083991244 -0.11595708 -0.20405494 0.11473529 0.106475234 0.16436335 -0.16281348 -0.050799012 0.044015124 0.023081105 -0.08942257 0.12587656 0.17702717 -0.23259656 -0.0012328548 0.25392023 -0.0049020797 0.18065476 -0.15828626 -0.009485071 0.112988144 -0.3753395 0.060977582 0.018466623 0.09084287 -0.12861633 -0.059884362 -0.07544826 0.040726017 0.10942843 -0.21307503 0.00090036006 0.11597715 0.22929604 -0.11609176 0.035484787 0.00071995956 -0.32539764 -0.12604061 -0.005495456 0.04436327 -0.1105619 -0.12655294 0.045705166 -0.14065112 0.21226525 -0.4863211 0.09879361 0.07101748 0.20841932 -0.028169975 0.075062476 -0.26905793 0.057516105 0.031906158 0.1752423 -0.19624741 -0.20997943 -0.10417411 -0.004082244 0.029495642 -0.07799115 -0.061133463 0.028057387 0.06255617 0.25191864 -0.048677184 -0.40772855 -0.025113298 0.019805929 -0.010906071 0.029409314 -0.17279296 0.14616875 -0.44125536 -0.1683791 -0.39358017 -0.04599949 0.10306317 -0.10953343 -0.36125863 -0.103272185 0.09990804 0.026997609 -0.17567022 0.12559506 -0.014309327 0.015485785 0.170501 -0.13221653 0.04849726 Approximate Neighbors - ('cat', 1.0) - ('polydactyl', 0.5950324535369873) - ('kitten', 0.5930328965187073) - ('sighthound', 0.5881928503513336) - ('leopardus', 0.585923820734024) - ('prionailurus', 0.5840010941028595) - ('pug', 0.5792734324932098) - ('cats', 0.5770905315876007) - ('eared', 0.5770178437232971) - ('badger', 0.5747911930084229) - ('albino', 0.5721485614776611) + ('cat', 0.9998273665260058) + ('leopardus', 0.594965249300003) + ('cats', 0.5882971882820129) + ('prionailurus', 0.5790365040302277) + ('proboscis', 0.5778042674064636) + ('eared', 0.5742282271385193) + ('dogs', 0.5695933997631073) + ('skunks', 0.5693343579769135) + ('albino', 0.56873419880867) + ('coyote', 0.5658003985881805) + ('ferret', 0.5657358169555664) Exact Neighbors ('cat', 1.0) - ('polydactyl', 0.6720025539398193) - ('kitten', 0.6687554717063904) - ('meow', 0.6622823476791382) - ('sighthound', 0.6608296632766724) - ('leopardus', 0.6570817828178406) - ('prionailurus', 0.6538898348808289) - ('pug', 0.6459784507751465) - ('proboscis', 0.6438583731651306) - ('cats', 0.6422951221466064) - ('eared', 0.6421721577644348) + ('leopardus', 0.6718936562538147) + ('felis', 0.6702097654342651) + ('cats', 0.6610016822814941) + ('lynxes', 0.6600459218025208) + ('meow', 0.6570931077003479) + ('prionailurus', 0.6455793380737305) + ('proboscis', 0.6435014605522156) + ('eared', 0.6374367475509644) + ('crustacean', 0.6350691914558411) + ('dogs', 0.6295004487037659) + @@ -642,9 +659,9 @@ of our word embeddings. To do so, we did the following steps: .. rst-class:: sphx-glr-timing - **Total running time of the script:** ( 15 minutes 0.569 seconds) + **Total running time of the script:** ( 15 minutes 21.247 seconds) -**Estimated memory usage:** 794 MB +**Estimated memory usage:** 732 MB .. _sphx_glr_download_auto_examples_tutorials_run_annoy.py: @@ -657,13 +674,13 @@ of our word embeddings. To do so, we did the following steps: - .. container:: sphx-glr-download + .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: run_annoy.py ` - .. container:: sphx-glr-download + .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: run_annoy.ipynb ` diff --git a/docs/src/auto_examples/tutorials/sg_execution_times.rst b/docs/src/auto_examples/tutorials/sg_execution_times.rst index b632424cd6..76aa94fdc6 100644 --- a/docs/src/auto_examples/tutorials/sg_execution_times.rst +++ b/docs/src/auto_examples/tutorials/sg_execution_times.rst @@ -5,14 +5,24 @@ Computation times ================= -**15:00.569** total execution time for **auto_examples_tutorials** files: +**15:21.247** total execution time for **auto_examples_tutorials** files: -- **15:00.569**: :ref:`sphx_glr_auto_examples_tutorials_run_annoy.py` (``run_annoy.py``) -- **00:00.000**: :ref:`sphx_glr_auto_examples_tutorials_run_distance_metrics.py` (``run_distance_metrics.py``) -- **00:00.000**: :ref:`sphx_glr_auto_examples_tutorials_run_doc2vec_lee.py` (``run_doc2vec_lee.py``) -- **00:00.000**: :ref:`sphx_glr_auto_examples_tutorials_run_fasttext.py` (``run_fasttext.py``) -- **00:00.000**: :ref:`sphx_glr_auto_examples_tutorials_run_lda.py` (``run_lda.py``) -- **00:00.000**: :ref:`sphx_glr_auto_examples_tutorials_run_pivoted_doc_norm.py` (``run_pivoted_doc_norm.py``) -- **00:00.000**: :ref:`sphx_glr_auto_examples_tutorials_run_summarization.py` (``run_summarization.py``) -- **00:00.000**: :ref:`sphx_glr_auto_examples_tutorials_run_wmd.py` (``run_wmd.py``) -- **00:00.000**: :ref:`sphx_glr_auto_examples_tutorials_run_word2vec.py` (``run_word2vec.py``) ++-----------------------------------------------------------------------------------------------+-----------+----------+ +| :ref:`sphx_glr_auto_examples_tutorials_run_annoy.py` (``run_annoy.py``) | 15:21.247 | 731.9 MB | ++-----------------------------------------------------------------------------------------------+-----------+----------+ +| :ref:`sphx_glr_auto_examples_tutorials_run_distance_metrics.py` (``run_distance_metrics.py``) | 00:00.000 | 0.0 MB | ++-----------------------------------------------------------------------------------------------+-----------+----------+ +| :ref:`sphx_glr_auto_examples_tutorials_run_doc2vec_lee.py` (``run_doc2vec_lee.py``) | 00:00.000 | 0.0 MB | ++-----------------------------------------------------------------------------------------------+-----------+----------+ +| :ref:`sphx_glr_auto_examples_tutorials_run_fasttext.py` (``run_fasttext.py``) | 00:00.000 | 0.0 MB | ++-----------------------------------------------------------------------------------------------+-----------+----------+ +| :ref:`sphx_glr_auto_examples_tutorials_run_lda.py` (``run_lda.py``) | 00:00.000 | 0.0 MB | ++-----------------------------------------------------------------------------------------------+-----------+----------+ +| :ref:`sphx_glr_auto_examples_tutorials_run_pivoted_doc_norm.py` (``run_pivoted_doc_norm.py``) | 00:00.000 | 0.0 MB | ++-----------------------------------------------------------------------------------------------+-----------+----------+ +| :ref:`sphx_glr_auto_examples_tutorials_run_summarization.py` (``run_summarization.py``) | 00:00.000 | 0.0 MB | ++-----------------------------------------------------------------------------------------------+-----------+----------+ +| :ref:`sphx_glr_auto_examples_tutorials_run_wmd.py` (``run_wmd.py``) | 00:00.000 | 0.0 MB | ++-----------------------------------------------------------------------------------------------+-----------+----------+ +| :ref:`sphx_glr_auto_examples_tutorials_run_word2vec.py` (``run_word2vec.py``) | 00:00.000 | 0.0 MB | ++-----------------------------------------------------------------------------------------------+-----------+----------+ diff --git a/docs/src/gallery/tutorials/run_annoy.py b/docs/src/gallery/tutorials/run_annoy.py index a2feca72a7..7535ec3113 100644 --- a/docs/src/gallery/tutorials/run_annoy.py +++ b/docs/src/gallery/tutorials/run_annoy.py @@ -120,7 +120,8 @@ annoy_index = AnnoyIndexer(model, 100) # Dry run to make sure both indexes are fully in RAM -vector = model.wv.vectors_norm[0] +normed_vectors = model.wv.get_normed_vectors() +vector = normed_vectors[0] model.wv.most_similar([vector], topn=5, indexer=annoy_index) model.wv.most_similar([vector], topn=5) @@ -131,7 +132,7 @@ def avg_query_time(annoy_index=None, queries=1000): """Average query time of a most_similar method over 1000 random queries.""" total_time = 0 for _ in range(queries): - rand_vec = model.wv.vectors_norm[np.random.randint(0, len(model.wv))] + rand_vec = normed_vectors[np.random.randint(0, len(model.wv))] start_time = time.process_time() model.wv.most_similar([rand_vec], topn=5, indexer=annoy_index) total_time += time.process_time() - start_time @@ -286,7 +287,7 @@ def f(process_id): # Build dataset of Initialization times and accuracy measures: # -exact_results = [element[0] for element in model.wv.most_similar([model.wv.vectors_norm[0]], topn=100)] +exact_results = [element[0] for element in model.wv.most_similar([normed_vectors[0]], topn=100)] x_values = [] y_values_init = [] @@ -297,7 +298,7 @@ def f(process_id): start_time = time.time() annoy_index = AnnoyIndexer(model, x) y_values_init.append(time.time() - start_time) - approximate_results = model.wv.most_similar([model.wv.vectors_norm[0]], topn=100, indexer=annoy_index) + approximate_results = model.wv.most_similar([normed_vectors[0]], topn=100, indexer=annoy_index) top_words = [result[0] for result in approximate_results] y_values_accuracy.append(len(set(top_words).intersection(exact_results))) diff --git a/gensim/models/doc2vec.py b/gensim/models/doc2vec.py index 8a9cb3a778..f7d43d8e70 100644 --- a/gensim/models/doc2vec.py +++ b/gensim/models/doc2vec.py @@ -755,8 +755,8 @@ def init_sims(self, replace=False): Precompute L2-normalized vectors. Obsoleted. If you need a single unit-normalized vector for some key, call - `:meth:`~gensim.models.keyedvectors.KeyedVectors.get_vector` instead: - ``doc2vec_model.dv.get_vector(key, use_norm=True)``. + :meth:`~gensim.models.keyedvectors.KeyedVectors.get_vector` instead: + ``doc2vec_model.dv.get_vector(key, norm=True)``. To refresh norms after you performed some atypical out-of-band vector tampering, call `:meth:`~gensim.models.keyedvectors.KeyedVectors.fill_norms()` instead. diff --git a/gensim/models/fasttext.py b/gensim/models/fasttext.py index 99a8ecef5b..277909822d 100644 --- a/gensim/models/fasttext.py +++ b/gensim/models/fasttext.py @@ -589,7 +589,6 @@ def build_vocab(self, corpus_iterable=None, corpus_file=None, update=False, prog def _clear_post_train(self): """Clear the model's internal structures after training has finished to free up RAM.""" - self.wv.vectors_norm = None self.wv.adjust_vectors() # ensure composite-word vecs reflect latest training def estimate_memory(self, vocab_size=None, report=None): @@ -758,8 +757,8 @@ def init_sims(self, replace=False): Precompute L2-normalized vectors. Obsoleted. If you need a single unit-normalized vector for some key, call - `:meth:`~gensim.models.keyedvectors.KeyedVectors.get_vector` instead: - ``fasttext_model.wv.get_vector(key, use_norm=True)``. + :meth:`~gensim.models.keyedvectors.KeyedVectors.get_vector` instead: + ``fasttext_model.wv.get_vector(key, norm=True)``. To refresh norms after you performed some atypical out-of-band vector tampering, call `:meth:`~gensim.models.keyedvectors.KeyedVectors.fill_norms()` instead. @@ -1264,14 +1263,14 @@ def save(self, *args, **kwargs): kwargs['ignore'] = kwargs.get('ignore', ignore_attrs) super(FastTextKeyedVectors, self).save(*args, **kwargs) - def get_vector(self, word, use_norm=False): + def get_vector(self, word, norm=False): """Get `word` representations in vector space, as a 1D numpy array. Parameters ---------- word : str Input word - use_norm : bool, optional + norm : bool, optional If True - resulting vector will be L2-normalized (unit euclidean length). Returns @@ -1286,7 +1285,7 @@ def get_vector(self, word, use_norm=False): """ if word in self.key_to_index: - return super(FastTextKeyedVectors, self).get_vector(word, use_norm) + return super(FastTextKeyedVectors, self).get_vector(word, norm=norm) elif self.bucket == 0: raise KeyError('cannot calculate vector for OOV word without ngrams') else: @@ -1307,7 +1306,7 @@ def get_vector(self, word, use_norm=False): for nh in ngram_hashes: word_vec += ngram_weights[nh] word_vec /= len(ngram_hashes) - if use_norm: + if norm: return word_vec / np.linalg.norm(word_vec) else: return word_vec diff --git a/gensim/models/keyedvectors.py b/gensim/models/keyedvectors.py index cfff5a0c86..e78beb8f44 100644 --- a/gensim/models/keyedvectors.py +++ b/gensim/models/keyedvectors.py @@ -139,7 +139,7 @@ >>> vector.shape (100,) >>> - >>> vector = word_vectors.wv.get_vector('office', use_norm=True) + >>> vector = word_vectors.wv.get_vector('office', norm=True) >>> vector.shape (100,) @@ -297,7 +297,7 @@ def resize_vectors(self): self.vectors = np.memmap(self.mapfile_path, shape=(target_count, self.vector_size), mode='w+', dtype=REAL) else: self.vectors = np.zeros((target_count, self.vector_size), dtype=REAL) - self.vectors[0:min(prev_count, target_count), ] = prev_vectors[0:min(prev_count, target_count), ] + self.vectors[0 : min(prev_count, target_count), ] = prev_vectors[0 : min(prev_count, target_count), ] self.allocate_vecattrs() self.norms = None return range(prev_count, target_count) @@ -310,8 +310,10 @@ def randomly_initialize_vectors(self, indexes=None, seed=0): if indexes is None: indexes = range(0, len(self.vectors)) for i in indexes: - self.vectors[i] = pseudorandom_weak_vector(self.vectors.shape[1], - seed_string=(str(self.index_to_key[i]) + str(seed))) + self.vectors[i] = pseudorandom_weak_vector( + self.vectors.shape[1], + seed_string=str(self.index_to_key[i]) + str(seed), + ) self.norms = None def __len__(self): @@ -351,14 +353,14 @@ def get_index(self, key, default=None): else: raise KeyError("Key '%s' not present" % key) - def get_vector(self, key, use_norm=False): + def get_vector(self, key, norm=False): """Get the key's vector, as a 1D numpy array. Parameters ---------- key : str or int Key for vector to return, or int slot - use_norm : bool, optional + norm : bool, optional If True - resulting vector will be L2-normalized (unit euclidean length). Returns @@ -373,7 +375,7 @@ def get_vector(self, key, use_norm=False): """ index = self.get_index(key) - if use_norm: + if norm: self.fill_norms() result = self.vectors[index] / self.norms[index] else: @@ -543,10 +545,6 @@ def fill_norms(self, force=False): if self.norms is None or force: self.norms = np.linalg.norm(self.vectors, axis=1) - @vectors_norm.setter - def vectors_norm(self, _): - pass # no-op; shouldn't be set - @property def index2entity(self): return self.index_to_key @@ -681,7 +679,7 @@ def most_similar(self, positive=None, negative=None, topn=10, clip_start=0, clip if isinstance(key, ndarray): mean.append(weight * key) else: - mean.append(weight * self.get_vector(key, use_norm=True)) + mean.append(weight * self.get_vector(key, norm=True)) if self.has_index_for(key): all_keys.add(self.get_index(key)) if not mean: @@ -838,7 +836,7 @@ def wmdistance(self, document1, document2): # Compute Euclidean distance between unit-normed word vectors. distance_matrix[i, j] = distance_matrix[j, i] = np.sqrt( - np_sum((self.get_vector(t1, use_norm=True) - self.get_vector(t2, use_norm=True))**2)) + np_sum((self.get_vector(t1, norm=True) - self.get_vector(t2, norm=True))**2)) if np_sum(distance_matrix) == 0.0: # `emd` gets stuck if the distance matrix contains only zeros. @@ -912,11 +910,11 @@ def most_similar_cosmul(self, positive=None, negative=None, topn=10): } positive = [ - self.get_vector(word, use_norm=True) if isinstance(word, str) else word + self.get_vector(word, norm=True) if isinstance(word, str) else word for word in positive ] negative = [ - self.get_vector(word, use_norm=True) if isinstance(word, str) else word + self.get_vector(word, norm=True) if isinstance(word, str) else word for word in negative ] @@ -960,7 +958,7 @@ def rank_by_centrality(self, words, use_norm=True): logger.warning("vectors for words %s are not present in the model, ignoring these words", ignored_words) if not used_words: raise ValueError("cannot select a word from an empty list") - vectors = vstack([self.get_vector(word, use_norm=use_norm) for word in used_words]).astype(REAL) + vectors = vstack([self.get_vector(word, norm=use_norm) for word in used_words]).astype(REAL) mean = matutils.unitvec(vectors.mean(axis=0)).astype(REAL) dists = dot(vectors, mean) return sorted(zip(dists, used_words), reverse=True) diff --git a/gensim/models/word2vec.py b/gensim/models/word2vec.py index ca7bb720df..d35a9b4599 100755 --- a/gensim/models/word2vec.py +++ b/gensim/models/word2vec.py @@ -817,8 +817,8 @@ def init_sims(self, replace=False): Precompute L2-normalized vectors. Obsoleted. If you need a single unit-normalized vector for some key, call - `:meth:`~gensim.models.keyedvectors.KeyedVectors.get_vector` instead: - ``word2vec_model.wv.get_vector(key, use_norm=True)``. + :meth:`~gensim.models.keyedvectors.KeyedVectors.get_vector` instead: + ``word2vec_model.wv.get_vector(key, norm=True)``. To refresh norms after you performed some atypical out-of-band vector tampering, call `:meth:`~gensim.models.keyedvectors.KeyedVectors.fill_norms()` instead. diff --git a/gensim/similarities/annoy.py b/gensim/similarities/annoy.py index d9816e2336..52934d06d2 100644 --- a/gensim/similarities/annoy.py +++ b/gensim/similarities/annoy.py @@ -151,7 +151,7 @@ def load(self, fname): def build_from_word2vec(self): """Build an Annoy index using word vectors from a Word2Vec model.""" self.model.init_sims() - return self._build_from_model(self.model.wv.vectors_norm, self.model.wv.index2word, self.model.vector_size) + return self._build_from_model(self.model.wv.get_normed_vectors(), self.model.wv.index2word, self.model.vector_size) def build_from_doc2vec(self): """Build an Annoy index using document vectors from a Doc2Vec model.""" @@ -163,7 +163,7 @@ def build_from_doc2vec(self): def build_from_keyedvectors(self): """Build an Annoy index using word vectors from a KeyedVectors model.""" self.model.init_sims() - return self._build_from_model(self.model.vectors_norm, self.model.index2word, self.model.vector_size) + return self._build_from_model(self.model.get_normed_vectors(), self.model.index2word, self.model.vector_size) def _build_from_model(self, vectors, labels, num_features): try: diff --git a/gensim/similarities/nmslib.py b/gensim/similarities/nmslib.py index a48cafe581..b70a9f4e43 100644 --- a/gensim/similarities/nmslib.py +++ b/gensim/similarities/nmslib.py @@ -187,20 +187,17 @@ def load(cls, fname): def _build_from_word2vec(self): """Build an NMSLIB index using word vectors from a Word2Vec model.""" - - self._build_from_model(self.model.wv.vectors_norm, self.model.wv.index2word) + self._build_from_model(self.model.wv.get_normed_vectors(), self.model.wv.index2word) def _build_from_doc2vec(self): """Build an NMSLIB index using document vectors from a Doc2Vec model.""" - docvecs = self.model.dv labels = docvecs.index_to_key - self._build_from_model(docvecs.vectors_norm, labels) + self._build_from_model(docvecs.get_normed_vectors(), labels) def _build_from_keyedvectors(self): """Build an NMSLIB index using word vectors from a KeyedVectors model.""" - - self._build_from_model(self.model.vectors_norm, self.model.index2word) + self._build_from_model(self.model.get_normed_vectors(), self.model.index2word) def _build_from_model(self, vectors, labels): index = nmslib.init(method='hnsw', space='cosinesimil') diff --git a/gensim/test/test_fasttext.py b/gensim/test/test_fasttext.py index 9ace152858..3fea696e19 100644 --- a/gensim/test/test_fasttext.py +++ b/gensim/test/test_fasttext.py @@ -84,7 +84,7 @@ def test_training(self): self.model_sanity(model) # test querying for "most similar" by vector - graph_vector = model.wv.get_vector('graph', use_norm=True) + graph_vector = model.wv.get_vector('graph', norm=True) sims2 = model.wv.most_similar(positive=[graph_vector], topn=11) sims2 = [(w, sim) for w, sim in sims2 if w != 'graph'] # ignore 'graph' itself self.assertEqual(sims, sims2) @@ -129,7 +129,7 @@ def test_training_fromfile(self): self.model_sanity(model) # test querying for "most similar" by vector - graph_vector = model.wv.get_vector('graph', use_norm=True) + graph_vector = model.wv.get_vector('graph', norm=True) sims2 = model.wv.most_similar(positive=[graph_vector], topn=11) sims2 = [(w, sim) for w, sim in sims2 if w != 'graph'] # ignore 'graph' itself self.assertEqual(sims, sims2) diff --git a/gensim/test/test_keras_integration.py b/gensim/test/test_keras_integration.py index 0319bddaf1..ef5ec3c823 100644 --- a/gensim/test/test_keras_integration.py +++ b/gensim/test/test_keras_integration.py @@ -39,7 +39,7 @@ def testWord2VecTraining(self): # self.assertTrue(sims[0][0] == 'trees', sims) # most similar # test querying for "most similar" by vector - graph_vector = model.wv.vectors_norm[model.wv.get_index('graph')] + graph_vector = model.wv.get_vector('graph', norm=True) sims2 = model.wv.most_similar(positive=[graph_vector], topn=11) sims2 = [(w, sim) for w, sim in sims2 if w != 'graph'] # ignore 'graph' itself self.assertEqual(sims, sims2) diff --git a/gensim/test/test_similarities.py b/gensim/test/test_similarities.py index 4840d30031..fbd8f53ade 100644 --- a/gensim/test/test_similarities.py +++ b/gensim/test/test_similarities.py @@ -590,7 +590,7 @@ def testLoadMissingRaisesError(self): self.assertRaises(IOError, test_index.load, fname='test-index') def assertVectorIsSimilarToItself(self, wv, index): - vector = wv.vectors_norm[0] + vector = wv.get_normed_vectors()[0] label = wv.index2word[0] approx_neighbors = index.most_similar(vector, 1) word, similarity = approx_neighbors[0] @@ -599,7 +599,7 @@ def assertVectorIsSimilarToItself(self, wv, index): self.assertAlmostEqual(similarity, 1.0, places=2) def assertApproxNeighborsMatchExact(self, model, wv, index): - vector = wv.vectors_norm[0] + vector = wv.get_normed_vectors()[0] approx_neighbors = model.most_similar([vector], topn=5, indexer=index) exact_neighbors = model.most_similar(positive=[vector], topn=5) @@ -609,7 +609,7 @@ def assertApproxNeighborsMatchExact(self, model, wv, index): self.assertEqual(approx_words, exact_words) def assertAllSimilaritiesDisableIndexer(self, model, wv, index): - vector = wv.vectors_norm[0] + vector = wv.get_normed_vectors()[0] approx_similarities = model.most_similar([vector], topn=None, indexer=index) exact_similarities = model.most_similar(positive=[vector], topn=None) @@ -649,7 +649,7 @@ def setUp(self): self.model = doc2vec.Doc2Vec(SENTENCES, min_count=1) self.index = AnnoyIndexer(self.model, 300) - self.vector = self.model.dv.vectors_norm[0] + self.vector = self.model.dv.get_normed_vectors()[0] def testDocumentIsSimilarToItself(self): approx_neighbors = self.index.most_similar(self.vector, 1) @@ -747,7 +747,7 @@ def test_load_missing_raises_error(self): self.assertRaises(IOError, NmslibIndexer.load, fname='test-index') def assertVectorIsSimilarToItself(self, wv, index): - vector = wv.vectors_norm[0] + vector = wv.get_normed_vectors()[0] label = wv.index2word[0] approx_neighbors = index.most_similar(vector, 1) word, similarity = approx_neighbors[0] @@ -756,7 +756,7 @@ def assertVectorIsSimilarToItself(self, wv, index): self.assertAlmostEqual(similarity, 1.0, places=2) def assertApproxNeighborsMatchExact(self, model, wv, index): - vector = wv.vectors_norm[0] + vector = wv.get_normed_vectors()[0] approx_neighbors = model.most_similar([vector], topn=5, indexer=index) exact_neighbors = model.most_similar([vector], topn=5) @@ -797,7 +797,7 @@ def setUp(self): self.model = doc2vec.Doc2Vec(SENTENCES, min_count=1) self.index = NmslibIndexer(self.model) - self.vector = self.model.dv.vectors_norm[0] + self.vector = self.model.dv.get_normed_vectors()[0] def test_document_is_similar_to_itself(self): approx_neighbors = self.index.most_similar(self.vector, 1) diff --git a/gensim/test/test_word2vec.py b/gensim/test/test_word2vec.py index 1be1ea9d21..20bf3555eb 100644 --- a/gensim/test/test_word2vec.py +++ b/gensim/test/test_word2vec.py @@ -355,7 +355,7 @@ def testPersistenceWord2VecFormat(self): norm_only_model = keyedvectors.KeyedVectors.load_word2vec_format(tmpf, binary=True) norm_only_model.unit_normalize_all() self.assertFalse(np.allclose(model.wv['human'], norm_only_model['human'])) - self.assertTrue(np.allclose(model.wv.get_vector('human', use_norm=True), norm_only_model['human'])) + self.assertTrue(np.allclose(model.wv.get_vector('human', norm=True), norm_only_model['human'])) limited_model_kv = keyedvectors.KeyedVectors.load_word2vec_format(tmpf, binary=True, limit=3) self.assertEqual(len(limited_model_kv.vectors), 3) half_precision_model_kv = keyedvectors.KeyedVectors.load_word2vec_format( @@ -401,7 +401,7 @@ def testPersistenceWord2VecFormatNonBinary(self): norm_only_model.unit_normalize_all() self.assertFalse(np.allclose(model.wv['human'], norm_only_model['human'], atol=1e-6)) self.assertTrue(np.allclose( - model.wv.get_vector('human', use_norm=True), norm_only_model['human'], atol=1e-4 + model.wv.get_vector('human', norm=True), norm_only_model['human'], atol=1e-4 )) def testPersistenceWord2VecFormatWithVocab(self): @@ -489,7 +489,7 @@ def testTraining(self): # self.assertTrue(sims[0][0] == 'trees', sims) # most similar # test querying for "most similar" by vector - graph_vector = model.wv.vectors_norm[model.wv.get_index('graph')] + graph_vector = model.wv.get_vector('graph', norm=True) sims2 = model.wv.most_similar(positive=[graph_vector], topn=11) sims2 = [(w, sim) for w, sim in sims2 if w != 'graph'] # ignore 'graph' itself self.assertEqual(sims, sims2) @@ -516,7 +516,7 @@ def testTrainingFromFile(self): # self.assertTrue(sims[0][0] == 'trees', sims) # most similar # test querying for "most similar" by vector - graph_vector = model.wv.vectors_norm[model.wv.get_index('graph')] + graph_vector = model.wv.get_vector('graph', norm=True) sims2 = model.wv.most_similar(positive=[graph_vector], topn=11) sims2 = [(w, sim) for w, sim in sims2 if w != 'graph'] # ignore 'graph' itself self.assertEqual(sims, sims2) @@ -670,7 +670,7 @@ def test_cosmul(self): # self.assertTrue(sims[0][0] == 'trees', sims) # most similar # test querying for "most similar" by vector - graph_vector = model.wv.vectors_norm[model.wv.get_index('graph')] + graph_vector = model.wv.get_vector('graph', norm=True) sims2 = model.wv.most_similar_cosmul(positive=[graph_vector], topn=11) sims2 = [(w, sim) for w, sim in sims2 if w != 'graph'] # ignore 'graph' itself self.assertEqual(sims, sims2) @@ -689,7 +689,7 @@ def testTrainingCbow(self): # self.assertTrue(sims[0][0] == 'trees', sims) # most similar # test querying for "most similar" by vector - graph_vector = model.wv.vectors_norm[model.wv.get_index('graph')] + graph_vector = model.wv.get_vector('graph', norm=True) sims2 = model.wv.most_similar(positive=[graph_vector], topn=11) sims2 = [(w, sim) for w, sim in sims2 if w != 'graph'] # ignore 'graph' itself self.assertEqual(sims, sims2) @@ -712,7 +712,7 @@ def testTrainingSgNegative(self): # self.assertTrue(sims[0][0] == 'trees', sims) # most similar # test querying for "most similar" by vector - graph_vector = model.wv.vectors_norm[model.wv.get_index('graph')] + graph_vector = model.wv.get_vectors('graph', norm=True) sims2 = model.wv.most_similar(positive=[graph_vector], topn=11) sims2 = [(w, sim) for w, sim in sims2 if w != 'graph'] # ignore 'graph' itself self.assertEqual(sims, sims2) @@ -735,7 +735,7 @@ def testTrainingCbowNegative(self): # self.assertTrue(sims[0][0] == 'trees', sims) # most similar # test querying for "most similar" by vector - graph_vector = model.wv.vectors_norm[model.wv.get_index('graph')] + graph_vector = model.wv.get_vector('graph', norm=True) sims2 = model.wv.most_similar(positive=[graph_vector], topn=11) sims2 = [(w, sim) for w, sim in sims2 if w != 'graph'] # ignore 'graph' itself self.assertEqual(sims, sims2) From d40f685e37ef01a437eceaf352197739f4e6c9b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20=C5=98eh=C5=AF=C5=99ek?= Date: Thu, 30 Jul 2020 14:36:10 +0200 Subject: [PATCH 18/32] put back no-op property setter of deprecated vectors_norm --- gensim/models/keyedvectors.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gensim/models/keyedvectors.py b/gensim/models/keyedvectors.py index e78beb8f44..84a7a923c4 100644 --- a/gensim/models/keyedvectors.py +++ b/gensim/models/keyedvectors.py @@ -527,6 +527,10 @@ def vectors_norm(self): "See https://github.com/RaRe-Technologies/gensim/wiki/Migrating-from-Gensim-3.x-to-4#init_sims" ) + @vectors_norm.setter + def vectors_norm(self, _): + pass # no-op; shouldn't be set + def get_normed_vectors(self): # TODO: what's the way for users to get from a matrix index (integer) to the # corresponding key (string)? From 872c8edd12287f1dbe7ce213e22c7c0fd7b60255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20=C5=98eh=C5=AF=C5=99ek?= Date: Thu, 30 Jul 2020 20:58:28 +0200 Subject: [PATCH 19/32] fix typo --- gensim/models/fasttext.py | 6 +++--- gensim/models/keyedvectors.py | 6 +++--- gensim/test/test_word2vec.py | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/gensim/models/fasttext.py b/gensim/models/fasttext.py index 277909822d..f21854f3d3 100644 --- a/gensim/models/fasttext.py +++ b/gensim/models/fasttext.py @@ -1269,9 +1269,9 @@ def get_vector(self, word, norm=False): Parameters ---------- word : str - Input word + Input word. norm : bool, optional - If True - resulting vector will be L2-normalized (unit euclidean length). + If True, resulting vector will be L2-normalized (unit Euclidean length). Returns ------- @@ -1281,7 +1281,7 @@ def get_vector(self, word, norm=False): Raises ------ KeyError - If word and all ngrams not in vocabulary. + If word and all its ngrams not in vocabulary. """ if word in self.key_to_index: diff --git a/gensim/models/keyedvectors.py b/gensim/models/keyedvectors.py index 84a7a923c4..cc6cb1197f 100644 --- a/gensim/models/keyedvectors.py +++ b/gensim/models/keyedvectors.py @@ -358,10 +358,10 @@ def get_vector(self, key, norm=False): Parameters ---------- - key : str or int - Key for vector to return, or int slot + key : str + Key for vector to return. norm : bool, optional - If True - resulting vector will be L2-normalized (unit euclidean length). + If True, the resulting vector will be L2-normalized (unit Euclidean length). Returns ------- diff --git a/gensim/test/test_word2vec.py b/gensim/test/test_word2vec.py index 20bf3555eb..f7a73ee375 100644 --- a/gensim/test/test_word2vec.py +++ b/gensim/test/test_word2vec.py @@ -712,7 +712,7 @@ def testTrainingSgNegative(self): # self.assertTrue(sims[0][0] == 'trees', sims) # most similar # test querying for "most similar" by vector - graph_vector = model.wv.get_vectors('graph', norm=True) + graph_vector = model.wv.get_vector('graph', norm=True) sims2 = model.wv.most_similar(positive=[graph_vector], topn=11) sims2 = [(w, sim) for w, sim in sims2 if w != 'graph'] # ignore 'graph' itself self.assertEqual(sims, sims2) From 4c1b3f712b173afbad9d7532340cce07741b9c52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20=C5=98eh=C5=AF=C5=99ek?= Date: Thu, 30 Jul 2020 22:08:44 +0200 Subject: [PATCH 20/32] fix flake8 --- docs/src/auto_examples/tutorials/run_annoy.py | 1 - docs/src/gallery/tutorials/run_annoy.py | 1 - gensim/models/keyedvectors.py | 2 +- gensim/similarities/annoy.py | 11 ++++++----- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/docs/src/auto_examples/tutorials/run_annoy.py b/docs/src/auto_examples/tutorials/run_annoy.py index 7535ec3113..e53f524dad 100644 --- a/docs/src/auto_examples/tutorials/run_annoy.py +++ b/docs/src/auto_examples/tutorials/run_annoy.py @@ -116,7 +116,6 @@ # ------------------------------------- # Set up the model and vector that we are using in the comparison -model.init_sims() annoy_index = AnnoyIndexer(model, 100) # Dry run to make sure both indexes are fully in RAM diff --git a/docs/src/gallery/tutorials/run_annoy.py b/docs/src/gallery/tutorials/run_annoy.py index 7535ec3113..e53f524dad 100644 --- a/docs/src/gallery/tutorials/run_annoy.py +++ b/docs/src/gallery/tutorials/run_annoy.py @@ -116,7 +116,6 @@ # ------------------------------------- # Set up the model and vector that we are using in the comparison -model.init_sims() annoy_index = AnnoyIndexer(model, 100) # Dry run to make sure both indexes are fully in RAM diff --git a/gensim/models/keyedvectors.py b/gensim/models/keyedvectors.py index cc6cb1197f..520536bd65 100644 --- a/gensim/models/keyedvectors.py +++ b/gensim/models/keyedvectors.py @@ -297,7 +297,7 @@ def resize_vectors(self): self.vectors = np.memmap(self.mapfile_path, shape=(target_count, self.vector_size), mode='w+', dtype=REAL) else: self.vectors = np.zeros((target_count, self.vector_size), dtype=REAL) - self.vectors[0 : min(prev_count, target_count), ] = prev_vectors[0 : min(prev_count, target_count), ] + self.vectors[0: min(prev_count, target_count), ] = prev_vectors[0: min(prev_count, target_count), ] self.allocate_vecattrs() self.norms = None return range(prev_count, target_count) diff --git a/gensim/similarities/annoy.py b/gensim/similarities/annoy.py index 52934d06d2..9f8b8fdbc0 100644 --- a/gensim/similarities/annoy.py +++ b/gensim/similarities/annoy.py @@ -150,20 +150,21 @@ def load(self, fname): def build_from_word2vec(self): """Build an Annoy index using word vectors from a Word2Vec model.""" - self.model.init_sims() - return self._build_from_model(self.model.wv.get_normed_vectors(), self.model.wv.index2word, self.model.vector_size) + return self._build_from_model( + self.model.wv.get_normed_vectors(), self.model.wv.index2word, self.model.vector_size, + ) def build_from_doc2vec(self): """Build an Annoy index using document vectors from a Doc2Vec model.""" docvecs = self.model.docvecs - docvecs.init_sims() labels = [docvecs.index_to_doctag(i) for i in range(docvecs.count)] return self._build_from_model(docvecs.vectors_docs_norm, labels, self.model.vector_size) def build_from_keyedvectors(self): """Build an Annoy index using word vectors from a KeyedVectors model.""" - self.model.init_sims() - return self._build_from_model(self.model.get_normed_vectors(), self.model.index2word, self.model.vector_size) + return self._build_from_model( + self.model.get_normed_vectors(), self.model.index2word, self.model.vector_size, + ) def _build_from_model(self, vectors, labels, num_features): try: From b39eec2b651b361894426780641442f7a228a15a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20=C5=98eh=C5=AF=C5=99ek?= Date: Thu, 30 Jul 2020 22:59:22 +0200 Subject: [PATCH 21/32] disable Keras tests - failing with weird errors on py3.7+3.8, see https://travis-ci.org/github/RaRe-Technologies/gensim/jobs/713448950#L862 --- gensim/test/test_keras_integration.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gensim/test/test_keras_integration.py b/gensim/test/test_keras_integration.py index ef5ec3c823..6dbe3fa4e6 100644 --- a/gensim/test/test_keras_integration.py +++ b/gensim/test/test_keras_integration.py @@ -1,6 +1,6 @@ import unittest + import numpy as np -from gensim.models import word2vec try: from sklearn.datasets import fetch_20newsgroups @@ -21,8 +21,10 @@ raise unittest.SkipTest("Test requires Keras to be installed, which is not available") from gensim.test.utils import common_texts +from gensim.models import word2vec +@unittest.skip("FIXME strange Keras errors in py3.7+") class TestKerasWord2VecWrapper(unittest.TestCase): def setUp(self): self.model_cos_sim = word2vec.Word2Vec(common_texts, vector_size=100, min_count=1, hs=1) From f2fd0451ae449bec1de66d8e36e6353d5337b37a Mon Sep 17 00:00:00 2001 From: Gordon Mohr Date: Wed, 22 Jul 2020 09:44:40 -0700 Subject: [PATCH 22/32] test showing FT failure as W2V --- gensim/test/test_fasttext.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/gensim/test/test_fasttext.py b/gensim/test/test_fasttext.py index 3fea696e19..6006c162b5 100644 --- a/gensim/test/test_fasttext.py +++ b/gensim/test/test_fasttext.py @@ -19,6 +19,7 @@ from gensim.models.fasttext import FastText as FT_gensim, FastTextKeyedVectors, _unpack from gensim.models.keyedvectors import KeyedVectors from gensim.test.utils import datapath, get_tmpfile, temporary_file, common_texts as sentences +from gensim.test.test_word2vec import TestWord2VecModel import gensim.models._fasttext_bin from gensim.models.fasttext_inner import compute_ngrams, compute_ngrams_bytes, ft_hash_bytes @@ -1367,6 +1368,7 @@ def _read_fb(fin): class ZeroBucketTest(unittest.TestCase): + """Tests FastText with no buckets/no-ngrams (essentially FastText-as-Word2Vec""" def test_in_vocab(self): model = train_gensim(bucket=0) self.assertIsNotNone(model.wv['anarchist']) @@ -1375,6 +1377,15 @@ def test_out_of_vocab(self): model = train_gensim(bucket=0) self.assertRaises(KeyError, model.wv.word_vec, 'streamtrain') + def test_cbow_neg(self): + """See gensim.test.test_word2vec.TestWord2VecModel.test_cbow_neg""" + model = FT_gensim( + sg=0, cbow_mean=1, alpha=0.05, window=5, hs=0, negative=15, + min_count=5, epochs=10, workers=2, sample=0, + max_n=0 # force no char-ngram buckets + ) + TestWord2VecModel.model_sanity(self, model) + class UnicodeVocabTest(unittest.TestCase): def test_ascii(self): From 7ab15011d218b05652307fad1a21c42490a80236 Mon Sep 17 00:00:00 2001 From: Gordon Mohr Date: Tue, 21 Jul 2020 21:16:50 -0700 Subject: [PATCH 23/32] set .vectors even when ngrams off --- gensim/models/fasttext.py | 1 + 1 file changed, 1 insertion(+) diff --git a/gensim/models/fasttext.py b/gensim/models/fasttext.py index f21854f3d3..42a69b8bc5 100644 --- a/gensim/models/fasttext.py +++ b/gensim/models/fasttext.py @@ -1406,6 +1406,7 @@ def adjust_vectors(self): """ if self.bucket == 0: + self.vectors = self.vectors_vocab # no ngrams influence return self.vectors = self.vectors_vocab[:].copy() From ce1616881def6b8358ae1861904216e6f1467061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20=C5=98eh=C5=AF=C5=99ek?= Date: Sun, 26 Jul 2020 18:09:53 +0200 Subject: [PATCH 24/32] Update gensim/test/test_fasttext.py --- gensim/test/test_fasttext.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gensim/test/test_fasttext.py b/gensim/test/test_fasttext.py index 6006c162b5..20b6c82584 100644 --- a/gensim/test/test_fasttext.py +++ b/gensim/test/test_fasttext.py @@ -1368,7 +1368,7 @@ def _read_fb(fin): class ZeroBucketTest(unittest.TestCase): - """Tests FastText with no buckets/no-ngrams (essentially FastText-as-Word2Vec""" + """Test FastText with no buckets / no-ngrams: essentially FastText-as-Word2Vec.""" def test_in_vocab(self): model = train_gensim(bucket=0) self.assertIsNotNone(model.wv['anarchist']) From 779fe46da3ceeceea6c0c4bea48749584bae97f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20=C5=98eh=C5=AF=C5=99ek?= Date: Sun, 26 Jul 2020 18:10:00 +0200 Subject: [PATCH 25/32] Update gensim/test/test_fasttext.py --- gensim/test/test_fasttext.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gensim/test/test_fasttext.py b/gensim/test/test_fasttext.py index 20b6c82584..90ffbfb2b9 100644 --- a/gensim/test/test_fasttext.py +++ b/gensim/test/test_fasttext.py @@ -1378,7 +1378,7 @@ def test_out_of_vocab(self): self.assertRaises(KeyError, model.wv.word_vec, 'streamtrain') def test_cbow_neg(self): - """See gensim.test.test_word2vec.TestWord2VecModel.test_cbow_neg""" + """See `gensim.test.test_word2vec.TestWord2VecModel.test_cbow_neg`.""" model = FT_gensim( sg=0, cbow_mean=1, alpha=0.05, window=5, hs=0, negative=15, min_count=5, epochs=10, workers=2, sample=0, From 9289c3b913cb452699b24420d80272338cfea999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20=C5=98eh=C5=AF=C5=99ek?= Date: Mon, 3 Aug 2020 09:34:45 +0200 Subject: [PATCH 26/32] refresh docs for run_annoy tutorial --- .../images/sphx_glr_run_annoy_001.png | Bin 48021 -> 45040 bytes .../images/thumb/sphx_glr_run_annoy_thumb.png | Bin 15673 -> 14743 bytes .../auto_examples/tutorials/run_annoy.ipynb | 2 +- .../auto_examples/tutorials/run_annoy.py.md5 | 2 +- .../src/auto_examples/tutorials/run_annoy.rst | 125 +++++++++--------- .../tutorials/sg_execution_times.rst | 4 +- 6 files changed, 66 insertions(+), 67 deletions(-) diff --git a/docs/src/auto_examples/tutorials/images/sphx_glr_run_annoy_001.png b/docs/src/auto_examples/tutorials/images/sphx_glr_run_annoy_001.png index 1c3020babc0b8d1c9e89a333b5fc2d6cb5854f56..09c6dede79ffbf3124f20ed3052a6788ea442276 100644 GIT binary patch literal 45040 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
He<oWWODfrO~$J|s__BP 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 z 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 CLek3s diff --git a/docs/src/auto_examples/tutorials/images/thumb/sphx_glr_run_annoy_thumb.png b/docs/src/auto_examples/tutorials/images/thumb/sphx_glr_run_annoy_thumb.png index 4395e8871ae0b28d01dacab40bcf46ab927a1e32..30df00db573789aa297b6d71eaf67359cfab05f3 100644 GIT binary patch literal 14743 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 f{&pEm8s^-6h>!cb)fl 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 Date: Fri, 7 Aug 2020 15:01:58 +0200 Subject: [PATCH 27/32] Reduce memory use of the term similarity matrix constructor, deprecate the positive_definite parameter, and extend normalization capabilities of the inner_product method (#2783) * Deprecate SparseTermSimilarityMatrix's positive_definite parameter * Reference paper on efficient implementation of soft cosine similarity * Add example with Annoy indexer to SparseTermSimilarityMatrix * Add example of obtaining word embeddings from SparseTermSimilarityMatrix * Reduce space complexity of SparseTermSimilarityMatrix construction Build matrix using arrays and bitfields rather than DOK sparse format This work is based on the following blog post by @maciejkula: https://maciejkula.github.io/2015/02/22/incremental-construction-of-sparse-matrices/ * Fix a typo in the soft cosine similarity Jupyter notebook * Add human-readable string representation for TermSimilarityIndex * Avoid sparse term similarity matrix computation when nonzero_limit <= 0 * Extend normalization in the inner_product method Support the `maintain` vector normalization scheme. Support separate vector normalization schemes for queries and documents. * Remove a note in the docstring of SparseTermSimilarityMatrix * Rerun continuous integration tests * Use ==/!= to compare constant literals * Add human-readable string representation for TermSimilarityIndex (cont.) * Prod flake8 with a coding style violation in a docstring * Collapse two lambdas into one internal function * Revert "Prod flake8 with a coding style violation in a docstring" This reverts commit 6557b849732b314570ea9d5132f1731d964e2fe6. * Avoid str.format() * Slice SparseTermSimilarityMatrix.inner_product tests by input types * Remove similarity_type_code local variable * Remove starting underscore from local function name * Save indentation level and define populate_buffers function * Extract SparseTermSimilarityMatrix constructor body to _create_source * Extract NON_NEGATIVE_NORM_ASSERTION_MESSAGE to a module-level constant * Extract cell assignment logic to cell_full local function * Split variable swapping into three separate statements * Extract normalization from the body of SparseTermSimilarityMatrix.inner_product * Wrap overlong line * Add test_inner_product_zerovector_zerovector and test_inner_product_zerovector_vector tests * Further split test_inner_product into 63 test cases * Raise ValueError when dictionary is empty --- docs/notebooks/soft_cosine_tutorial.ipynb | 4 +- gensim/similarities/docsim.py | 2 +- gensim/similarities/termsim.py | 527 +++++++++++++------- gensim/test/test_similarities.py | 562 ++++++++++++++++++++-- 4 files changed, 862 insertions(+), 233 deletions(-) diff --git a/docs/notebooks/soft_cosine_tutorial.ipynb b/docs/notebooks/soft_cosine_tutorial.ipynb index 358c80ed02..aadbecf6a5 100644 --- a/docs/notebooks/soft_cosine_tutorial.ipynb +++ b/docs/notebooks/soft_cosine_tutorial.ipynb @@ -225,7 +225,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Number of documents: 3\n", + "Number of documents: 2274338\n", "CPU times: user 2min 1s, sys: 1.9 s, total: 2min 3s\n", "Wall time: 2min 56s\n" ] @@ -259,7 +259,7 @@ " [preprocess(relcomment[\"RelCText\"]) for relcomment in thread[\"RelComments\"]])\n", " for thread in api.load(\"semeval-2016-2017-task3-subtaskA-unannotated\")]))\n", "\n", - "print(\"Number of documents: %d\" % len(documents))" + "print(\"Number of documents: %d\" % len(corpus))" ] }, { diff --git a/gensim/similarities/docsim.py b/gensim/similarities/docsim.py index daba706eb1..b014952499 100755 --- a/gensim/similarities/docsim.py +++ b/gensim/similarities/docsim.py @@ -978,7 +978,7 @@ def get_similarities(self, query): is_corpus, query = utils.is_corpus(query) if not is_corpus and isinstance(query, numpy.ndarray): query = [self.corpus[i] for i in query] # convert document indexes to actual documents - result = self.similarity_matrix.inner_product(query, self.corpus, normalized=True) + result = self.similarity_matrix.inner_product(query, self.corpus, normalized=(True, True)) if scipy.sparse.issparse(result): return numpy.asarray(result.todense()) diff --git a/gensim/similarities/termsim.py b/gensim/similarities/termsim.py index c0e61e1490..3dcd4c6ae6 100644 --- a/gensim/similarities/termsim.py +++ b/gensim/similarities/termsim.py @@ -8,11 +8,14 @@ This module provides classes that deal with term similarities. """ +from array import array from itertools import chain import logging from math import sqrt +import warnings import numpy as np +from six.moves import range from scipy import sparse from gensim.matutils import corpus2csc @@ -20,6 +23,10 @@ logger = logging.getLogger(__name__) +NON_NEGATIVE_NORM_ASSERTION_MESSAGE = u"sparse documents must not contain any explicit " \ + u"zero entries and the similarity matrix S must satisfy x^T * S * x >= 0 for any " \ + u"nonzero bag-of-words vector x." + class TermSimilarityIndex(SaveLoad): """ @@ -52,6 +59,10 @@ def most_similar(self, term, topn=10): """ raise NotImplementedError + def __str__(self): + members = ', '.join('%s=%s' % pair for pair in vars(self).items()) + return '%s(%s)' % (self.__class__.__name__, members) + class UniformTermSimilarityIndex(TermSimilarityIndex): """ @@ -86,33 +97,6 @@ def most_similar(self, t1, topn=10): yield (t2, self.term_similarity) -def _shortest_uint_dtype(max_value): - """Get the shortest unsingned integer data-type required for representing values up to a given - maximum value. - - Returns the shortest unsingned integer data-type required for representing values up to a given - maximum value. - - Parameters - ---------- - max_value : int - The maximum value we wish to represent. - - Returns - ------- - data-type - The shortest unsigned integer data-type required for representing values up to a given - maximum value. - """ - if max_value < 2**8: - return np.uint8 - elif max_value < 2**16: - return np.uint16 - elif max_value < 2**32: - return np.uint32 - return np.uint64 - - class WordEmbeddingSimilarityIndex(TermSimilarityIndex): """ Use objects of this class to: @@ -156,32 +140,288 @@ def most_similar(self, t1, topn=10): yield (t2, similarity**self.exponent) +def _shortest_uint_dtype(max_value): + """Get the shortest unsingned integer data-type required for representing values up to a given + maximum value. + + Returns the shortest unsingned integer data-type required for representing values up to a given + maximum value. + + Parameters + ---------- + max_value : int + The maximum value we wish to represent. + + Returns + ------- + data-type + The shortest unsigned integer data-type required for representing values up to a given + maximum value. + """ + if max_value < 2**8: + return np.uint8 + elif max_value < 2**16: + return np.uint16 + elif max_value < 2**32: + return np.uint32 + return np.uint64 + + +def _create_source(index, dictionary, tfidf, symmetric, dominant, nonzero_limit, dtype): + """Build a sparse term similarity matrix using a term similarity index. + + Returns + ------- + matrix : :class:`scipy.sparse.coo_matrix` + The sparse term similarity matrix. + + """ + assert isinstance(index, TermSimilarityIndex) + assert dictionary is not None + matrix_order = len(dictionary) + + if matrix_order == 0: + raise ValueError('Dictionary provided to SparseTermSimilarityMatrix must not be empty') + + logger.info("constructing a sparse term similarity matrix using %s", index) + + if nonzero_limit is None: + nonzero_limit = matrix_order + + def tfidf_sort_key(term_index): + if isinstance(term_index, tuple): + term_index, *_ = term_index + term_idf = tfidf.idfs[term_index] + return (-term_idf, term_index) + + if tfidf is None: + logger.info("iterating over columns in dictionary order") + columns = sorted(dictionary.keys()) + else: + assert max(tfidf.idfs) == matrix_order - 1 + logger.info("iterating over columns in tf-idf order") + columns = sorted(tfidf.idfs.keys(), key=tfidf_sort_key) + + nonzero_counter_dtype = _shortest_uint_dtype(nonzero_limit) + + column_nonzero = np.array([0] * matrix_order, dtype=nonzero_counter_dtype) + if dominant: + column_sum = np.zeros(matrix_order, dtype=dtype) + if symmetric: + assigned_cells = set() + row_buffer = array('Q') + column_buffer = array('Q') + if dtype is np.float16 or dtype is np.float32: + data_buffer = array('f') + elif dtype is np.float64: + data_buffer = array('d') + else: + raise ValueError('Dtype %s is unsupported, use numpy.float16, float32, or float64.' % dtype) + + def cell_full(t1_index, t2_index, similarity): + if dominant and column_sum[t1_index] + abs(similarity) >= 1.0: + return True # after adding the similarity, the matrix would cease to be strongly diagonally dominant + assert column_nonzero[t1_index] <= nonzero_limit + if column_nonzero[t1_index] == nonzero_limit: + return True # after adding the similarity, the column would contain more than nonzero_limit elements + if symmetric and (t1_index, t2_index) in assigned_cells: + return True # a similarity has already been assigned to this cell + return False + + def populate_buffers(t1_index, t2_index, similarity): + column_buffer.append(t1_index) + row_buffer.append(t2_index) + data_buffer.append(similarity) + column_nonzero[t1_index] += 1 + if symmetric: + assigned_cells.add((t1_index, t2_index)) + if dominant: + column_sum[t1_index] += abs(similarity) + + try: + from tqdm import tqdm as progress_bar + except ImportError: + def progress_bar(iterable): + return iterable + + for column_number, t1_index in enumerate(progress_bar(columns)): + column_buffer.append(column_number) + row_buffer.append(column_number) + data_buffer.append(1.0) + + if nonzero_limit <= 0: + continue + + t1 = dictionary[t1_index] + num_nonzero = column_nonzero[t1_index] + num_rows = nonzero_limit - num_nonzero + most_similar = [ + (dictionary.token2id[term], similarity) + for term, similarity in index.most_similar(t1, topn=num_rows) + if term in dictionary.token2id + ] if num_rows > 0 else [] + + if tfidf is None: + rows = sorted(most_similar) + else: + rows = sorted(most_similar, key=tfidf_sort_key) + + for t2_index, similarity in rows: + if cell_full(t1_index, t2_index, similarity): + continue + if not symmetric: + populate_buffers(t1_index, t2_index, similarity) + elif not cell_full(t2_index, t1_index, similarity): + populate_buffers(t1_index, t2_index, similarity) + populate_buffers(t2_index, t1_index, similarity) + + data_buffer = np.frombuffer(data_buffer, dtype=dtype) + row_buffer = np.frombuffer(row_buffer, dtype=np.uint64) + column_buffer = np.frombuffer(column_buffer, dtype=np.uint64) + matrix = sparse.coo_matrix((data_buffer, (row_buffer, column_buffer)), shape=(matrix_order, matrix_order)) + + logger.info( + "constructed a sparse term similarity matrix with %0.06f%% density", + 100.0 * matrix.getnnz() / matrix_order**2, + ) + + return matrix + + +def _normalize_dense_vector(vector, matrix, normalization): + """Normalize a dense vector after a change of basis. + + Parameters + ---------- + vector : 1xN ndarray + A dense vector. + matrix : NxN ndarray + A change-of-basis matrix. + normalization : {True, False, 'maintain'} + Whether the vector will be L2-normalized (True; corresponds to the soft + cosine measure), maintain its L2-norm during the change of basis + ('maintain'; corresponds to query expansion with partial membership), + or kept as-is (False; corresponds to query expansion). + + Returns + ------- + vector : ndarray + The normalized dense vector. + + """ + if not normalization: + return vector + + vector_norm = vector.T.dot(matrix).dot(vector)[0, 0] + assert vector_norm >= 0.0, NON_NEGATIVE_NORM_ASSERTION_MESSAGE + if normalization == 'maintain' and vector_norm > 0.0: + vector_norm /= vector.T.dot(vector) + vector_norm = sqrt(vector_norm) + + normalized_vector = vector + if vector_norm > 0.0: + normalized_vector /= vector_norm + + return normalized_vector + + +def _normalize_dense_corpus(corpus, matrix, normalization): + """Normalize a dense corpus after a change of basis. + + Parameters + ---------- + corpus : MxN ndarray + A dense corpus. + matrix : NxN ndarray + A change-of-basis matrix. + normalization : {True, False, 'maintain'} + Whether the vector will be L2-normalized (True; corresponds to the soft + cosine measure), maintain its L2-norm during the change of basis + ('maintain'; corresponds to query expansion with partial membership), + or kept as-is (False; corresponds to query expansion). + + Returns + ------- + normalized_corpus : ndarray + The normalized dense corpus. + + """ + if not normalization: + return corpus + + # use the following equality: np.diag(A.T.dot(B).dot(A)) == A.T.dot(B).multiply(A.T).sum(axis=1).T + corpus_norm = np.multiply(corpus.T.dot(matrix), corpus.T).sum(axis=1).T + assert corpus_norm.min() >= 0.0, NON_NEGATIVE_NORM_ASSERTION_MESSAGE + if normalization == 'maintain': + corpus_norm /= np.multiply(corpus.T, corpus.T).sum(axis=1).T + corpus_norm = np.sqrt(corpus_norm) + + normalized_corpus = np.multiply(corpus, 1.0 / corpus_norm) + normalized_corpus = np.nan_to_num(normalized_corpus) # account for division by zero + return normalized_corpus + + +def _normalize_sparse_corpus(corpus, matrix, normalization): + """Normalize a sparse corpus after a change of basis. + + Parameters + ---------- + corpus : MxN :class:`scipy.sparse.csc_matrix` + A sparse corpus. + matrix : NxN :class:`scipy.sparse.csc_matrix` + A change-of-basis matrix. + normalization : {True, False, 'maintain'} + Whether the vector will be L2-normalized (True; corresponds to the soft + cosine measure), maintain its L2-norm during the change of basis + ('maintain'; corresponds to query expansion with partial membership), + or kept as-is (False; corresponds to query expansion). + + Returns + ------- + normalized_corpus : :class:`scipy.sparse.csc_matrix` + The normalized sparse corpus. + + """ + if not normalization: + return corpus + + # use the following equality: np.diag(A.T.dot(B).dot(A)) == A.T.dot(B).multiply(A.T).sum(axis=1).T + corpus_norm = corpus.T.dot(matrix).multiply(corpus.T).sum(axis=1).T + assert corpus_norm.min() >= 0.0, NON_NEGATIVE_NORM_ASSERTION_MESSAGE + if normalization == 'maintain': + corpus_norm /= corpus.T.multiply(corpus.T).sum(axis=1).T + corpus_norm = np.sqrt(corpus_norm) + + normalized_corpus = corpus.multiply(sparse.csr_matrix(1.0 / corpus_norm)) + normalized_corpus[normalized_corpus == np.inf] = 0 # account for division by zero + return normalized_corpus + + class SparseTermSimilarityMatrix(SaveLoad): """ Builds a sparse term similarity matrix using a term similarity index. - Notes - ----- - Building a DOK matrix, and converting it to a CSC matrix carries a significant memory overhead. - Future work should switch to building arrays of rows, columns, and non-zero elements and - directly passing these arrays to the CSC matrix constructor without copying. - Examples -------- >>> from gensim.test.utils import common_texts >>> from gensim.corpora import Dictionary >>> from gensim.models import Word2Vec, WordEmbeddingSimilarityIndex >>> from gensim.similarities import SoftCosineSimilarity, SparseTermSimilarityMatrix + >>> from gensim.similarities.index import AnnoyIndexer + >>> from scikits.sparse.cholmod import cholesky >>> >>> model = Word2Vec(common_texts, size=20, min_count=1) # train word-vectors - >>> termsim_index = WordEmbeddingSimilarityIndex(model.wv) + >>> annoy = AnnoyIndexer(model, num_trees=2) # use annoy for faster word similarity lookups + >>> termsim_index = WordEmbeddingSimilarityIndex(model.wv, kwargs={'indexer': annoy}) >>> dictionary = Dictionary(common_texts) >>> bow_corpus = [dictionary.doc2bow(document) for document in common_texts] - >>> similarity_matrix = SparseTermSimilarityMatrix(termsim_index, dictionary) # construct similarity matrix + >>> similarity_matrix = SparseTermSimilarityMatrix(termsim_index, dictionary, symmetric=True, dominant=True) >>> docsim_index = SoftCosineSimilarity(bow_corpus, similarity_matrix, num_best=10) >>> >>> query = 'graph trees computer'.split() # make a query >>> sims = docsim_index[dictionary.doc2bow(query)] # calculate similarity of query to each doc from bow_corpus + >>> + >>> word_embeddings = cholesky(similarity_matrix.matrix).L() # obtain word embeddings from similarity matrix Check out `Tutorial Notebook `_ @@ -192,125 +432,64 @@ class SparseTermSimilarityMatrix(SaveLoad): source : :class:`~gensim.similarities.termsim.TermSimilarityIndex` or :class:`scipy.sparse.spmatrix` The source of the term similarity. Either a term similarity index that will be used for building the term similarity matrix, or an existing sparse term similarity matrix that will - be encapsulated and stored in the matrix attribute. + be encapsulated and stored in the matrix attribute. When a matrix is specified as the + source, any other parameters will be ignored. dictionary : :class:`~gensim.corpora.dictionary.Dictionary` or None, optional A dictionary that specifies a mapping between terms and the indices of rows and columns - of the resulting term similarity matrix. The dictionary may only be `None` when `source` is + of the resulting term similarity matrix. The dictionary may only be None when source is a :class:`scipy.sparse.spmatrix`. tfidf : :class:`gensim.models.tfidfmodel.TfidfModel` or None, optional A model that specifies the relative importance of the terms in the dictionary. The columns of the term similarity matrix will be build in a decreasing order of importance of terms, or in the order of term identifiers if None. symmetric : bool, optional - Whether the symmetry of the term similarity matrix will be enforced. This parameter only has - an effect when `source` is a :class:`scipy.sparse.spmatrix`. Positive definiteness is a - necessary precondition if you later wish to derive a change-of-basis matrix from the term - similarity matrix using Cholesky factorization. - positive_definite: bool, optional - Whether the positive definiteness of the term similarity matrix will be enforced through - strict column diagonal dominance. Positive definiteness is a necessary precondition if you - later wish to derive a change-of-basis matrix from the term similarity matrix using Cholesky - factorization. + Whether the symmetry of the term similarity matrix will be enforced. Symmetry is a necessary + precondition for positive definiteness, which is necessary if you later wish to derive a + unique change-of-basis matrix from the term similarity matrix using Cholesky factorization. + Setting symmetric to False will significantly reduce memory usage during matrix construction. + dominant: bool, optional + Whether the strict column diagonal dominance of the term similarity matrix will be enforced. + Strict diagonal dominance and symmetry are sufficient preconditions for positive + definiteness, which is necessary if you later wish to derive a change-of-basis matrix from + the term similarity matrix using Cholesky factorization. nonzero_limit : int or None, optional The maximum number of non-zero elements outside the diagonal in a single column of the sparse term similarity matrix. If None, then no limit will be imposed. dtype : numpy.dtype, optional - Data-type of the sparse term similarity matrix. + The data type of the sparse term similarity matrix. + positive_definite: bool or None, optional + A deprecated alias for dominant. Attributes ---------- matrix : :class:`scipy.sparse.csc_matrix` The encapsulated sparse term similarity matrix. - """ - PROGRESS_MESSAGE_PERIOD = 1000 # how many columns are processed between progress messages - def __init__(self, source, dictionary=None, tfidf=None, symmetric=True, positive_definite=False, nonzero_limit=100, - dtype=np.float32): - if sparse.issparse(source): - self.matrix = source.tocsc() # encapsulate the passed sparse matrix - return + Raises + ------ + ValueError + If `dictionary` is empty. + + """ + def __init__(self, source, dictionary=None, tfidf=None, symmetric=True, dominant=False, + nonzero_limit=100, dtype=np.float32, positive_definite=None): - index = source - assert isinstance(index, TermSimilarityIndex) - assert dictionary is not None - matrix_order = len(dictionary) + if positive_definite is not None: + warnings.warn( + 'Parameter positive_definite will be removed in 4.0.0, use dominant instead', + category=DeprecationWarning, + ) + dominant = positive_definite - logger.info("constructing a sparse term similarity matrix using %s", index) + if not sparse.issparse(source): + index = source + args = (index, dictionary, tfidf, symmetric, dominant, nonzero_limit, dtype) + source = _create_source(*args) + assert sparse.issparse(source) - if nonzero_limit is None: - nonzero_limit = matrix_order + self.matrix = source.tocsc() - if tfidf is None: - logger.info("iterating over columns in dictionary order") - columns = sorted(dictionary.keys()) - else: - assert max(tfidf.idfs) == matrix_order - 1 - logger.info("iterating over columns in tf-idf order") - columns = [ - term_index for term_index, _ - in sorted( - tfidf.idfs.items(), - key=lambda x: (lambda term_index, term_idf: (term_idf, -term_index))(*x), reverse=True)] - - column_nonzero = np.array([0] * matrix_order, dtype=_shortest_uint_dtype(nonzero_limit)) - column_sum = np.zeros(matrix_order, dtype=dtype) - matrix = sparse.identity(matrix_order, dtype=dtype, format="dok") - - for column_number, t1_index in enumerate(columns): - if column_number % self.PROGRESS_MESSAGE_PERIOD == 0: - logger.info( - "PROGRESS: at %.02f%% columns (%d / %d, %.06f%% density, " - "%.06f%% projected density)", - 100.0 * (column_number + 1) / matrix_order, column_number + 1, matrix_order, - 100.0 * matrix.getnnz() / matrix_order**2, - 100.0 * np.clip( - (1.0 * (matrix.getnnz() - matrix_order) / matrix_order**2) - * (1.0 * matrix_order / (column_number + 1)) - + (1.0 / matrix_order), # add density correspoding to the main diagonal - 0.0, 1.0)) - - t1 = dictionary[t1_index] - num_nonzero = column_nonzero[t1_index] - num_rows = nonzero_limit - num_nonzero - most_similar = [ - (dictionary.token2id[term], similarity) - for term, similarity in index.most_similar(t1, topn=num_rows) - if term in dictionary.token2id - ] if num_rows > 0 else [] - - if tfidf is None: - rows = sorted(most_similar) - else: - rows = sorted( - most_similar, - key=lambda x: (lambda term_index, _: (tfidf.idfs[term_index], -term_index))(*x), reverse=True) - - for row_number, (t2_index, similarity) in zip(range(num_rows), rows): - if positive_definite and column_sum[t1_index] + abs(similarity) >= 1.0: - break - if symmetric: - if column_nonzero[t2_index] < nonzero_limit \ - and (not positive_definite or column_sum[t2_index] + abs(similarity) < 1.0) \ - and not (t1_index, t2_index) in matrix: - matrix[t1_index, t2_index] = similarity - column_nonzero[t1_index] += 1 - column_sum[t1_index] += abs(similarity) - matrix[t2_index, t1_index] = similarity - column_nonzero[t2_index] += 1 - column_sum[t2_index] += abs(similarity) - else: - matrix[t1_index, t2_index] = similarity - column_sum[t1_index] += abs(similarity) - - logger.info( - "constructed a sparse term similarity matrix with %0.06f%% density", - 100.0 * matrix.getnnz() / matrix_order**2) - - matrix = matrix.T - assert sparse.issparse(matrix) - self.__init__(matrix) - - def inner_product(self, X, Y, normalized=False): + def inner_product(self, X, Y, normalized=(False, False)): """Get the inner product(s) between real vectors / corpora X and Y. Return the inner product(s) between real vectors / corpora vec1 and vec2 expressed in a @@ -323,10 +502,11 @@ def inner_product(self, X, Y, normalized=False): A query vector / corpus in the sparse bag-of-words format. vec2 : list of (int, float) or iterable of list of (int, float) A document vector / corpus in the sparse bag-of-words format. - normalized : bool, optional - Whether the inner product should be L2-normalized. The normalized inner product - corresponds to the Soft Cosine Measure (SCM). SCM is a number between <-1.0, 1.0>, - where higher is more similar. + normalized : tuple of {True, False, 'maintain'}, optional + First/second value specifies whether the query/document vectors in the inner product + will be L2-normalized (True; corresponds to the soft cosine measure), maintain their + L2-norm during change of basis ('maintain'; corresponds to query expansion with partial + membership), or kept as-is (False; corresponds to query expansion; default). Returns ------- @@ -336,14 +516,35 @@ def inner_product(self, X, Y, normalized=False): References ---------- The soft cosine measure was perhaps first described by [sidorovetal14]_. + Further notes on the efficient implementation of the soft cosine measure are described by + [novotny18]_. .. [sidorovetal14] Grigori Sidorov et al., "Soft Similarity and Soft Cosine Measure: Similarity of Features in Vector Space Model", 2014, http://www.cys.cic.ipn.mx/ojs/index.php/CyS/article/view/2043/1921. + .. [novotny18] Vít Novotný, "Implementation Notes for the Soft Cosine Measure", 2018, + http://dx.doi.org/10.1145/3269206.3269317. + """ if not X or not Y: return self.matrix.dtype.type(0.0) + if normalized in (True, False): + warnings.warn( + 'Boolean parameter normalized will be removed in 4.0.0, use ' + 'normalized=(%s, %s) instead of normalized=%s' % tuple([normalized] * 3), + category=DeprecationWarning, + ) + normalized = (normalized, normalized) + + normalized_X, normalized_Y = normalized + valid_normalized_values = (True, False, 'maintain') + + if normalized_X not in valid_normalized_values: + raise ValueError('{} is not a valid value of normalize'.format(normalized_X)) + if normalized_Y not in valid_normalized_values: + raise ValueError('{} is not a valid value of normalize'.format(normalized_Y)) + is_corpus_X, X = is_corpus(X) is_corpus_Y, Y = is_corpus(Y) @@ -356,24 +557,19 @@ def inner_product(self, X, Y, normalized=False): Y = np.array([Y[i] if i in Y else 0 for i in word_indices], dtype=dtype) matrix = self.matrix[word_indices[:, None], word_indices].todense() + X = _normalize_dense_vector(X, matrix, normalized_X) + Y = _normalize_dense_vector(Y, matrix, normalized_Y) result = X.T.dot(matrix).dot(Y) - if normalized: - X_norm = X.T.dot(matrix).dot(X)[0, 0] - Y_norm = Y.T.dot(matrix).dot(Y)[0, 0] - - assert \ - X_norm > 0.0 and Y_norm > 0.0, \ - u"sparse documents must not contain any explicit zero entries and the similarity matrix S " \ - u"must satisfy x^T * S * x > 0 for any nonzero bag-of-words vector x." - - result /= sqrt(X_norm) * sqrt(Y_norm) + if normalized_X is True and normalized_Y is True: result = np.clip(result, -1.0, 1.0) return result[0, 0] elif not is_corpus_X or not is_corpus_Y: if is_corpus_X and not is_corpus_Y: - is_corpus_X, X, is_corpus_Y, Y = is_corpus_Y, Y, is_corpus_X, X # make Y the corpus + X, Y = Y, X # make Y the corpus + is_corpus_X, is_corpus_Y = is_corpus_Y, is_corpus_X + normalized_X, normalized_Y = normalized_Y, normalized_X transposed = True else: transposed = False @@ -387,23 +583,12 @@ def inner_product(self, X, Y, normalized=False): X = np.array([X[i] if i in X else 0 for i in word_indices], dtype=dtype) Y = corpus2csc(Y, num_terms=self.matrix.shape[0], dtype=dtype)[word_indices, :].todense() matrix = self.matrix[word_indices[:, None], word_indices].todense() - if normalized: - # use the following equality: np.diag(A.T.dot(B).dot(A)) == A.T.dot(B).multiply(A.T).sum(axis=1).T - X_norm = np.multiply(X.T.dot(matrix), X.T).sum(axis=1).T - Y_norm = np.multiply(Y.T.dot(matrix), Y.T).sum(axis=1).T - - assert \ - X_norm.min() > 0.0 and Y_norm.min() >= 0.0, \ - u"sparse documents must not contain any explicit zero entries and the similarity matrix S " \ - u"must satisfy x^T * S * x > 0 for any nonzero bag-of-words vector x." - - X = np.multiply(X, 1 / np.sqrt(X_norm)).T - Y = np.multiply(Y, 1 / np.sqrt(Y_norm)) - Y = np.nan_to_num(Y) # Account for division by zero when Y_norm.min() == 0.0 - result = X.T.dot(matrix).dot(Y) + X = _normalize_dense_vector(X, matrix, normalized_X) + Y = _normalize_dense_corpus(Y, matrix, normalized_Y) + result = X.dot(matrix).dot(Y) - if normalized: + if normalized_X is True and normalized_Y is True: result = np.clip(result, -1.0, 1.0) if transposed: @@ -416,23 +601,11 @@ def inner_product(self, X, Y, normalized=False): Y = corpus2csc(Y if is_corpus_Y else [Y], num_terms=self.matrix.shape[0], dtype=dtype) matrix = self.matrix - if normalized: - # use the following equality: np.diag(A.T.dot(B).dot(A)) == A.T.dot(B).multiply(A.T).sum(axis=1).T - X_norm = X.T.dot(matrix).multiply(X.T).sum(axis=1).T - Y_norm = Y.T.dot(matrix).multiply(Y.T).sum(axis=1).T - - assert \ - X_norm.min() > 0.0 and Y_norm.min() >= 0.0, \ - u"sparse documents must not contain any explicit zero entries and the similarity matrix S " \ - u"must satisfy x^T * S * x > 0 for any nonzero bag-of-words vector x." - - X = X.multiply(sparse.csr_matrix(1 / np.sqrt(X_norm))) - Y = Y.multiply(sparse.csr_matrix(1 / np.sqrt(Y_norm))) - Y[Y == np.inf] = 0 # Account for division by zero when Y_norm.min() == 0.0 - + X = _normalize_sparse_corpus(X, matrix, normalized_X) + Y = _normalize_sparse_corpus(Y, matrix, normalized_Y) result = X.T.dot(matrix).dot(Y) - if normalized: + if normalized_X is True and normalized_Y is True: result.data = np.clip(result.data, -1.0, 1.0) return result diff --git a/gensim/test/test_similarities.py b/gensim/test/test_similarities.py index fbd8f53ade..6a898f1a67 100644 --- a/gensim/test/test_similarities.py +++ b/gensim/test/test_similarities.py @@ -876,7 +876,16 @@ def setUp(self): [u"government", u"denied", u"holiday", u"slowing", u"hollingworth"]] self.dictionary = Dictionary(self.documents) self.tfidf = TfidfModel(dictionary=self.dictionary) + zero_index = UniformTermSimilarityIndex(self.dictionary, term_similarity=0.0) self.index = UniformTermSimilarityIndex(self.dictionary, term_similarity=0.5) + self.identity_matrix = SparseTermSimilarityMatrix(zero_index, self.dictionary) + self.uniform_matrix = SparseTermSimilarityMatrix(self.index, self.dictionary) + self.vec1 = self.dictionary.doc2bow([u"government", u"government", u"denied"]) + self.vec2 = self.dictionary.doc2bow([u"government", u"holiday"]) + + def test_empty_dictionary(self): + with self.assertRaises(ValueError): + SparseTermSimilarityMatrix(self.index, []) def test_type(self): """Test the type of the produced matrix.""" @@ -942,6 +951,29 @@ def test_symmetric(self): [0.0, 0.0, 0.0, 0.0, 1.0]]) self.assertTrue(numpy.all(expected_matrix == matrix)) + def test_dominant(self): + """Test the dominant parameter of the matrix constructor.""" + negative_index = UniformTermSimilarityIndex(self.dictionary, term_similarity=-0.5) + matrix = SparseTermSimilarityMatrix( + negative_index, self.dictionary, nonzero_limit=2).matrix.todense() + expected_matrix = numpy.array([ + [1.0, -.5, -.5, 0.0, 0.0], + [-.5, 1.0, 0.0, -.5, 0.0], + [-.5, 0.0, 1.0, 0.0, 0.0], + [0.0, -.5, 0.0, 1.0, 0.0], + [0.0, 0.0, 0.0, 0.0, 1.0]]) + self.assertTrue(numpy.all(expected_matrix == matrix)) + + matrix = SparseTermSimilarityMatrix( + negative_index, self.dictionary, nonzero_limit=2, dominant=True).matrix.todense() + expected_matrix = numpy.array([ + [1.0, -.5, 0.0, 0.0, 0.0], + [-.5, 1.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 1.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 1.0, 0.0], + [0.0, 0.0, 0.0, 0.0, 1.0]]) + self.assertTrue(numpy.all(expected_matrix == matrix)) + def test_positive_definite(self): """Test the positive_definite parameter of the matrix constructor.""" negative_index = UniformTermSimilarityIndex(self.dictionary, term_similarity=-0.5) @@ -1004,109 +1036,533 @@ def test_encapsulation(self): self.assertTrue(isinstance(matrix, scipy.sparse.csc_matrix)) self.assertTrue(numpy.all(matrix.todense() == expected_matrix)) - def test_inner_product(self): - """Test the inner product.""" + def test_inner_product_zerovector_zerovector_default(self): + """Test the inner product between two zero vectors with the default normalization.""" - matrix = SparseTermSimilarityMatrix( - UniformTermSimilarityIndex(self.dictionary, term_similarity=0.5), self.dictionary) + self.assertEqual(0.0, self.uniform_matrix.inner_product([], [])) + + def test_inner_product_zerovector_zerovector_false_maintain(self): + """Test the inner product between two zero vectors with the (False, 'maintain') normalization.""" + + self.assertEqual(0.0, self.uniform_matrix.inner_product([], [], normalized=(False, 'maintain'))) + + def test_inner_product_zerovector_zerovector_false_true(self): + """Test the inner product between two zero vectors with the (False, True) normalization.""" + + self.assertEqual(0.0, self.uniform_matrix.inner_product([], [], normalized=(False, True))) + + def test_inner_product_zerovector_zerovector_maintain_false(self): + """Test the inner product between two zero vectors with the ('maintain', False) normalization.""" + + self.assertEqual(0.0, self.uniform_matrix.inner_product([], [], normalized=('maintain', False))) + + def test_inner_product_zerovector_zerovector_maintain_maintain(self): + """Test the inner product between two zero vectors with the ('maintain', 'maintain') normalization.""" + + self.assertEqual(0.0, self.uniform_matrix.inner_product([], [], normalized=('maintain', 'maintain'))) + + def test_inner_product_zerovector_zerovector_maintain_true(self): + """Test the inner product between two zero vectors with the ('maintain', True) normalization.""" + + self.assertEqual(0.0, self.uniform_matrix.inner_product([], [], normalized=('maintain', True))) + + def test_inner_product_zerovector_zerovector_true_false(self): + """Test the inner product between two zero vectors with the (True, False) normalization.""" + + self.assertEqual(0.0, self.uniform_matrix.inner_product([], [], normalized=(True, False))) + + def test_inner_product_zerovector_zerovector_true_maintain(self): + """Test the inner product between two zero vectors with the (True, 'maintain') normalization.""" + + self.assertEqual(0.0, self.uniform_matrix.inner_product([], [], normalized=(True, 'maintain'))) + + def test_inner_product_zerovector_zerovector_true_true(self): + """Test the inner product between two zero vectors with the (True, True) normalization.""" + + self.assertEqual(0.0, self.uniform_matrix.inner_product([], [], normalized=(True, True))) + + def test_inner_product_zerovector_vector_default(self): + """Test the inner product between a zero vector and a vector with the default normalization.""" + + self.assertEqual(0.0, self.uniform_matrix.inner_product([], self.vec2)) + + def test_inner_product_zerovector_vector_false_maintain(self): + """Test the inner product between a zero vector and a vector with the (False, 'maintain') normalization.""" + + self.assertEqual(0.0, self.uniform_matrix.inner_product([], self.vec2, normalized=(False, 'maintain'))) + + def test_inner_product_zerovector_vector_false_true(self): + """Test the inner product between a zero vector and a vector with the (False, True) normalization.""" + + self.assertEqual(0.0, self.uniform_matrix.inner_product([], self.vec2, normalized=(False, True))) + + def test_inner_product_zerovector_vector_maintain_false(self): + """Test the inner product between a zero vector and a vector with the ('maintain', False) normalization.""" + + self.assertEqual(0.0, self.uniform_matrix.inner_product([], self.vec2, normalized=('maintain', False))) + + def test_inner_product_zerovector_vector_maintain_maintain(self): + """Test the inner product between a zero vector and a vector with the ('maintain', 'maintain') normalization.""" + + self.assertEqual(0.0, self.uniform_matrix.inner_product([], self.vec2, normalized=('maintain', 'maintain'))) + + def test_inner_product_zerovector_vector_maintain_true(self): + """Test the inner product between a zero vector and a vector with the ('maintain', True) normalization.""" + + self.assertEqual(0.0, self.uniform_matrix.inner_product([], self.vec2, normalized=('maintain', True))) + + def test_inner_product_zerovector_vector_true_false(self): + """Test the inner product between a zero vector and a vector with the (True, False) normalization.""" + + self.assertEqual(0.0, self.uniform_matrix.inner_product([], self.vec2, normalized=(True, False))) - # check zero vectors work as expected - vec1 = self.dictionary.doc2bow([u"government", u"government", u"denied"]) - vec2 = self.dictionary.doc2bow([u"government", u"holiday"]) + def test_inner_product_zerovector_vector_true_maintain(self): + """Test the inner product between a zero vector and a vector with the (True, 'maintain') normalization.""" - self.assertEqual(0.0, matrix.inner_product([], vec2)) - self.assertEqual(0.0, matrix.inner_product(vec1, [])) - self.assertEqual(0.0, matrix.inner_product([], [])) + self.assertEqual(0.0, self.uniform_matrix.inner_product([], self.vec2, normalized=(True, 'maintain'))) - self.assertEqual(0.0, matrix.inner_product([], vec2, normalized=True)) - self.assertEqual(0.0, matrix.inner_product(vec1, [], normalized=True)) - self.assertEqual(0.0, matrix.inner_product([], [], normalized=True)) + def test_inner_product_zerovector_vector_true_true(self): + """Test the inner product between a zero vector and a vector with the (True, True) normalization.""" + + self.assertEqual(0.0, self.uniform_matrix.inner_product([], self.vec2, normalized=(True, True))) + + def test_inner_product_vector_zerovector_default(self): + """Test the inner product between a vector and a zero vector with the default normalization.""" + + self.assertEqual(0.0, self.uniform_matrix.inner_product(self.vec1, [])) + + def test_inner_product_vector_zerovector_false_maintain(self): + """Test the inner product between a vector and a zero vector with the (False, 'maintain') normalization.""" + + self.assertEqual(0.0, self.uniform_matrix.inner_product(self.vec1, [], normalized=(False, 'maintain'))) + + def test_inner_product_vector_zerovector_false_true(self): + """Test the inner product between a vector and a zero vector with the (False, True) normalization.""" + + self.assertEqual(0.0, self.uniform_matrix.inner_product(self.vec1, [], normalized=(False, True))) + + def test_inner_product_vector_zerovector_maintain_false(self): + """Test the inner product between a vector and a zero vector with the ('maintain', False) normalization.""" + + self.assertEqual(0.0, self.uniform_matrix.inner_product(self.vec1, [], normalized=('maintain', False))) + + def test_inner_product_vector_zerovector_maintain_maintain(self): + """Test the inner product between a vector and a zero vector with the ('maintain', 'maintain') normalization.""" + + self.assertEqual(0.0, self.uniform_matrix.inner_product(self.vec1, [], normalized=('maintain', 'maintain'))) + + def test_inner_product_vector_zerovector_maintain_true(self): + """Test the inner product between a vector and a zero vector with the ('maintain', True) normalization.""" + + self.assertEqual(0.0, self.uniform_matrix.inner_product(self.vec1, [], normalized=('maintain', True))) + + def test_inner_product_vector_zerovector_true_false(self): + """Test the inner product between a vector and a zero vector with the (True, False) normalization.""" + + self.assertEqual(0.0, self.uniform_matrix.inner_product(self.vec1, [], normalized=(True, False))) + + def test_inner_product_vector_zerovector_true_maintain(self): + """Test the inner product between a vector and a zero vector with the (True, 'maintain') normalization.""" + + self.assertEqual(0.0, self.uniform_matrix.inner_product(self.vec1, [], normalized=(True, 'maintain'))) + + def test_inner_product_vector_zerovector_true_true(self): + """Test the inner product between a vector and a zero vector with the (True, True) normalization.""" + + self.assertEqual(0.0, self.uniform_matrix.inner_product(self.vec1, [], normalized=(True, True))) + + def test_inner_product_vector_vector_default(self): + """Test the inner product between two vectors with the default normalization.""" - # check that real-world vectors work as expected - vec1 = self.dictionary.doc2bow([u"government", u"government", u"denied"]) - vec2 = self.dictionary.doc2bow([u"government", u"holiday"]) expected_result = 0.0 expected_result += 2 * 1.0 * 1 # government * s_{ij} * government expected_result += 2 * 0.5 * 1 # government * s_{ij} * holiday expected_result += 1 * 0.5 * 1 # denied * s_{ij} * government expected_result += 1 * 0.5 * 1 # denied * s_{ij} * holiday - result = matrix.inner_product(vec1, vec2) + result = self.uniform_matrix.inner_product(self.vec1, self.vec2) self.assertAlmostEqual(expected_result, result, places=5) - vec1 = self.dictionary.doc2bow([u"government", u"government", u"denied"]) - vec2 = self.dictionary.doc2bow([u"government", u"holiday"]) - expected_result = matrix.inner_product(vec1, vec2) - expected_result /= math.sqrt(matrix.inner_product(vec1, vec1)) - expected_result /= math.sqrt(matrix.inner_product(vec2, vec2)) - result = matrix.inner_product(vec1, vec2, normalized=True) + def test_inner_product_vector_vector_false_maintain(self): + """Test the inner product between two vectors with the (False, 'maintain') normalization.""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec2, self.vec2)) + expected_result *= math.sqrt(self.identity_matrix.inner_product(self.vec2, self.vec2)) + result = self.uniform_matrix.inner_product(self.vec1, self.vec2, normalized=(False, 'maintain')) + self.assertAlmostEqual(expected_result, result, places=5) + + def test_inner_product_vector_vector_false_true(self): + """Test the inner product between two vectors with the (False, True) normalization.""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec2, self.vec2)) + result = self.uniform_matrix.inner_product(self.vec1, self.vec2, normalized=(False, True)) self.assertAlmostEqual(expected_result, result, places=5) - # check that real-world (vector, corpus) pairs work as expected - vec1 = self.dictionary.doc2bow([u"government", u"government", u"denied"]) - vec2 = self.dictionary.doc2bow([u"government", u"holiday"]) + def test_inner_product_vector_vector_maintain_false(self): + """Test the inner product between two vectors with the ('maintain', False) normalization.""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec1, self.vec1)) + expected_result *= math.sqrt(self.identity_matrix.inner_product(self.vec1, self.vec1)) + result = self.uniform_matrix.inner_product(self.vec1, self.vec2, normalized=('maintain', False)) + self.assertAlmostEqual(expected_result, result, places=5) + + def test_inner_product_vector_vector_maintain_maintain(self): + """Test the inner product between two vectors with the ('maintain', 'maintain') normalization.""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec1, self.vec1)) + expected_result *= math.sqrt(self.identity_matrix.inner_product(self.vec1, self.vec1)) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec2, self.vec2)) + expected_result *= math.sqrt(self.identity_matrix.inner_product(self.vec2, self.vec2)) + result = self.uniform_matrix.inner_product(self.vec1, self.vec2, normalized=('maintain', 'maintain')) + self.assertAlmostEqual(expected_result, result, places=5) + + def test_inner_product_vector_vector_maintain_true(self): + """Test the inner product between two vectors with the ('maintain', True) normalization.""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec1, self.vec1)) + expected_result *= math.sqrt(self.identity_matrix.inner_product(self.vec1, self.vec1)) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec2, self.vec2)) + result = self.uniform_matrix.inner_product(self.vec1, self.vec2, normalized=('maintain', True)) + self.assertAlmostEqual(expected_result, result, places=5) + + def test_inner_product_vector_vector_true_false(self): + """Test the inner product between two vectors with the (True, False) normalization.""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec1, self.vec1)) + result = self.uniform_matrix.inner_product(self.vec1, self.vec2, normalized=(True, False)) + self.assertAlmostEqual(expected_result, result, places=5) + + def test_inner_product_vector_vector_true_maintain(self): + """Test the inner product between two vectors with the (True, 'maintain') normalization.""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec1, self.vec1)) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec2, self.vec2)) + expected_result *= math.sqrt(self.identity_matrix.inner_product(self.vec2, self.vec2)) + result = self.uniform_matrix.inner_product(self.vec1, self.vec2, normalized=(True, 'maintain')) + self.assertAlmostEqual(expected_result, result, places=5) + + def test_inner_product_vector_vector_true_true(self): + """Test the inner product between two vectors with the (True, True) normalization.""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec1, self.vec1)) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec2, self.vec2)) + result = self.uniform_matrix.inner_product(self.vec1, self.vec2, normalized=(True, True)) + self.assertAlmostEqual(expected_result, result, places=5) + + def test_inner_product_vector_corpus_default(self): + """Test the inner product between a vector and a corpus with the default normalization.""" + expected_result = 0.0 expected_result += 2 * 1.0 * 1 # government * s_{ij} * government expected_result += 2 * 0.5 * 1 # government * s_{ij} * holiday expected_result += 1 * 0.5 * 1 # denied * s_{ij} * government expected_result += 1 * 0.5 * 1 # denied * s_{ij} * holiday expected_result = numpy.full((1, 2), expected_result) - result = matrix.inner_product(vec1, [vec2] * 2) + result = self.uniform_matrix.inner_product(self.vec1, [self.vec2] * 2) + self.assertTrue(isinstance(result, numpy.ndarray)) + self.assertTrue(numpy.allclose(expected_result, result)) + + def test_inner_product_vector_corpus_false_maintain(self): + """Test the inner product between a vector and a corpus with the (False, 'maintain') normalization.""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec2, self.vec2)) + expected_result *= math.sqrt(self.identity_matrix.inner_product(self.vec2, self.vec2)) + expected_result = numpy.full((1, 2), expected_result) + result = self.uniform_matrix.inner_product(self.vec1, [self.vec2] * 2, normalized=(False, 'maintain')) self.assertTrue(isinstance(result, numpy.ndarray)) self.assertTrue(numpy.allclose(expected_result, result)) - vec1 = self.dictionary.doc2bow([u"government", u"government", u"denied"]) - vec2 = self.dictionary.doc2bow([u"government", u"holiday"]) - expected_result = matrix.inner_product(vec1, vec2) - expected_result /= math.sqrt(matrix.inner_product(vec1, vec1)) - expected_result /= math.sqrt(matrix.inner_product(vec2, vec2)) + def test_inner_product_vector_corpus_false_true(self): + """Test the inner product between a vector and a corpus with the (False, True) normalization.""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec2, self.vec2)) expected_result = numpy.full((1, 2), expected_result) - result = matrix.inner_product(vec1, [vec2] * 2, normalized=True) + result = self.uniform_matrix.inner_product(self.vec1, [self.vec2] * 2, normalized=(False, True)) self.assertTrue(isinstance(result, numpy.ndarray)) self.assertTrue(numpy.allclose(expected_result, result)) - # check that real-world (corpus, vector) pairs work as expected - vec1 = self.dictionary.doc2bow([u"government", u"government", u"denied"]) - vec2 = self.dictionary.doc2bow([u"government", u"holiday"]) + def test_inner_product_vector_corpus_maintain_false(self): + """Test the inner product between a vector and a corpus with the ('maintain', False) normalization.""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec1, self.vec1)) + expected_result *= math.sqrt(self.identity_matrix.inner_product(self.vec1, self.vec1)) + expected_result = numpy.full((1, 2), expected_result) + result = self.uniform_matrix.inner_product(self.vec1, [self.vec2] * 2, normalized=('maintain', False)) + self.assertTrue(isinstance(result, numpy.ndarray)) + self.assertTrue(numpy.allclose(expected_result, result)) + + def test_inner_product_vector_corpus_maintain_maintain(self): + """Test the inner product between a vector and a corpus with the ('maintain', 'maintain') normalization.""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec1, self.vec1)) + expected_result *= math.sqrt(self.identity_matrix.inner_product(self.vec1, self.vec1)) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec2, self.vec2)) + expected_result *= math.sqrt(self.identity_matrix.inner_product(self.vec2, self.vec2)) + expected_result = numpy.full((1, 2), expected_result) + result = self.uniform_matrix.inner_product(self.vec1, [self.vec2] * 2, normalized=('maintain', 'maintain')) + self.assertTrue(isinstance(result, numpy.ndarray)) + self.assertTrue(numpy.allclose(expected_result, result)) + + def test_inner_product_vector_corpus_maintain_true(self): + """Test the inner product between a vector and a corpus with the ('maintain', True) normalization.""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec1, self.vec1)) + expected_result *= math.sqrt(self.identity_matrix.inner_product(self.vec1, self.vec1)) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec2, self.vec2)) + expected_result = numpy.full((1, 2), expected_result) + result = self.uniform_matrix.inner_product(self.vec1, [self.vec2] * 2, normalized=('maintain', True)) + self.assertTrue(isinstance(result, numpy.ndarray)) + self.assertTrue(numpy.allclose(expected_result, result)) + + def test_inner_product_vector_corpus_true_false(self): + """Test the inner product between a vector and a corpus with the (True, False) normalization.""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec1, self.vec1)) + expected_result = numpy.full((1, 2), expected_result) + result = self.uniform_matrix.inner_product(self.vec1, [self.vec2] * 2, normalized=(True, False)) + self.assertTrue(isinstance(result, numpy.ndarray)) + self.assertTrue(numpy.allclose(expected_result, result)) + + def test_inner_product_vector_corpus_true_maintain(self): + """Test the inner product between a vector and a corpus with the (True, 'maintain') normalization.""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec1, self.vec1)) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec2, self.vec2)) + expected_result *= math.sqrt(self.identity_matrix.inner_product(self.vec2, self.vec2)) + expected_result = numpy.full((1, 2), expected_result) + result = self.uniform_matrix.inner_product(self.vec1, [self.vec2] * 2, normalized=(True, 'maintain')) + self.assertTrue(isinstance(result, numpy.ndarray)) + self.assertTrue(numpy.allclose(expected_result, result)) + + def test_inner_product_vector_corpus_true_true(self): + """Test the inner product between a vector and a corpus with the (True, True) normalization.""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec1, self.vec1)) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec2, self.vec2)) + expected_result = numpy.full((1, 2), expected_result) + result = self.uniform_matrix.inner_product(self.vec1, [self.vec2] * 2, normalized=(True, True)) + self.assertTrue(isinstance(result, numpy.ndarray)) + self.assertTrue(numpy.allclose(expected_result, result)) + + def test_inner_product_corpus_vector_default(self): + """Test the inner product between a corpus and a vector with the default normalization.""" + expected_result = 0.0 expected_result += 2 * 1.0 * 1 # government * s_{ij} * government expected_result += 2 * 0.5 * 1 # government * s_{ij} * holiday expected_result += 1 * 0.5 * 1 # denied * s_{ij} * government expected_result += 1 * 0.5 * 1 # denied * s_{ij} * holiday expected_result = numpy.full((3, 1), expected_result) - result = matrix.inner_product([vec1] * 3, vec2) + result = self.uniform_matrix.inner_product([self.vec1] * 3, self.vec2) + self.assertTrue(isinstance(result, numpy.ndarray)) + self.assertTrue(numpy.allclose(expected_result, result)) + + def test_inner_product_corpus_vector_false_maintain(self): + """Test the inner product between a corpus and a vector with the (False, 'maintain') normalization.""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec2, self.vec2)) + expected_result *= math.sqrt(self.identity_matrix.inner_product(self.vec2, self.vec2)) + expected_result = numpy.full((3, 1), expected_result) + result = self.uniform_matrix.inner_product([self.vec1] * 3, self.vec2, normalized=(False, 'maintain')) + self.assertTrue(isinstance(result, numpy.ndarray)) + self.assertTrue(numpy.allclose(expected_result, result)) + + def test_inner_product_corpus_vector_false_true(self): + """Test the inner product between a corpus and a vector with the (False, True) normalization.""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec2, self.vec2)) + expected_result = numpy.full((3, 1), expected_result) + result = self.uniform_matrix.inner_product([self.vec1] * 3, self.vec2, normalized=(False, True)) + self.assertTrue(isinstance(result, numpy.ndarray)) + self.assertTrue(numpy.allclose(expected_result, result)) + + def test_inner_product_corpus_vector_maintain_false(self): + """Test the inner product between a corpus and a vector with the ('maintain', False) normalization.""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec1, self.vec1)) + expected_result *= math.sqrt(self.identity_matrix.inner_product(self.vec1, self.vec1)) + expected_result = numpy.full((3, 1), expected_result) + result = self.uniform_matrix.inner_product([self.vec1] * 3, self.vec2, normalized=('maintain', False)) + self.assertTrue(isinstance(result, numpy.ndarray)) + self.assertTrue(numpy.allclose(expected_result, result)) + + def test_inner_product_corpus_vector_maintain_maintain(self): + """Test the inner product between a corpus and a vector with the ('maintain', 'maintain') normalization.""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec1, self.vec1)) + expected_result *= math.sqrt(self.identity_matrix.inner_product(self.vec1, self.vec1)) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec2, self.vec2)) + expected_result *= math.sqrt(self.identity_matrix.inner_product(self.vec2, self.vec2)) + expected_result = numpy.full((3, 1), expected_result) + result = self.uniform_matrix.inner_product([self.vec1] * 3, self.vec2, normalized=('maintain', 'maintain')) + self.assertTrue(isinstance(result, numpy.ndarray)) + self.assertTrue(numpy.allclose(expected_result, result)) + + def test_inner_product_corpus_vector_maintain_true(self): + """Test the inner product between a corpus and a vector with the ('maintain', True) normalization.""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec1, self.vec1)) + expected_result *= math.sqrt(self.identity_matrix.inner_product(self.vec1, self.vec1)) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec2, self.vec2)) + expected_result = numpy.full((3, 1), expected_result) + result = self.uniform_matrix.inner_product([self.vec1] * 3, self.vec2, normalized=('maintain', True)) + self.assertTrue(isinstance(result, numpy.ndarray)) + self.assertTrue(numpy.allclose(expected_result, result)) + + def test_inner_product_corpus_vector_true_false(self): + """Test the inner product between a corpus and a vector with the (True, False) normalization.""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec1, self.vec1)) + expected_result = numpy.full((3, 1), expected_result) + result = self.uniform_matrix.inner_product([self.vec1] * 3, self.vec2, normalized=(True, False)) + self.assertTrue(isinstance(result, numpy.ndarray)) + self.assertTrue(numpy.allclose(expected_result, result)) + + def test_inner_product_corpus_vector_true_maintain(self): + """Test the inner product between a corpus and a vector with the (True, 'maintain') normalization.""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec1, self.vec1)) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec2, self.vec2)) + expected_result *= math.sqrt(self.identity_matrix.inner_product(self.vec2, self.vec2)) + expected_result = numpy.full((3, 1), expected_result) + result = self.uniform_matrix.inner_product([self.vec1] * 3, self.vec2, normalized=(True, 'maintain')) self.assertTrue(isinstance(result, numpy.ndarray)) self.assertTrue(numpy.allclose(expected_result, result)) - vec1 = self.dictionary.doc2bow([u"government", u"government", u"denied"]) - vec2 = self.dictionary.doc2bow([u"government", u"holiday"]) - expected_result = matrix.inner_product(vec1, vec2) - expected_result /= math.sqrt(matrix.inner_product(vec1, vec1)) - expected_result /= math.sqrt(matrix.inner_product(vec2, vec2)) + def test_inner_product_corpus_vector_true_true(self): + """Test the inner product between a corpus and a vector with the (True, True) normalization.""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec1, self.vec1)) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec2, self.vec2)) expected_result = numpy.full((3, 1), expected_result) - result = matrix.inner_product([vec1] * 3, vec2, normalized=True) + result = self.uniform_matrix.inner_product([self.vec1] * 3, self.vec2, normalized=(True, True)) self.assertTrue(isinstance(result, numpy.ndarray)) self.assertTrue(numpy.allclose(expected_result, result)) - # check that real-world corpora work as expected - vec1 = self.dictionary.doc2bow([u"government", u"government", u"denied"]) - vec2 = self.dictionary.doc2bow([u"government", u"holiday"]) + def test_inner_product_corpus_corpus_default(self): + """Test the inner product between two corpora with the default normalization.""" + expected_result = 0.0 expected_result += 2 * 1.0 * 1 # government * s_{ij} * government expected_result += 2 * 0.5 * 1 # government * s_{ij} * holiday expected_result += 1 * 0.5 * 1 # denied * s_{ij} * government expected_result += 1 * 0.5 * 1 # denied * s_{ij} * holiday expected_result = numpy.full((3, 2), expected_result) - result = matrix.inner_product([vec1] * 3, [vec2] * 2) + result = self.uniform_matrix.inner_product([self.vec1] * 3, [self.vec2] * 2) + self.assertTrue(isinstance(result, scipy.sparse.csr_matrix)) + self.assertTrue(numpy.allclose(expected_result, result.todense())) + + def test_inner_product_corpus_corpus_false_maintain(self): + """Test the inner product between two corpora with the (False, 'maintain').""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec2, self.vec2)) + expected_result *= math.sqrt(self.identity_matrix.inner_product(self.vec2, self.vec2)) + expected_result = numpy.full((3, 2), expected_result) + result = self.uniform_matrix.inner_product([self.vec1] * 3, [self.vec2] * 2, normalized=(False, 'maintain')) self.assertTrue(isinstance(result, scipy.sparse.csr_matrix)) self.assertTrue(numpy.allclose(expected_result, result.todense())) - vec1 = self.dictionary.doc2bow([u"government", u"government", u"denied"]) - vec2 = self.dictionary.doc2bow([u"government", u"holiday"]) - expected_result = matrix.inner_product(vec1, vec2) - expected_result /= math.sqrt(matrix.inner_product(vec1, vec1)) - expected_result /= math.sqrt(matrix.inner_product(vec2, vec2)) + def test_inner_product_corpus_corpus_false_true(self): + """Test the inner product between two corpora with the (False, True).""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec2, self.vec2)) + expected_result = numpy.full((3, 2), expected_result) + result = self.uniform_matrix.inner_product([self.vec1] * 3, [self.vec2] * 2, normalized=(False, True)) + self.assertTrue(isinstance(result, scipy.sparse.csr_matrix)) + self.assertTrue(numpy.allclose(expected_result, result.todense())) + + def test_inner_product_corpus_corpus_maintain_false(self): + """Test the inner product between two corpora with the ('maintain', False).""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec1, self.vec1)) + expected_result *= math.sqrt(self.identity_matrix.inner_product(self.vec1, self.vec1)) + expected_result = numpy.full((3, 2), expected_result) + result = self.uniform_matrix.inner_product([self.vec1] * 3, [self.vec2] * 2, normalized=('maintain', False)) + self.assertTrue(isinstance(result, scipy.sparse.csr_matrix)) + self.assertTrue(numpy.allclose(expected_result, result.todense())) + + def test_inner_product_corpus_corpus_maintain_maintain(self): + """Test the inner product between two corpora with the ('maintain', 'maintain').""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec1, self.vec1)) + expected_result *= math.sqrt(self.identity_matrix.inner_product(self.vec1, self.vec1)) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec2, self.vec2)) + expected_result *= math.sqrt(self.identity_matrix.inner_product(self.vec2, self.vec2)) + expected_result = numpy.full((3, 2), expected_result) + result = self.uniform_matrix.inner_product([self.vec1] * 3, [self.vec2] * 2, + normalized=('maintain', 'maintain')) + self.assertTrue(isinstance(result, scipy.sparse.csr_matrix)) + self.assertTrue(numpy.allclose(expected_result, result.todense())) + + def test_inner_product_corpus_corpus_maintain_true(self): + """Test the inner product between two corpora with the ('maintain', True).""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec1, self.vec1)) + expected_result *= math.sqrt(self.identity_matrix.inner_product(self.vec1, self.vec1)) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec2, self.vec2)) + expected_result = numpy.full((3, 2), expected_result) + result = self.uniform_matrix.inner_product([self.vec1] * 3, [self.vec2] * 2, normalized=('maintain', True)) + self.assertTrue(isinstance(result, scipy.sparse.csr_matrix)) + self.assertTrue(numpy.allclose(expected_result, result.todense())) + + def test_inner_product_corpus_corpus_true_false(self): + """Test the inner product between two corpora with the (True, False).""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec1, self.vec1)) + expected_result = numpy.full((3, 2), expected_result) + result = self.uniform_matrix.inner_product([self.vec1] * 3, [self.vec2] * 2, normalized=(True, False)) + self.assertTrue(isinstance(result, scipy.sparse.csr_matrix)) + self.assertTrue(numpy.allclose(expected_result, result.todense())) + + def test_inner_product_corpus_corpus_true_maintain(self): + """Test the inner product between two corpora with the (True, 'maintain').""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec1, self.vec1)) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec2, self.vec2)) + expected_result *= math.sqrt(self.identity_matrix.inner_product(self.vec2, self.vec2)) + expected_result = numpy.full((3, 2), expected_result) + result = self.uniform_matrix.inner_product([self.vec1] * 3, [self.vec2] * 2, normalized=(True, 'maintain')) + self.assertTrue(isinstance(result, scipy.sparse.csr_matrix)) + self.assertTrue(numpy.allclose(expected_result, result.todense())) + + def test_inner_product_corpus_corpus_true_true(self): + """Test the inner product between two corpora with the (True, True).""" + + expected_result = self.uniform_matrix.inner_product(self.vec1, self.vec2) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec1, self.vec1)) + expected_result /= math.sqrt(self.uniform_matrix.inner_product(self.vec2, self.vec2)) expected_result = numpy.full((3, 2), expected_result) - result = matrix.inner_product([vec1] * 3, [vec2] * 2, normalized=True) + result = self.uniform_matrix.inner_product([self.vec1] * 3, [self.vec2] * 2, normalized=(True, True)) self.assertTrue(isinstance(result, scipy.sparse.csr_matrix)) self.assertTrue(numpy.allclose(expected_result, result.todense())) From 28a211028df29dd3e24ac878e7ba646af9538571 Mon Sep 17 00:00:00 2001 From: Gordon Mohr Date: Sun, 16 Aug 2020 19:49:27 -0700 Subject: [PATCH 28/32] Fix doc2vec crash for large sets of doc-vectors (#2907) --- gensim/models/doc2vec_corpusfile.pyx | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/gensim/models/doc2vec_corpusfile.pyx b/gensim/models/doc2vec_corpusfile.pyx index 5b8cbeabff..40bf20bdd3 100644 --- a/gensim/models/doc2vec_corpusfile.pyx +++ b/gensim/models/doc2vec_corpusfile.pyx @@ -162,7 +162,7 @@ def d2v_train_epoch_dbow( cdef int sent_idx, idx_start, idx_end cdef vector[string] doc_words - cdef int _doc_tag = start_doctag + cdef long long _doc_tag = start_doctag init_d2v_config( &c, model, _alpha, learn_doctags, learn_words, learn_hidden, train_words=train_words, @@ -302,7 +302,7 @@ def d2v_train_epoch_dm( cdef REAL_t count, inv_count = 1.0 cdef vector[string] doc_words - cdef int _doc_tag = start_doctag + cdef long long _doc_tag = start_doctag init_d2v_config( &c, model, _alpha, learn_doctags, learn_words, learn_hidden, train_words=False, @@ -455,7 +455,7 @@ def d2v_train_epoch_dm_concat( cdef int sent_idx, idx_start, idx_end cdef vector[string] doc_words - cdef int _doc_tag = start_doctag + cdef long long _doc_tag = start_doctag init_d2v_config( &c, model, _alpha, learn_doctags, learn_words, learn_hidden, train_words=False, @@ -469,6 +469,17 @@ def d2v_train_epoch_dm_concat( effective_words = 0 doc_words = input_stream.read_sentence() + + # FIXME? These next 2 lines look fishy to me (gojomo). First, skipping to + # 'total_documents' (end) seems it'd do nothing useful. Second, assigning + # into what is typically a count (`doctag_len`) from a boolean test is + # sketchy, even if in the current limitations of this mode (corpus_file) + # only '1' is a workable value. But, this code seems to pass at least + # one real has-some-function test (test_dmc_hs_fromfile), and this mode + # is rarely used, & I haven't written this code & would prefer to see the + # whole duplicate-logic of corpus_file mode removed in favor of an approach + # with less duplication. So I'm not sure anything is broken & it's far from + # a near-term priority - thus leaving this note. _doc_tag = total_documents c.doctag_len = _doc_tag < c.docvecs_count From 817cac99422a255001034203dc0720f7d0df0ce6 Mon Sep 17 00:00:00 2001 From: jeni Shah Date: Mon, 17 Aug 2020 08:33:02 +0530 Subject: [PATCH 29/32] Fix AttributeError in WikiCorpus (#2901) * bug fix: wikicorpus getstream from data file-path \n Replace fname with input * refactor: use property decorator for input Co-authored-by: jshah02 --- gensim/corpora/wikicorpus.py | 4 ++++ gensim/test/test_corpora.py | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/gensim/corpora/wikicorpus.py b/gensim/corpora/wikicorpus.py index ba371225ab..78affc1028 100644 --- a/gensim/corpora/wikicorpus.py +++ b/gensim/corpora/wikicorpus.py @@ -639,6 +639,10 @@ def __init__(self, fname, processes=None, lemmatize=utils.has_pattern(), diction else: self.dictionary = dictionary + @property + def input(self): + return self.fname + def get_texts(self): """Iterate over the dump, yielding a list of tokens for each article that passed the length and namespace filtering. diff --git a/gensim/test/test_corpora.py b/gensim/test/test_corpora.py index 6660542b48..e13e06ca36 100644 --- a/gensim/test/test_corpora.py +++ b/gensim/test/test_corpora.py @@ -769,6 +769,11 @@ def test_removed_table_markup(self): for word in table_markup: self.assertTrue(word not in text) + def test_get_stream(self): + wiki = self.corpus_class(self.enwiki) + sample_text_wiki = next(wiki.getstream()).decode()[1:14] + self.assertEqual(sample_text_wiki, "mediawiki xml") + # #TODO: sporadic failure to be investigated # def test_get_texts_returns_generator_of_lists(self): # corpus = self.corpus_class(self.enwiki) From fc4b97fbd6893a44c699eedb439200afbdcc0271 Mon Sep 17 00:00:00 2001 From: Gordon Mohr Date: Tue, 1 Sep 2020 20:32:05 -0700 Subject: [PATCH 30/32] intensify cbow+hs tests; bulk testing method --- gensim/test/test_word2vec.py | 57 ++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/gensim/test/test_word2vec.py b/gensim/test/test_word2vec.py index f7a73ee375..6d53fc8cba 100644 --- a/gensim/test/test_word2vec.py +++ b/gensim/test/test_word2vec.py @@ -11,6 +11,7 @@ import logging import unittest +import pytest import os import bz2 import sys @@ -589,7 +590,7 @@ def testEvaluateWordPairsFromFile(self): self.assertTrue(0.1 < spearman < 1.0, "spearman %f not between 0.1 and 1.0" % spearman) self.assertTrue(0.0 <= oov < 90.0, "oov %f not between 0.0 and 90.0" % oov) - def model_sanity(self, model, train=True, with_corpus_file=False): + def model_sanity(self, model, train=True, with_corpus_file=False, ranks=None): """Even tiny models trained on LeeCorpus should pass these sanity checks""" # run extra before/after training tests if train=True if train: @@ -603,14 +604,18 @@ def model_sanity(self, model, train=True, with_corpus_file=False): else: model.train(lee_corpus_list, total_examples=model.corpus_count, epochs=model.epochs) self.assertFalse((orig0 == model.wv.vectors[1]).all()) # vector should vary after training - sims = model.wv.most_similar('war', topn=len(model.wv.index2word)) - t_rank = [word for word, score in sims].index('terrorism') + query_word = 'attacks' + expected_word = 'bombings' + sims = model.wv.most_similar(query_word, topn=len(model.wv.index2word)) + t_rank = [word for word, score in sims].index(expected_word) # in >200 calibration runs w/ calling parameters, 'terrorism' in 50-most_sim for 'war' + if ranks is not None: + ranks.append(t_rank) # tabulate trial rank if requested self.assertLess(t_rank, 50) - war_vec = model.wv['war'] - sims2 = model.wv.most_similar([war_vec], topn=51) - self.assertTrue('war' in [word for word, score in sims2]) - self.assertTrue('terrorism' in [word for word, score in sims2]) + query_vec = model.wv[query_word] + sims2 = model.wv.most_similar([query_vec], topn=51) + self.assertTrue(query_word in [word for word, score in sims2]) + self.assertTrue(expected_word in [word for word, score in sims2]) def test_sg_hs(self): """Test skipgram w/ hierarchical softmax""" @@ -632,29 +637,51 @@ def test_sg_neg_fromfile(self): model = word2vec.Word2Vec(sg=1, window=4, hs=0, negative=15, min_count=5, epochs=10, workers=2) self.model_sanity(model, with_corpus_file=True) - def test_cbow_hs(self): + @pytest.mark.skipif('BULK_TEST_REPS' not in os.environ, reason="bulk test only occasionally run locally") + def test_method_in_bulk(self): + """Not run by default testing, but can be run locally to help tune stochastic aspects of tests + to very-very-rarely fail. EG: + % BULK_TEST_REPS=200 METHOD_NAME=test_cbow_hs pytest test_word2vec.py -k "test_method_in_bulk" + Method must accept `ranks` keyword-argument, empty list into which salient internal result can be reported. + """ + failures = 0 + ranks = [] + reps = int(os.environ['BULK_TEST_REPS']) + method_name = os.environ.get('METHOD_NAME', 'test_cbow_hs') # by default test that specially-troublesome one + method_fn = getattr(self, method_name) + for i in range(reps): + try: + method_fn(ranks=ranks) + except Exception as ex: + print('%s failed: %s' % (method_name, ex)) + failures = failures + 1 + print(ranks) + print(np.mean(ranks)) + self.assertEquals(failures, 0, "too many failures") + + def test_cbow_hs(self, ranks=None): """Test CBOW w/ hierarchical softmax""" model = word2vec.Word2Vec( - sg=0, cbow_mean=1, alpha=0.05, window=8, hs=1, negative=0, - min_count=5, epochs=20, workers=2, batch_words=1000 + sg=0, cbow_mean=1, alpha=0.1, window=2, hs=1, negative=0, + min_count=5, epochs=60, workers=2, batch_words=1000 ) - self.model_sanity(model) + self.model_sanity(model, ranks=ranks) @unittest.skipIf(os.name == 'nt' and six.PY2, "CythonLineSentence is not supported on Windows + Py27") def test_cbow_hs_fromfile(self): model = word2vec.Word2Vec( - sg=0, cbow_mean=1, alpha=0.05, window=8, hs=1, negative=0, - min_count=5, epochs=20, workers=2, batch_words=1000 + sg=0, cbow_mean=1, alpha=0.1, window=2, hs=1, negative=0, + min_count=5, epochs=60, workers=2, batch_words=1000 ) self.model_sanity(model, with_corpus_file=True) - def test_cbow_neg(self): + def test_cbow_neg(self, ranks=None): """Test CBOW w/ negative sampling""" model = word2vec.Word2Vec( sg=0, cbow_mean=1, alpha=0.05, window=5, hs=0, negative=15, min_count=5, epochs=10, workers=2, sample=0 ) - self.model_sanity(model) + self.model_sanity(model, ranks=ranks) @unittest.skipIf(os.name == 'nt' and six.PY2, "CythonLineSentence is not supported on Windows + Py27") def test_cbow_neg_fromfile(self): From 030e650a223320f2d1176936ff8abf0180acc0db Mon Sep 17 00:00:00 2001 From: Gordon Mohr Date: Wed, 2 Sep 2020 09:49:51 -0700 Subject: [PATCH 31/32] use increment operator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Radim Řehůřek --- gensim/test/test_word2vec.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gensim/test/test_word2vec.py b/gensim/test/test_word2vec.py index 6d53fc8cba..001ad4c365 100644 --- a/gensim/test/test_word2vec.py +++ b/gensim/test/test_word2vec.py @@ -654,7 +654,7 @@ def test_method_in_bulk(self): method_fn(ranks=ranks) except Exception as ex: print('%s failed: %s' % (method_name, ex)) - failures = failures + 1 + failures += 1 print(ranks) print(np.mean(ranks)) self.assertEquals(failures, 0, "too many failures") From 6e0d00b3da13b0b503e1cda7f7eb47e2c958e881 Mon Sep 17 00:00:00 2001 From: Megan Date: Thu, 3 Sep 2020 12:41:01 +0100 Subject: [PATCH 32/32] Change num_words to topn in dtm_coherence (#2926) --- gensim/models/wrappers/dtmmodel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gensim/models/wrappers/dtmmodel.py b/gensim/models/wrappers/dtmmodel.py index 4530bbb3b7..7271e45cf1 100644 --- a/gensim/models/wrappers/dtmmodel.py +++ b/gensim/models/wrappers/dtmmodel.py @@ -604,7 +604,7 @@ def dtm_coherence(self, time, num_words=20): """ coherence_topics = [] for topic_no in range(0, self.num_topics): - topic = self.show_topic(topicid=topic_no, time=time, num_words=num_words) + topic = self.show_topic(topicid=topic_no, time=time, topn=num_words) coherence_topic = [] for prob, word in topic: coherence_topic.append(word)