Я пытаюсь написать программу анализа настроений на основе Spark. Для этого я использую кластеры word2vec и KMeans. Из word2Vec у меня есть коллекция 20k word/vectors в 100-мерном пространстве, и теперь я пытаюсь кластеризовать это пространство векторов. Когда я запускаю KMeans с параллельной реализацией по умолчанию, алгоритм работал 3 часа! Но со случайной стратегией инициализации это было похоже на 8 минут. Что я делаю не так? У меня есть Mac-книга pro machine с процессором 4 ядер и 16 ГБ оперативной памяти.
K ~ = 4000 maxInteration было 20
var vectors: Iterable[org.apache.spark.mllib.linalg.Vector] =
model.getVectors.map(entry => new VectorWithLabel(entry._1, entry._2.map(_.toDouble)))
val data = sc.parallelize(vectors.toIndexedSeq).persist(StorageLevel.MEMORY_ONLY_2)
log.info("Clustering data size {}",data.count())
log.info("==================Train process started==================");
val clusterSize = modelSize/5
val kmeans = new KMeans()
kmeans.setInitializationMode(KMeans.K_MEANS_PARALLEL)
kmeans.setK(clusterSize)
kmeans.setRuns(1)
kmeans.setMaxIterations(50)
kmeans.setEpsilon(1e-4)
time = System.currentTimeMillis()
val clusterModel: KMeansModel = kmeans.run(data)
И инициализация искрового контекста находится здесь:
val conf = new SparkConf()
.setAppName("SparkPreProcessor")
.setMaster("local[4]")
.set("spark.default.parallelism", "8")
.set("spark.executor.memory", "1g")
val sc = SparkContext.getOrCreate(conf)
Также несколько обновлений о запуске этой программы. Я запускаю его внутри Intelij IDEA. У меня нет реального Spark-кластера. Но я думал, что вашей личной машиной может быть Spark cluster
Я видел, что программа зависает внутри этого цикла от Spark-кода LocalKMeans.scala:
// Initialize centers by sampling using the k-means++ procedure.
centers(0) = pickWeighted(rand, points, weights).toDense
for (i <- 1 until k) {
// Pick the next center with a probability proportional to cost under current centers
val curCenters = centers.view.take(i)
val sum = points.view.zip(weights).map { case (p, w) =>
w * KMeans.pointCost(curCenters, p)
}.sum
val r = rand.nextDouble() * sum
var cumulativeScore = 0.0
var j = 0
while (j < points.length && cumulativeScore < r) {
cumulativeScore += weights(j) * KMeans.pointCost(curCenters, points(j))
j += 1
}
if (j == 0) {
logWarning("kMeansPlusPlus initialization ran out of distinct points for centers." +
s" Using duplicate point for center k = $i.")
centers(i) = points(0).toDense
} else {
centers(i) = points(j - 1).toDense
}
}