web-dev-qa-db-ja.com

事前学習済みのWordベクトルでGensim doc2vecを使用する方法は?

最近、Gensimにdoc2vecが追加されたことに出会いました。 doc2vecで事前にトレーニングされたWordベクトル(Word2vecの元のWebサイトなど)を使用するにはどうすればよいですか?

または、doc2vecは、段落ベクトルトレーニングに使用するのと同じ文からWordベクトルを取得していますか?

ありがとう。

34
Stergios

「DBOW」(_dm=0_)トレーニングモードでは、トレーニングの一部としてWordベクトルを必要としない、または作成することさえできないことに注意してください。各Wordを順番に予測するのが得意なドキュメントベクトルを学習するだけです(Word2vecスキップグラムトレーニングモードによく似ています)。

(gensim 0.12.0より前には、別のコメントで言及されたパラメーター_train_words_がありましたが、いくつかのドキュメントは単語を共同訓練することを提案しましたが、これが実際に機能するとは思われません。パラメータ_dbow_words_があり、これはDBOW doc-vectorsと同時にスキップグラムトレインワードに機能します。これにより、windowに関連する要因により、トレーニングに時間がかかります。 Wordのベクターが必要な場合でも、これはそのままにしておくことができます。)

"DM"トレーニングメソッド(_dm=1_)では、プロセス中にdoc-vectorとともにWord-vectorが本質的にトレーニングされ、doc-vectorの品質にも影響を与える可能性があります。理論的には、以前のデータからWordベクトルを事前に初期化することができます。しかし、これがdoc-vectorを改善すると確信する強力な理論的または実験的理由は知りません。

これらの線に沿って実行した断片的な実験は、doc-vectorトレーニングがより早い開始に着手したことを示唆しました。 Wordのベクトルを一定に保つか、新しいトレーニングで調整し続けるかも重要な考慮事項です...しかし、どちらを選択するのが良いかは、目標、データセット、既存の品質/関連性によって異なります単語ベクトル。

(gensim 0.12.0で利用可能なintersect_Word2vec_format()メソッドを使用して実験を繰り返し、プリロードされたベクトルを_syn0_lockf_値を介して新しいトレーニングに耐性にするさまざまなレベルを試すことができます。これは実験的な領域であることを忘れないでください。基本的なdoc2vecの結果は、再利用されたWordベクトルに依存せず、必ずしも改善されません。)

23
gojomo

さて、私も最近Doc2Vecを使用しています。また、LDAの結果をWordベクトルとして使用し、それらのWordベクトルを修正してドキュメントベクトルを取得することを考えていました。結果はあまり興味深いものではありません。たぶんそれは私のデータセットがそれほど良くないからだ。コードは次のとおりです。 Doc2Vecは、Wordベクターとドキュメントベクターを辞書doc2vecmodel.syn0に一緒に保存します。ベクトル値を直接変更できます。唯一の問題は、syn0のどの位置がどのWordまたはドキュメントを表すかを調べる必要があることです。ベクトルは、辞書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"]
12
STEVE Guo

gensimのこの分岐バージョン は、doc2vecのトレーニング用に事前トレーニング済みのWordベクトルをロードできるようにします。 ここ 使用方法の例があります。 Wordベクトルは、C-Word2vecツールのテキスト形式である必要があります。Wordベクトルごとに1行で、最初にWordを表す文字列、次にスペースで区切られたfloat値が埋め込まれます。

この作業は paper に属し、事前に訓練されたWord埋め込みを使用すると実際にドキュメントベクトルの構築に役立つと主張しています。しかし、事前に訓練された埋め込みをロードしてもしなくてもalmostと同じ結果になります。

編集:実際、私の実験には1つの顕著な違いがあります。事前トレーニング済みの埋め込みをロードしたときに、doc2vecを半分の反復でトレーニングしてalmostと同じ結果を得ました(それよりも長くトレーニングすると、タスクが悪化しました)。

10
Álvaro Marco

Radimはgensimのdoc2vec機能について tutorial を投稿しました(昨日、あなたの質問はタイムリーです!)。

Gensimは、 gensim models.Word2vec APIドキュメント で説明されているように、 C実装 から事前に訓練されたベクトルの読み込みをサポートしています。

2
AaronD