关于Java:使用Apache Spark 2.0.0和mllib的分布式Word2Vec模型培训

Distributed Word2Vec Model Training using Apache Spark 2.0.0 and mllib

我一直在尝试使用spark和mllib训练word2vec模型,但是我似乎并没有从大型数据集上获得分布式机器学习的性能优势。我的理解是,如果我有w个工作人员,那么,如果我创建一个n个分区的n个分区的RDD,并尝试通过调用RDD作为参数的Word2Vec的fit函数来创建Word2Vec模型,则spark将分布数据统一在这些w工人上训练单独的word2vec模型,并在最后使用某种化简函数从这些w模型中创建单个输出模型。这将减少计算时间,而不是减少1个块,同时将处理w个数据块。权衡取舍的是,根据最终使用的减速器功能,可能会发生一些精度损失。 Spark中的Word2Vec是否实际上以这种方式工作?如果确实是这种情况,我可能需要使用可配置的参数。

编辑

在提出此问题的背后添加原因。在查阅文档后,我在10个工作机上运行了java spark word2vec代码,并为执行程序内存,驱动程序内存和num-executors设置了适当的值,以获取2.5gb的输入文本文件,该文件映射到rdd分区,然后用作mllib word2vec模型的训练数据。培训部分花费了多个小时。工作节点的数量似乎对培训时间没有太大影响。相同的代码可在较小的数据文件(大约10s MB)上成功运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
SparkConf conf = new SparkConf().setAppName("SampleWord2Vec");
conf.set("spark.serializer","org.apache.spark.serializer.KryoSerializer");
conf.registerKryoClasses(new Class[]{String.class, List.class});
JavaSparkContext jsc = new JavaSparkContext(conf);
JavaRDD<List<String>> jrdd = jsc.textFile(inputFile, 3).map(new Function<String, List<String>>(){            
        @Override
        public List<String> call(String s) throws Exception {
            return Arrays.asList(s.split(","));
        }        
});
jrdd.persist(StorageLevel.MEMORY_AND_DISK());
Word2Vec word2Vec = new Word2Vec()
      .setWindowSize(20)
      .setMinCount(20);

Word2VecModel model = word2Vec.fit(jrdd);
jrdd.unpersist(false);
model.save(jsc.sc(), outputfile);
jsc.stop();
jsc.close();


从评论,答案和否决票来看,我想我无法正确提出问题。但是我想知道的答案是肯定的,可以在spark上并行训练您的word2vec模型。此功能的拉取请求已创建很久了:

https://github.com/apache/spark/pull/1719

在Java中,Spark mllib中的Word2Vec对象有一个setter方法(setNumPartitions)。这使您可以在多个执行器上并行训练word2vec模型。
根据上述对拉取请求的评论:

"为使我们的实现更具可伸缩性,我们分别训练每个分区,并在每次迭代后合并每个分区的模型。为使模型更准确,可能需要多次迭代。"

希望这对某人有帮助。


我没有发现您的代码天生就有错误。但是,我强烈建议您考虑使用数据框架API。例如,下面是一些经常出现的图表:

enter image description here

另外,我不知道您是如何在数据框架的元素上"迭代"的(实际上并不是它们的工作原理)。这是Spark在线文档中的示例:

enter image description here

您已经有了大致的想法...但是首先必须将数据并行化为数据框。而是将您的javardd转换为DataFrame是很简单的。

1
DataFrame fileDF = sqlContext.createDataFrame(jrdd, Model.class);

Spark运行有向无环图(DAG)代替MR,但是概念是相同的。在您的数据上运行'fit()确实会跨多个工作程序上的数据运行,然后简化为单个模型。但是,直到您决定将其写下来,该模型本身都会分配在内存中。

但是,作为试用,通过NLTK或Word2Vec的本机C ++二进制文件运行同一文件要花多长时间?

最后一个想法...您是否坚持使用内存和磁盘? Spark具有一个本机.cache(),默认情况下会持久保存到内存中。 Spark的功能是对内存中保存的数据进行机器学习...内存中的大数据。如果您坚持使用磁盘,即使使用kryo,也会在磁盘I / O上造成瓶颈。恕我直言,首先要尝试的是摆脱这种情况并仅保留到内存中。如果性能提高了,那就太好了,但是通过DataFrames依靠Catalyst的强大功能,您将发现性能的跨越式发展。

我们没有讨论的一件事是您的集群。考虑一下诸如每个节点有多少内存,每个节点有多少核心...将群集与其他正在请求资源的应用程序虚拟化(像大多数vHosts一样进行预配置)的虚拟机,将很有帮助。您的集群在云中?共享还是专用?

您是否查看过Spark的UI来分析代码的运行时操作?当模型拟合时,在工作程序上运行top时会看到什么?您可以看到完整的CPU使用率吗?您是否尝试指定--executor-cores以确保充分利用CPU?

我已经多次看到所有工作都是在一个工作节点上的一个核心上完成的。拥有此信息将很有帮助。

在对性能进行故障排除时,有很多地方值得一看,包括Spark配置文件本身!