KMeans || для анализа настроений на Spark

Я пытаюсь написать программу анализа настроений на основе 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
      }
    }

Ответ 1

Я запускаю искру на AWS с 3 подчиненными (c3.xlarge), и результат один и тот же - проблема в том, что параллельно KMeans инициализирует algo в N параллельных прогонах, но он по-прежнему чрезвычайно медленный для небольшого количества данных, мое решение является contionue, используя случайную инициализацию. Размер данных приблизительно: 4k кластеров для 21k 100-мерных векторов.

Ответ 2

Инициализация с использованием KMeans.K_MEANS_PARALLEL более сложна, чем random. Однако это не должно иметь большого значения. Я бы рекомендовал исследовать, является ли это параллельным алгоритмом, который занимает много времени (он должен быть фактически более эффективным, чем сам KMeans).

Информацию о профилировании см. в: http://spark.apache.org/docs/latest/monitoring.html

Если это не инициализация, которая занимает время, есть что-то серьезное. Тем не менее, использование случайной инициализации не должно быть хуже для конечного результата (только менее эффективно!).

Фактически, когда вы используете KMeans.K_MEANS_PARALLEL для инициализации, вы должны получить разумные результаты с помощью 0 итераций. Если это не так, могут быть некоторые закономерности в распределении данных, которые отправляют KMeans offtrack. Следовательно, если вы случайно не распределяете свои данные, вы также можете изменить это. Тем не менее, такое воздействие может удивить меня указанием фиксированного числа итераций.