增加 Spark 的 Word2Vec 的 numPartitions 使其速度更快,但准确性较低,因为它单独适合每个分区,从而在合并结果之前减少了每个单词可用的上下文。
它到底是如何合并多个分区的结果的?它只是向量的平均值吗?希望更好地了解这如何影响准确性。
查看源代码,我认为合并发生在这里:
val synAgg = partial.reduceByKey { case (v1, v2) =>
blas.saxpy(vectorSize, 1.0f, v2, 1, v1, 1)
v1
}.collect()
这看起来只是一个向量和(实际上是一个平均值)。部分来自:
val sentences: RDD[Array[Int]] = dataset.mapPartitions { sentenceIter =>
// Each sentence will map to 0 or more Array[Int]
sentenceIter.flatMap { sentence =>
// Sentence of words, some of which map to a word index
val wordIndexes = sentence.flatMap(bcVocabHash.value.get)
// break wordIndexes into trunks of maxSentenceLength when has more
wordIndexes.grouped(maxSentenceLength).map(_.toArray)
}
}
val newSentences = sentences.repartition(numPartitions).cache()
val partial = newSentences.mapPartitionsWithIndex { case (idx, iter) =>
// ... long calculation (skip-gram training, etc.)
}
但我不是Word2Vec/Spark ML/Scala专家,所以希望更有知识的人可以验证。
saxpy
是 BLAS(广泛使用的线性代数库)中的一个 函数,用于计算“标量乘以向量加向量”。在本例中,标量为 1.0,因此该函数只是对结果求和。增量项 (1) 让函数知道内存中的元素之间没有间距,这使其能够更有效地计算结果。在 pyspark
的最新版本中,使用了额外的标准化术语来防止溢出(请参阅此处)。
你是对的,这实际上是向量的平均值。如果您将 Word2Vec 视为神经网络,这类似于执行批量归一化步骤,批量大小是每个数据分区中的行数。由于这是一个非常大的数字,它可能会阻止您达到绝对最佳结果(即,最小化 Word2Vec 损失函数的一组“完美”嵌入),但这可能是也可能不是一个真正的问题,具体取决于您的情况应用程序和数据集。