Doc2Vec 和 PySpark:基于 DeepDist 的 Gensim Doc2vec
Doc2Vec and PySpark: Gensim Doc2vec over DeepDist
我正在查看 DeepDist
(link) 模块并考虑将其与 Gensim
的 Doc2Vec
API 结合起来训练段落向量在 PySpark
上。 link 实际上提供了以下干净示例,说明如何为 Gensim
的 Word2Vec
模型执行此操作:
from deepdist import DeepDist
from gensim.models.word2vec import Word2Vec
from pyspark import SparkContext
sc = SparkContext()
corpus = sc.textFile('enwiki').map(lambda s: s.split())
def gradient(model, sentences): # executes on workers
syn0, syn1 = model.syn0.copy(), model.syn1.copy() # previous weights
model.train(sentences)
return {'syn0': model.syn0 - syn0, 'syn1': model.syn1 - syn1}
def descent(model, update): # executes on master
model.syn0 += update['syn0']
model.syn1 += update['syn1']
with DeepDist(Word2Vec(corpus.collect()) as dd:
dd.train(corpus, gradient, descent)
print dd.model.most_similar(positive=['woman', 'king'], negative=['man'])
据我了解,DeepDist
是将梯度下降的工作分批分配给worker,在master重新组合更新。如果我用 Doc2Vec
替换 Word2Vec
,应该有正在用词向量训练的文档向量。
所以我查看了 gensim.models.doc2vec
(link) 的源代码。 Doc2Vec
模型实例中有以下字段:
model.syn0
model.syn0_lockf
model.docvecs.doctag_syn0
model.docvecs.doctag_syn0_lockf
与 gensim.models.word2vec
(link) 的源代码相比,Doc2Vec
模型中缺少以下字段:
model.syn1
model.syn1neg
我想我不会触及 lockf
向量,因为它们似乎是在训练完成后新数据点进来时使用的。因此我的代码应该类似于
from deepdist import DeepDist
from gensim.models.doc2vec import Doc2Vec, LabeledSentence
from pyspark import SparkContext
sc = SparkContext()
# assume my dataset is in format 10-char-id followed by doc content
# 1 line per doc
corpus = sc.textFile('data_set').map(
lambda s: LabeledSentence(words=s[10:].split(),labels=s[:10])
)
def gradient(model, sentence): # executes on workers
syn0, doctag_syn0 = model.syn0.copy(), model.docvecs.doctag_syn0.copy() # previous weights
model.train(sentence)
return {'syn0': model.syn0 - syn0, 'doctag_syn0': model.docvecs.doctag_syn0 - doctag_syn0}
def descent(model, update): # executes on master
model.syn0 += update['syn0']
model.docvecs.doctag_syn0 += update['doctag_syn0']
with DeepDist(Doc2Vec(corpus.collect()) as dd:
dd.train(corpus, gradient, descent)
print dd.model.most_similar(positive=['woman', 'king'], negative=['man'])
我是不是漏掉了什么重要的东西?例如:
- 我应该关心
model.syn1
吗?它们到底是什么意思?
- 我说的对吗
model.*_lockf
是训练后的锁定矩阵?
- 我可以使用
lambda s: LabeledSentence(words=s[10:].split(),labels=s[:10]
来解析我的数据集吗,假设我将每个文档放在一行中,并以 0 填充的 10 位数字 ID 作为前缀?
非常感谢任何suggestion/contribution。我将写一篇博客 post 来总结结果,在这里提到贡献者,可能会帮助其他人在扩展的分布式系统上训练 Doc2Vec 模型,而无需花费太多开发时间来尝试解决我现在正在解决的问题。
谢谢
2018 年 6 月 13 日更新
很抱歉,我没有实现它。但是现在有更好的选择,而且 DeepDist
已经有一段时间没有维护了。请阅读下面的评论。
如果您现在坚持要尝试我的想法,请注意,您要自行承担风险。另外,如果有人知道 DeepDist
仍然有效,请在评论中反馈。它会帮助其他读者。
为避免此问题显示为未解决,以下是提问者解决问题的方式:
I did not get to implement this, until it's too late that I didn't think it would work. DeepDist uses Flask app in backend to interact with Spark web interface. Since it wasn't maintained anymore, Spark's update very likely broke it already. If you are looking for Doc2Vec training in Spark, just go for Deeplearning4J(deeplearning4j.org/doc2vec#)
我正在查看 DeepDist
(link) 模块并考虑将其与 Gensim
的 Doc2Vec
API 结合起来训练段落向量在 PySpark
上。 link 实际上提供了以下干净示例,说明如何为 Gensim
的 Word2Vec
模型执行此操作:
from deepdist import DeepDist
from gensim.models.word2vec import Word2Vec
from pyspark import SparkContext
sc = SparkContext()
corpus = sc.textFile('enwiki').map(lambda s: s.split())
def gradient(model, sentences): # executes on workers
syn0, syn1 = model.syn0.copy(), model.syn1.copy() # previous weights
model.train(sentences)
return {'syn0': model.syn0 - syn0, 'syn1': model.syn1 - syn1}
def descent(model, update): # executes on master
model.syn0 += update['syn0']
model.syn1 += update['syn1']
with DeepDist(Word2Vec(corpus.collect()) as dd:
dd.train(corpus, gradient, descent)
print dd.model.most_similar(positive=['woman', 'king'], negative=['man'])
据我了解,DeepDist
是将梯度下降的工作分批分配给worker,在master重新组合更新。如果我用 Doc2Vec
替换 Word2Vec
,应该有正在用词向量训练的文档向量。
所以我查看了 gensim.models.doc2vec
(link) 的源代码。 Doc2Vec
模型实例中有以下字段:
model.syn0
model.syn0_lockf
model.docvecs.doctag_syn0
model.docvecs.doctag_syn0_lockf
与 gensim.models.word2vec
(link) 的源代码相比,Doc2Vec
模型中缺少以下字段:
model.syn1
model.syn1neg
我想我不会触及 lockf
向量,因为它们似乎是在训练完成后新数据点进来时使用的。因此我的代码应该类似于
from deepdist import DeepDist
from gensim.models.doc2vec import Doc2Vec, LabeledSentence
from pyspark import SparkContext
sc = SparkContext()
# assume my dataset is in format 10-char-id followed by doc content
# 1 line per doc
corpus = sc.textFile('data_set').map(
lambda s: LabeledSentence(words=s[10:].split(),labels=s[:10])
)
def gradient(model, sentence): # executes on workers
syn0, doctag_syn0 = model.syn0.copy(), model.docvecs.doctag_syn0.copy() # previous weights
model.train(sentence)
return {'syn0': model.syn0 - syn0, 'doctag_syn0': model.docvecs.doctag_syn0 - doctag_syn0}
def descent(model, update): # executes on master
model.syn0 += update['syn0']
model.docvecs.doctag_syn0 += update['doctag_syn0']
with DeepDist(Doc2Vec(corpus.collect()) as dd:
dd.train(corpus, gradient, descent)
print dd.model.most_similar(positive=['woman', 'king'], negative=['man'])
我是不是漏掉了什么重要的东西?例如:
- 我应该关心
model.syn1
吗?它们到底是什么意思? - 我说的对吗
model.*_lockf
是训练后的锁定矩阵? - 我可以使用
lambda s: LabeledSentence(words=s[10:].split(),labels=s[:10]
来解析我的数据集吗,假设我将每个文档放在一行中,并以 0 填充的 10 位数字 ID 作为前缀?
非常感谢任何suggestion/contribution。我将写一篇博客 post 来总结结果,在这里提到贡献者,可能会帮助其他人在扩展的分布式系统上训练 Doc2Vec 模型,而无需花费太多开发时间来尝试解决我现在正在解决的问题。
谢谢
2018 年 6 月 13 日更新
很抱歉,我没有实现它。但是现在有更好的选择,而且 DeepDist
已经有一段时间没有维护了。请阅读下面的评论。
如果您现在坚持要尝试我的想法,请注意,您要自行承担风险。另外,如果有人知道 DeepDist
仍然有效,请在评论中反馈。它会帮助其他读者。
为避免此问题显示为未解决,以下是提问者解决问题的方式:
I did not get to implement this, until it's too late that I didn't think it would work. DeepDist uses Flask app in backend to interact with Spark web interface. Since it wasn't maintained anymore, Spark's update very likely broke it already. If you are looking for Doc2Vec training in Spark, just go for Deeplearning4J(deeplearning4j.org/doc2vec#)