Je suis récemment tombé sur l'addition doc2vec à Gensim. Comment puis-je utiliser des vecteurs Word pré-formés (par exemple, trouvés sur le site Web original de Word2vec) avec doc2vec?
Ou est-ce que doc2vec obtient les vecteurs Word à partir des mêmes phrases qu'il utilise pour la formation de vecteur de paragraphe?
Merci.
Notez que le mode de formation "DBOW" (dm=0
) Ne nécessite pas ou ne crée même pas de vecteurs Word dans le cadre de la formation. Il apprend simplement les vecteurs de documents qui sont bons pour prédire tour à tour chaque mot (un peu comme le mode d'apprentissage de saut de gramme Word2vec).
(Avant gensim 0.12.0, il y avait le paramètre train_words
Mentionné dans un autre commentaire, qui, selon la documentation, co-entraînerait les mots. Cependant, je ne pense pas que cela ait réellement fonctionné. À partir de gensim 0.12.0 , il y a le paramètre dbow_words
, qui fonctionne pour sauter les mots de train gramme simultanément avec les vecteurs doc DBOW. Notez que cela rend la formation plus longue - par un facteur lié à window
. Donc si vous vous n'avez pas besoin de vecteurs Word, vous pouvez toujours laisser cette option désactivée.)
Dans la méthode de formation "DM" (dm=1
), Les vecteurs de mots sont intrinsèquement formés pendant le processus avec les vecteurs de doc, et sont susceptibles d'affecter également la qualité des vecteurs de doc. Il est théoriquement possible de pré-initialiser les vecteurs Word à partir de données antérieures. Mais je ne connais aucune raison théorique ou expérimentale solide pour être sûr que cela améliorerait les doc-vecteurs.
Une expérience fragmentaire que j'ai menée dans ce sens a suggéré que la formation doc-vecteur a démarré plus rapidement - de meilleures qualités prédictives après les premières passes - mais cet avantage s'est estompé avec plus de passes. Que vous mainteniez les vecteurs Word constants ou que vous les laissiez continuer à s'adapter avec la nouvelle formation est également probablement une considération importante ... mais le meilleur choix peut dépendre de vos objectifs, de votre ensemble de données et de la qualité/pertinence de la préexistante Mot-vecteurs.
(Vous pouvez répéter mon expérience avec la méthode intersect_Word2vec_format()
disponible dans gensim 0.12.0, et essayer différents niveaux de rendre les vecteurs préchargés résistants à la nouvelle formation via les valeurs syn0_lockf
. Mais rappelez-vous qu'il s'agit d'un territoire expérimental: les résultats de base de doc2vec ne reposent pas sur, ou même nécessairement s'améliorent avec, les vecteurs Word réutilisés.)
Eh bien, j'utilise aussi récemment Doc2Vec. Et je pensais utiliser le résultat LDA comme vecteur Word et corriger ces vecteurs Word pour obtenir un vecteur de document. Le résultat n'est cependant pas très intéressant. Peut-être que mon ensemble de données n'est pas si bon. Le code est ci-dessous. Doc2Vec enregistre les vecteurs Word et les vecteurs de document ensemble dans le dictionnaire doc2vecmodel.syn0. Vous pouvez directement modifier les valeurs vectorielles. Le seul problème peut être que vous devez savoir quelle position dans syn0 représente quel mot ou document. Les vecteurs sont stockés dans un ordre aléatoire dans le dictionnaire syn0.
import logging
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
from gensim import corpora, models, similarities
import gensim
from sklearn import svm, metrics
import numpy
#Read in texts into div_texts(for LDA and Doc2Vec)
div_texts = []
f = open("clean_ad_nonad.txt")
lines = f.readlines()
f.close()
for line in lines:
div_texts.append(line.strip().split(" "))
#Set up dictionary and MMcorpus
dictionary = corpora.Dictionary(div_texts)
dictionary.save("ad_nonad_lda_deeplearning.dict")
#dictionary = corpora.Dictionary.load("ad_nonad_lda_deeplearning.dict")
print dictionary.token2id["junk"]
corpus = [dictionary.doc2bow(text) for text in div_texts]
corpora.MmCorpus.serialize("ad_nonad_lda_deeplearning.mm", corpus)
#LDA training
id2token = {}
token2id = dictionary.token2id
for onemap in dictionary.token2id:
id2token[token2id[onemap]] = onemap
#ldamodel = models.LdaModel(corpus, num_topics = 100, passes = 1000, id2Word = id2token)
#ldamodel.save("ldamodel1000pass.lda")
#ldamodel = models.LdaModel(corpus, num_topics = 100, id2Word = id2token)
ldamodel = models.LdaModel.load("ldamodel1000pass.lda")
ldatopics = ldamodel.show_topics(num_topics = 100, num_words = len(dictionary), formatted = False)
print ldatopics[10][1]
print ldatopics[10][1][1]
ldawordindex = {}
for i in range(len(dictionary)):
ldawordindex[ldatopics[0][i][1]] = i
#Doc2Vec initialize
sentences = []
for i in range(len(div_texts)):
string = "SENT_" + str(i)
sentence = models.doc2vec.LabeledSentence(div_texts[i], labels = [string])
sentences.append(sentence)
doc2vecmodel = models.Doc2Vec(sentences, size = 100, window = 5, min_count = 0, dm = 1)
print "Initial Word vector for Word junk:"
print doc2vecmodel["junk"]
#Replace the Word vector with Word vectors from LDA
print len(doc2vecmodel.syn0)
index2wordcollection = doc2vecmodel.index2Word
print index2wordcollection
for i in range(len(doc2vecmodel.syn0)):
if index2wordcollection[i].startswith("SENT_"):
continue
wordindex = ldawordindex[index2wordcollection[i]]
wordvectorfromlda = [ldatopics[j][wordindex][0] for j in range(100)]
doc2vecmodel.syn0[i] = wordvectorfromlda
#print doc2vecmodel.index2Word[26841]
#doc2vecmodel.syn0[0] = [0 for i in range(100)]
print "Changed Word vector for Word junk:"
print doc2vecmodel["junk"]
#Train Doc2Vec
doc2vecmodel.train_words = False
print "Initial doc vector for 1st document"
print doc2vecmodel["SENT_0"]
for i in range(50):
print "Round: " + str(i)
doc2vecmodel.train(sentences)
print "Trained doc vector for 1st document"
print doc2vecmodel["SENT_0"]
#Using SVM to do classification
resultlist = []
for i in range(4143):
string = "SENT_" + str(i)
resultlist.append(doc2vecmodel[string])
svm_x_train = []
for i in range(1000):
svm_x_train.append(resultlist[i])
for i in range(2210,3210):
svm_x_train.append(resultlist[i])
print len(svm_x_train)
svm_x_test = []
for i in range(1000,2210):
svm_x_test.append(resultlist[i])
for i in range(3210,4143):
svm_x_test.append(resultlist[i])
print len(svm_x_test)
svm_y_train = numpy.array([0 for i in range(2000)])
for i in range(1000,2000):
svm_y_train[i] = 1
print svm_y_train
svm_y_test = numpy.array([0 for i in range(2143)])
for i in range(1210,2143):
svm_y_test[i] = 1
print svm_y_test
svc = svm.SVC(kernel='linear')
svc.fit(svm_x_train, svm_y_train)
expected = svm_y_test
predicted = svc.predict(svm_x_test)
print("Classification report for classifier %s:\n%s\n"
% (svc, metrics.classification_report(expected, predicted)))
print("Confusion matrix:\n%s" % metrics.confusion_matrix(expected, predicted))
print doc2vecmodel["junk"]
Cette version fourchue de gensim permet de charger des vecteurs Word pré-formés pour la formation doc2vec. Ici vous avez un exemple sur la façon de l'utiliser. Les vecteurs Word doivent être au format texte de l'outil C-Word2vec: une ligne par vecteur Word où vient d'abord une chaîne représentant le mot puis des valeurs flottantes séparées par des espaces, une pour chaque dimension de l'incorporation.
Ce travail appartient à un papier dans lequel ils prétendent que l'utilisation des incorporations Word pré-formées aide réellement à construire les vecteurs de document. Cependant, j'obtiens presque les mêmes résultats, peu importe que je charge les intégrations pré-entraînées ou non.
Edit: en fait il y a une différence remarquable dans mes expériences. Quand j'ai chargé les intégrations pré-formées, j'ai formé doc2vec pour la moitié des itérations pour obtenir presque les mêmes résultats (une formation plus longue que celle-ci a produit des résultats moins bons dans ma tâche).
Radim vient de publier un tutoriel sur les fonctionnalités doc2vec de gensim (hier, je crois - votre question arrive à point nommé!).
Gensim prend en charge le chargement de vecteurs pré-entraînés à partir de l'implémentation C , comme décrit dans les modèles Gensim. Documentation API Word2vec .