如何使用Gensim doc2vec与预先训练的单词向量?

Ste*_*ios 36 python nlp gensim word2vec

我最近遇到了Gensim的doc2vec.如何使用doc2vec预训练的单词向量(例如在word2vec原始网站中找到)?

或者是doc2vec从用于段落矢量训练的相同句子中获取单词向量?

谢谢.

goj*_*omo 23

请注意,"DBOW"(dm=0)训练模式不需要甚至创建单词向量作为训练的一部分.它只是学习擅长依次预测每个单词的文档向量(很像word2vec skip-gram训练模式).

(在gensim 0.12.0之前,有train_words另一个评论中提到的参数,一些文档建议将共同训练单词.但是,我不相信这实际上有用.从gensim 0.12.0开始,有参数dbow_words,它可以与DBOW doc-vectors同时跳过-ke训练单词.请注意,这会使训练需要更长时间 - 与之相关的因素window.因此,如果你不需要单词向量,你可能仍然会将其关闭.)

在"DM"训练方法(dm=1)中,单词向量在过程中与doc向量一起被固有地训练,并且可能也影响doc向量的质量.理论上可以从先前数据预初始化字矢量.但我不知道有任何强烈的理论或实验理由相信这会改善doc-vectors.

我沿着这些线进行的一个零碎实验表明,文档向量训练开始得更快 - 在前几次传球之后有更好的预测性 - 但这种优势随着传球次数的增加而逐渐消失.无论是保持单词向量不变还是让它们继续通过新培训进行调整也可能是一个重要的考虑因素......但哪种选择更好可能取决于您的目标,数据集以及预先存在的质量/相关性文字载体.

(您可以intersect_word2vec_format()使用gensim 0.12.0中提供的方法重复我的实验,并通过syn0_lockf值尝试不同级别的预加载向量抵抗新训练.但请记住这是实验性领域:基本的doc2vec结果不是' t依赖于,甚至必须改进重用的单词向量.)

  • 在训练/推理过程中,原始语料库中没有的单词(或者在其他词汇修剪中不存在的单词,例如"min_count")将被忽略 - 因此将它们传递给`infer_vector()`没有任何效果.(如果你传递一个包含所有未知单词的文本,就像传递一个空列表一样.)没有支持的方法用其他单词向量预初始化`Doc2Vec`; 甚至我在上面3年的回答中提到的实验性`intersect_word2vec_format()`方法:(1)在最近的版本中已经破坏了`Doc2Vec`; (2)只在你提供的任何初始化语料库中留下带有单词的词汇表. (4认同)

小智 12

好吧,我最近也在使用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"]
Run Code Online (Sandbox Code Playgroud)


Álv*_*rco 10

这个分叉版本的gensim允许加载预训练的单词向量来训练doc2vec.这里有一个如何使用它的例子.单词向量必须采用C-word2vec工具文本格式:每个单词向量一行,其中第一个是表示单词的字符串,然后是空格分隔的浮点值,每个维度对应一个嵌入.

这项工作属于一篇论文,他们声称使用预先训练的文字嵌入实际上有助于构建文档向量.然而,无论我是否加载预先训练好的嵌入,我都得到几乎相同的结果.

编辑:实际上我的实验有一个显着的不同.当我加载预训练的嵌入时,我训练了doc2vec进行了一半的迭代以获得几乎相同的结果(训练时间比我的任务产生更差的结果).


Aar*_*onD 2

Radim 刚刚发布了有关 gensim doc2vec 功能的教程(昨天,我相信 - 你的问题很及时!)。

Gensim 支持从C 实现加载预先训练的向量,如gensim models.word2vec API 文档中所述。