Repository: piskvorky/gensim

Issue:
Re-enable tests for Keras integration
The Keras tests started failing on py3.7 + 3.8 in #2899:

https://travis-ci.org/github/RaRe-Technologies/gensim/jobs/713448950#L862

None of the changes in that PR seem related to these errors, so probably some TF / Keras weirdness again.

**Task**: Look into it and either fix, or rip out that entire Keras submodule. One of the contributed / never properly vetted features. Or Keras is that unstable… same difference.


Discussion:
Related: #2911. 

Resolving patch:
diff --git a/gensim/models/keyedvectors.py b/gensim/models/keyedvectors.py
--- a/gensim/models/keyedvectors.py
+++ b/gensim/models/keyedvectors.py
@@ -1588,47 +1588,8 @@ def intersect_word2vec_format(self, fname, lockf=0.0, binary=False, encoding='ut
                         self.vectors_lockf[self.get_index(word)] = lockf  # lock-factor: 0.0=no changes
         logger.info("merged %d vectors into %s matrix from %s", overlap_count, self.wv.vectors.shape, fname)
 
-    def get_keras_embedding(self, train_embeddings=False):
-        """Get a Keras 'Embedding' layer with weights set as the Word2Vec model's learned word embeddings.
-
-        Parameters
-        ----------
-        train_embeddings : bool
-            If False, the weights are frozen and stopped from being updated.
-            If True, the weights can/will be further trained/updated.
-
-        Returns
-        -------
-        `keras.layers.Embedding`
-            Embedding layer.
-
-        Raises
-        ------
-        ImportError
-            If `Keras <https://pypi.org/project/Keras/>`_ not installed.
-
-        Warnings
-        --------
-        Current method work only if `Keras <https://pypi.org/project/Keras/>`_ installed.
-
-        """
-        try:
-            from keras.layers import Embedding
-        except ImportError:
-            raise ImportError("Please install Keras to use this function")
-        weights = self.vectors
-
-        # set `trainable` as `False` to use the pretrained word embedding
-        # No extra mem usage here as `Embedding` layer doesn't create any new matrix for weights
-        layer = Embedding(
-            input_dim=weights.shape[0], output_dim=weights.shape[1],
-            weights=[weights], trainable=train_embeddings
-        )
-        return layer
-
     def _upconvert_old_d2vkv(self):
         """Convert a deserialized older Doc2VecKeyedVectors instance to latest generic KeyedVectors"""
-
         self.vocab = self.doctags
         self._upconvert_old_vocab()  # destroys 'vocab', fills 'key_to_index' & 'extras'
         for k in self.key_to_index.keys():
@@ -1636,7 +1597,7 @@ def _upconvert_old_d2vkv(self):
             true_index = old_offset + self.max_rawint + 1
             self.key_to_index[k] = true_index
         del self.expandos['offset']  # no longer needed
-        if(self.max_rawint > -1):
+        if self.max_rawint > -1:
             self.index_to_key = list(range(0, self.max_rawint + 1)) + self.offset2doctag
         else:
             self.index_to_key = self.offset2doctag
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -280,13 +280,6 @@ def run(self):
 
 # Add additional requirements for testing on Linux that are skipped on Windows.
 linux_testenv = core_testenv[:] + visdom_req + ['pyemd', ]
-if sys.version_info >= (3, 7):
-    # HACK: Installing tensorflow causes a segfault in Travis on py3.6. Other Pythons work – a mystery.
-    # See https://github.com/RaRe-Technologies/gensim/pull/2814#issuecomment-621477948
-    linux_testenv += [
-        'tensorflow',
-        'keras==2.3.1',
-    ]
 
 # Skip problematic/uninstallable  packages (& thus related conditional tests) in Windows builds.
 # We still test them in Linux via Travis, see linux_testenv above.


Test patch:
diff --git a/gensim/test/test_keras_integration.py b/gensim/test/test_keras_integration.py
deleted file mode 100644
--- a/gensim/test/test_keras_integration.py
+++ /dev/null
@@ -1,152 +0,0 @@
-import unittest
-
-import numpy as np
-
-try:
-    from sklearn.datasets import fetch_20newsgroups
-except ImportError:
-    raise unittest.SkipTest("Test requires sklearn to be installed, which is not available")
-
-try:
-    import keras
-    from keras.engine import Input
-    from keras.models import Model
-    from keras.layers.merge import dot
-    from keras.preprocessing.text import Tokenizer
-    from keras.preprocessing.sequence import pad_sequences
-    from keras.utils.np_utils import to_categorical
-    from keras.layers import Dense, Flatten
-    from keras.layers import Conv1D, MaxPooling1D
-except ImportError:
-    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)
-        self.model_twenty_ng = word2vec.Word2Vec(min_count=1)
-
-    def testWord2VecTraining(self):
-        """
-        Test word2vec training.
-        """
-        model = self.model_cos_sim
-        self.assertTrue(model.wv.vectors.shape == (len(model.wv), 100))
-        self.assertTrue(model.syn1.shape == (len(model.wv), 100))
-        sims = model.wv.most_similar('graph', topn=10)
-        # self.assertTrue(sims[0][0] == 'trees', sims)  # most similar
-
-        # test querying for "most similar" by vector
-        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)
-
-    def testEmbeddingLayerCosineSim(self):
-        """
-        Test Keras 'Embedding' layer returned by 'get_embedding_layer' function for a simple word similarity task.
-        """
-        keras_w2v_model = self.model_cos_sim
-        keras_w2v_model_wv = keras_w2v_model.wv
-
-        embedding_layer = keras_w2v_model_wv.get_keras_embedding()
-
-        input_a = Input(shape=(1,), dtype='int32', name='input_a')
-        input_b = Input(shape=(1,), dtype='int32', name='input_b')
-        embedding_a = embedding_layer(input_a)
-        embedding_b = embedding_layer(input_b)
-        similarity = dot([embedding_a, embedding_b], axes=2, normalize=True)
-
-        model = Model(inputs=[input_a, input_b], outputs=similarity)
-        model.compile(optimizer='sgd', loss='mse')
-
-        word_a = 'graph'
-        word_b = 'trees'
-        output = model.predict([
-            np.asarray([keras_w2v_model.wv.get_index(word_a)]),
-            np.asarray([keras_w2v_model.wv.get_index(word_b)])
-        ])
-        # output is the cosine distance between the two words (as a similarity measure)
-
-        self.assertTrue(type(output[0][0][0]) == np.float32)     # verify that  a float is returned
-
-    def testEmbeddingLayer20NewsGroup(self):
-        """
-        Test Keras 'Embedding' layer returned by 'get_embedding_layer' function
-        for a smaller version of the 20NewsGroup classification problem.
-        """
-        MAX_SEQUENCE_LENGTH = 1000
-
-        # Prepare text samples and their labels
-
-        # Processing text dataset
-        texts = []  # list of text samples
-        texts_w2v = []  # used to train the word embeddings
-        labels = []  # list of label ids
-
-        data = fetch_20newsgroups(subset='train', categories=['alt.atheism', 'comp.graphics', 'sci.space'])
-        for index in range(len(data)):
-            label_id = data.target[index]
-            file_data = data.data[index]
-            i = file_data.find('\n\n')  # skip header
-            if i > 0:
-                file_data = file_data[i:]
-            try:
-                curr_str = str(file_data)
-                sentence_list = curr_str.split('\n')
-                for sentence in sentence_list:
-                    sentence = (sentence.strip()).lower()
-                    texts.append(sentence)
-                    texts_w2v.append(sentence.split(' '))
-                    labels.append(label_id)
-            except Exception:
-                pass
-
-        # Vectorize the text samples into a 2D integer tensor
-        tokenizer = Tokenizer()
-        tokenizer.fit_on_texts(texts)
-        sequences = tokenizer.texts_to_sequences(texts)
-
-        # word_index = tokenizer.word_index
-        data = pad_sequences(sequences, maxlen=MAX_SEQUENCE_LENGTH)
-        labels = to_categorical(np.asarray(labels))
-
-        x_train = data
-        y_train = labels
-
-        # prepare the embedding layer using the wrapper
-        keras_w2v = self.model_twenty_ng
-        keras_w2v.build_vocab(texts_w2v)
-        keras_w2v.train(texts, total_examples=keras_w2v.corpus_count, epochs=keras_w2v.epochs)
-        keras_w2v_wv = keras_w2v.wv
-        embedding_layer = keras_w2v_wv.get_keras_embedding()
-
-        # create a 1D convnet to solve our classification task
-        sequence_input = Input(shape=(MAX_SEQUENCE_LENGTH,), dtype='int32')
-        embedded_sequences = embedding_layer(sequence_input)
-        x = Conv1D(128, 5, activation='relu')(embedded_sequences)
-        x = MaxPooling1D(5)(x)
-        x = Conv1D(128, 5, activation='relu')(x)
-        x = MaxPooling1D(5)(x)
-        x = Conv1D(128, 5, activation='relu')(x)
-        x = MaxPooling1D(35)(x)  # global max pooling
-        x = Flatten()(x)
-        x = Dense(128, activation='relu')(x)
-        preds = Dense(y_train.shape[1], activation='softmax')(x)
-
-        model = Model(sequence_input, preds)
-        model.compile(loss='categorical_crossentropy', optimizer='rmsprop', metrics=['acc'])
-        fit_ret_val = model.fit(x_train, y_train, epochs=1)
-
-        # verify the type of the object returned after training
-        # value returned is a `History` instance.
-        # Its `history` attribute contains all information collected during training.
-        self.assertTrue(type(fit_ret_val) == keras.callbacks.History)
-
-
-if __name__ == '__main__':
-    unittest.main()