簡體   English   中英

如何將 Gensim doc2vec 與預訓練的詞向量一起使用?

[英]How to use Gensim doc2vec with pre-trained word vectors?

我最近遇到了 doc2vec 添加到 Gensim。 如何在 doc2vec 中使用預先訓練的詞向量(例如在 word2vec 原始網站中找到)?

還是 doc2vec 從用於段落向量訓練的相同句子中獲取詞向量?

謝謝。

請注意,“DBOW”( dm=0 )訓練模式不需要甚至創建詞向量作為訓練的一部分。 它只是學習擅長依次預測每個單詞的文檔向量(很像 word2vec skip-gram 訓練模式)。

(在 gensim 0.12.0 之前,在另一條評論中提到了參數train_words ,一些文檔建議將共同訓練單詞。但是,我不相信這真的有效。從 gensim 0.12.0 開始,有參數dbow_words ,它可以同時使用 DBOW doc-vectors 跳過 gram 訓練單詞。請注意,這使訓練需要更長的時間 - 與window相關的因素。因此,如果您不需要單詞向量,您仍然可以將其關閉。 )

在“DM”訓練方法( dm=1 )中,word-vectors 在這個過程中與 doc-vectors 一起被固有地訓練,並且很可能也會影響 doc-vectors 的質量。 理論上可以從先前的數據中預初始化詞向量。 但我不知道有任何強有力的理論或實驗理由來相信這會改善文檔向量。

我沿着這些路線進行的一個零碎實驗表明 doc-vector 訓練開始得更快——在前幾次傳球后預測質量更好——但這種優勢隨着傳球次數的增加而逐漸消失。 是保持詞向量不變還是讓它們隨着新訓練繼續調整也可能是一個重要的考慮因素……但哪種選擇更好可能取決於您的目標、數據集以及預先存在的質量/相關性詞向量。

(您可以使用 gensim 0.12.0 中可用的intersect_word2vec_format()方法重復我的實驗,並嘗試通過syn0_lockf值嘗試不同級別的預加載向量對新訓練的syn0_lockf 。但請記住,這是實驗領域:基本doc2vec 結果不依賴於,甚至不一定通過重用的詞向量來改進。)

嗯,我最近也在使用 Doc2Vec。 我正在考慮使用 LDA 結果作為詞向量並修復這些詞向量以獲得文檔向量。 然而結果並不是很有趣。 也許只是我的數據集不太好。 代碼如下。 Doc2Vec 將詞向量和文檔向量一起保存在字典 doc2vecmodel.syn0 中。 您可以直接更改矢量值。 唯一的問題可能是您需要找出 syn0 中的哪個位置代表哪個單詞或文檔。 這些向量以隨機順序存儲在字典 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"]

這個 gensim 的分叉版本允許加載預訓練的詞向量來訓練 doc2vec。 這里有一個關於如何使用它的示例。 詞向量必須采用 C-word2vec 工具文本格式:每個詞向量一行,首先是一個表示詞的字符串,然后是空格分隔的浮點值,每個嵌入的維度一個。

這項工作屬於文件中,他們聲稱,使用預訓練字的嵌入實際上有助於構建文檔向量。 但是,無論我是否加載預訓練的嵌入,我都會得到幾乎相同的結果。

編輯:實際上,我的實驗有一個顯着的不同。 當我加載預訓練嵌入時,我在一半的迭代中訓練了 doc2vec 以獲得幾乎相同的結果(訓練時間比我的任務產生的結果更差)。

拉迪姆剛剛發布了一個教程上gensim的doc2vec功能(昨天,我相信-你的問題是及時的!)。

Gensim 支持從C 實現加載預訓練向量,如gensim models.word2vec API 文檔中所述

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM