4

テキスト ドキュメント (TF-IDF ベクトル) の (大規模な) コレクションから MLLib で KMeans を実行しようとしています。ドキュメントは Lucene English アナライザーを介して送信され、HashingTF.transform() 関数からスパース ベクトルが作成されます。(coalesce 関数を使用して) 使用している並列処理の程度に関係なく、KMeans.train は常に以下の OutOfMemory 例外を返します。この問題に取り組む方法について何か考えはありますか?

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at scala.reflect.ManifestFactory$$anon$12.newArray(Manifest.scala:138)
at scala.reflect.ManifestFactory$$anon$12.newArray(Manifest.scala:136)
at breeze.linalg.Vector$class.toArray(Vector.scala:80)
at breeze.linalg.SparseVector.toArray(SparseVector.scala:48)
at breeze.linalg.Vector$class.toDenseVector(Vector.scala:75)
at breeze.linalg.SparseVector.toDenseVector(SparseVector.scala:48)
at breeze.linalg.Vector$class.toDenseVector$mcD$sp(Vector.scala:74)
at breeze.linalg.SparseVector.toDenseVector$mcD$sp(SparseVector.scala:48)
at org.apache.spark.mllib.clustering.BreezeVectorWithNorm.toDense(KMeans.scala:422)
at org.apache.spark.mllib.clustering.KMeans$$anonfun$initKMeansParallel$1.apply(KMeans.scala:285)
at org.apache.spark.mllib.clustering.KMeans$$anonfun$initKMeansParallel$1.apply(KMeans.scala:284)
at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:33)
at scala.collection.mutable.ArrayOps$ofRef.foreach(ArrayOps.scala:108)
at org.apache.spark.mllib.clustering.KMeans.initKMeansParallel(KMeans.scala:284)
at org.apache.spark.mllib.clustering.KMeans.runBreeze(KMeans.scala:143)
at org.apache.spark.mllib.clustering.KMeans.run(KMeans.scala:126)
at org.apache.spark.mllib.clustering.KMeans$.train(KMeans.scala:338)
at org.apache.spark.mllib.clustering.KMeans$.train(KMeans.scala:348)
4

1 に答える 1

4

new HashingTF().transform(v)いくつかの調査の後、この問題はメソッドに関連していることが判明しました。ハッシュ トリックを使用してスパース ベクトルを作成することは非常に役立ちますが (特にフィーチャの数が不明な場合)、ベクトルはスパースに保つ必要があります。HashingTF ベクトルのデフォルト サイズは 2^20 です。64 ビットの倍精度を指定すると、適用できる次元削減に関係なく、理論的には各ベクトルを高密度ベクトルに変換すると 8MB が必要になります。

悲しいことに、KMeans はtoDenseメソッドを (少なくともクラスター センターに対して) 使用するため、OutOfMemory エラーが発生します (k = 1000 の場合を想像してください)。

  private def initRandom(data: RDD[BreezeVectorWithNorm]) : Array[Array[BreezeVectorWithNorm]] = {
    val sample = data.takeSample(true, runs * k, new XORShiftRandom().nextInt()).toSeq
    Array.tabulate(runs)(r => sample.slice(r * k, (r + 1) * k).map { v =>
      new BreezeVectorWithNorm(v.vector.toDenseVector, v.norm)
    }.toArray)
  }
于 2014-10-21T19:38:49.143 に答える