web-dev-qa-db-fra.com

gensim Doc2Vec vs tensorflow Doc2Vec

J'essaie de comparer mon implémentation de Doc2Vec (via tf) et l'implémentation de gensims. Il semble au moins visuellement que les gens du monde fonctionnent mieux.

J'ai exécuté le code suivant pour former le modèle gensim et celui ci-dessous pour le modèle tensorflow. Mes questions sont les suivantes:

  1. Mon implémentation tf de Doc2Vec est-elle correcte? Fondamentalement, est-il censé concaténer les vecteurs Word et le vecteur de document pour prédire le mot du milieu dans un certain contexte?
  2. Est-ce que le window=5 paramètre dans gensim signifie que j'utilise deux mots de chaque côté pour prédire celui du milieu? Ou est-ce 5 de chaque côté. Le fait est qu'il y a pas mal de documents qui sont plus petits que la longueur 10.
  3. Avez-vous une idée des raisons pour lesquelles Gensim fonctionne mieux? Mon modèle est-il différent de la façon dont ils le mettent en œuvre?
  4. Étant donné qu'il s'agit effectivement d'un problème de factorisation matricielle, pourquoi le modèle TF obtient-il même une réponse? Il existe des solutions infinies à cela, car c'est un problème de rang déficient. <- Cette dernière question est simplement un bonus.

Gensim

model = Doc2Vec(dm=1, dm_concat=1, size=100, window=5, negative=10, hs=0, min_count=2, workers=cores)
model.build_vocab(corpus)
epochs = 100
for i in range(epochs):
    model.train(corpus)

TF

batch_size = 512
embedding_size = 100 # Dimension of the embedding vector.
num_sampled = 10 # Number of negative examples to sample.


graph = tf.Graph()

with graph.as_default(), tf.device('/cpu:0'):
    # Input data.
    train_Word_dataset = tf.placeholder(tf.int32, shape=[batch_size])
    train_doc_dataset = tf.placeholder(tf.int32, shape=[batch_size/context_window])
    train_labels = tf.placeholder(tf.int32, shape=[batch_size/context_window, 1])

    # The variables   
    Word_embeddings =  tf.Variable(tf.random_uniform([vocabulary_size,embedding_size],-1.0,1.0))
    doc_embeddings = tf.Variable(tf.random_uniform([len_docs,embedding_size],-1.0,1.0))
    softmax_weights = tf.Variable(tf.truncated_normal([vocabulary_size, (context_window+1)*embedding_size],
                             stddev=1.0 / np.sqrt(embedding_size)))
    softmax_biases = tf.Variable(tf.zeros([vocabulary_size]))

    ###########################
    # Model.
    ###########################
    # Look up embeddings for inputs and stack words side by side
    embed_words = tf.reshape(tf.nn.embedding_lookup(Word_embeddings, train_Word_dataset),
                            shape=[int(batch_size/context_window),-1])
    embed_docs = tf.nn.embedding_lookup(doc_embeddings, train_doc_dataset)
    embed = tf.concat(1,[embed_words, embed_docs])
    # Compute the softmax loss, using a sample of the negative labels each time.
    loss = tf.reduce_mean(tf.nn.sampled_softmax_loss(softmax_weights, softmax_biases, embed,
                                   train_labels, num_sampled, vocabulary_size))

    # Optimizer.
    optimizer = tf.train.AdagradOptimizer(1.0).minimize(loss)

Mise à jour:

Consultez le cahier jupyter ici (J'ai les deux modèles qui fonctionnent et sont testés ici). Il semble toujours que le modèle gensim fonctionne mieux dans cette analyse initiale.

45
sachinruk

Vieille question, mais une réponse serait utile pour les futurs visiteurs. Voici donc certaines de mes pensées.

Il y a quelques problèmes dans l'implémentation de tensorflow:

  • window est de la taille d'un côté, donc window=5 serait 5*2+1 = 11 mots.
  • Notez qu'avec la version PV-DM de doc2vec, le batch_size serait le nombre de documents. Alors train_Word_dataset la forme serait batch_size * context_window, tandis que train_doc_dataset et train_labels les formes seraient batch_size.
  • Plus important, sampled_softmax_loss n'est pas negative_sampling_loss. Ce sont deux approximations différentes de softmax_loss.

Donc, pour les questions énumérées du PO:

  1. Cette implémentation de doc2vec in tensorflow fonctionne et se corrige à sa manière, mais il est différent de l'implémentation gensim et du papier.
  2. window est de la taille d'un côté comme indiqué ci-dessus. Si la taille du document est inférieure à la taille du contexte, alors le plus petit serait utilisé.
  3. Il existe de nombreuses raisons pour lesquelles la mise en œuvre de gensim est plus rapide. Premièrement, gensim a été fortement optimisé, toutes les opérations sont plus rapides que les opérations naïves python, en particulier les E/S de données. Deuxièmement, certaines étapes de prétraitement telles que min_count le filtrage dans gensim réduirait la taille de l'ensemble de données. Plus important encore, gensim utilise negative_sampling_loss, ce qui est beaucoup plus rapide que sampled_softmax_loss, Je suppose que c'est la principale raison.
  4. Est-il plus facile de trouver quelque chose quand il y en a beaucoup? Je rigole ;-)
    Il est vrai qu'il existe de nombreuses solutions à ce problème d'optimisation non convexe, donc le modèle ne ferait que trouver un optimum local. Fait intéressant, dans le réseau neuronal, la plupart des optima locaux sont "assez bons". Il a été observé que la descente de gradient stochastique semble trouver de meilleurs optima locaux que la descente de gradient de lot plus important, bien que ce soit encore une énigme dans la recherche actuelle.
14
THN