Repository: piskvorky/gensim

Issue:
Doc2Vec defaults shouldn't override Word2Vec defaults without good reason
Following #534, Word2Vec matches the word2vec.c defaults (as of the time Google stopped updating/maintaining that code). However, where our Doc2Vec class takes its own parameters – `hs`, `negative`, `sample`, `window`, and `dm_mean` – it's still using the older defaults. There's not really any case that these older defaults are better – and in some cases they're probably worse. 

Unless there's a reason for different defaults, Doc2Vec should use the same values as Word2Vec... ideally by not specifying them at all (to avoid duplication). This probably means removing those params from the `__init__()` signature – but still documenting them in the doc-comment – so that the extra keywords just pass through to `Word2Vec.__init__()` if/when present. 



Discussion:

Resolving patch:
diff --git a/gensim/models/doc2vec.py b/gensim/models/doc2vec.py
--- a/gensim/models/doc2vec.py
+++ b/gensim/models/doc2vec.py
@@ -529,9 +529,8 @@ def repeat(self, word_count):
 
 class Doc2Vec(Word2Vec):
     """Class for training, using and evaluating neural networks described in http://arxiv.org/pdf/1405.4053v2.pdf"""
-    def __init__(self, documents=None, size=300, alpha=0.025, window=8, min_count=5,
-                 max_vocab_size=None, sample=0, seed=1, workers=1, min_alpha=0.0001,
-                 dm=1, hs=1, negative=0, dbow_words=0, dm_mean=0, dm_concat=0, dm_tag_count=1,
+    def __init__(self, documents=None, dm_mean=None,
+                 dm=1, dbow_words=0, dm_concat=0, dm_tag_count=1,
                  docvecs=None, docvecs_mapfile=None, comment=None, trim_rule=None, **kwargs):
         """
         Initialize the model from an iterable of `documents`. Each document is a
@@ -600,18 +599,20 @@ def __init__(self, documents=None, size=300, alpha=0.025, window=8, min_count=5,
           of the model.
 
         """
+
         super(Doc2Vec, self).__init__(
-            size=size, alpha=alpha, window=window, min_count=min_count, max_vocab_size=max_vocab_size,
-            sample=sample, seed=seed, workers=workers, min_alpha=min_alpha,
-            sg=(1+dm) % 2, hs=hs, negative=negative, cbow_mean=dm_mean,
+            sg=(1 + dm) % 2,
             null_word=dm_concat, **kwargs)
+
+        if dm_mean is not None:
+            self.cbow_mean = dm_mean
+
         self.dbow_words = dbow_words
         self.dm_concat = dm_concat
         self.dm_tag_count = dm_tag_count
         if self.dm and self.dm_concat:
             self.layer1_size = (self.dm_tag_count + (2 * self.window)) * self.vector_size
-        else:
-            self.layer1_size = size
+
         self.docvecs = docvecs or DocvecsArray(docvecs_mapfile)
         self.comment = comment
         if documents is not None:


Test patch:
diff --git a/gensim/test/test_doc2vec.py b/gensim/test/test_doc2vec.py
--- a/gensim/test/test_doc2vec.py
+++ b/gensim/test/test_doc2vec.py
@@ -87,7 +87,7 @@ def test_int_doctags(self):
         model = doc2vec.Doc2Vec(min_count=1)
         model.build_vocab(corpus)
         self.assertEqual(len(model.docvecs.doctag_syn0), 300)
-        self.assertEqual(model.docvecs[0].shape, (300,))
+        self.assertEqual(model.docvecs[0].shape, (100,))
         self.assertRaises(KeyError, model.__getitem__, '_*0')
 
     def test_missing_string_doctag(self):
@@ -108,9 +108,10 @@ def test_string_doctags(self):
 
         model = doc2vec.Doc2Vec(min_count=1)
         model.build_vocab(corpus)
+
         self.assertEqual(len(model.docvecs.doctag_syn0), 300)
-        self.assertEqual(model.docvecs[0].shape, (300,))
-        self.assertEqual(model.docvecs['_*0'].shape, (300,))
+        self.assertEqual(model.docvecs[0].shape, (100,))
+        self.assertEqual(model.docvecs['_*0'].shape, (100,))
         self.assertTrue(all(model.docvecs['_*0'] == model.docvecs[0]))
         self.assertTrue(max(d.offset for d in model.docvecs.doctags.values()) < len(model.docvecs.doctags))
         self.assertTrue(max(model.docvecs._int_index(str_key) for str_key in model.docvecs.doctags.keys()) < len(model.docvecs.doctag_syn0))
@@ -168,7 +169,7 @@ def model_sanity(self, model):
     def test_training(self):
         """Test doc2vec training."""
         corpus = DocsLeeCorpus()
-        model = doc2vec.Doc2Vec(size=100, min_count=2, iter=20)
+        model = doc2vec.Doc2Vec(size=100, min_count=2, iter=20, workers=1)
         model.build_vocab(corpus)
         self.assertEqual(model.docvecs.doctag_syn0.shape, (300, 100))
         model.train(corpus)
@@ -176,7 +177,7 @@ def test_training(self):
         self.model_sanity(model)
 
         # build vocab and train in one step; must be the same as above
-        model2 = doc2vec.Doc2Vec(corpus, size=100, min_count=2, iter=20)
+        model2 = doc2vec.Doc2Vec(corpus, size=100, min_count=2, iter=20, workers=1)
         self.models_equal(model, model2)
 
     def test_dbow_hs(self):