Merge pull request #460 from srowen/RandomInitialALSVectors
Choose initial user/item vectors uniformly on the unit sphere ...rather than within the unit square to possibly avoid bias in the initial state and improve convergence. The current implementation picks the N vector elements uniformly at random from [0,1). This means they all point into one quadrant of the vector space. As N gets just a little large, the vector tend strongly to point into the "corner", towards (1,1,1...,1). The vectors are not unit vectors either. I suggest choosing the elements as Gaussian ~ N(0,1) and normalizing. This gets you uniform random choices on the unit sphere which is more what's of interest here. It has worked a little better for me in the past. This is pretty minor but wanted to warm up suggesting a few tweaks to ALS. Please excuse my Scala, pretty new to it. Author: Sean Owen <sowen@cloudera.com> == Merge branch commits == commit 492b13a7469e5a4ed7591ee8e56d8bd7570dfab6 Author: Sean Owen <sowen@cloudera.com> Date: Mon Jan 27 08:05:25 2014 +0000 Style: spaces around binary operators commit ce2b5b5a4fefa0356875701f668f01f02ba4d87e Author: Sean Owen <sowen@cloudera.com> Date: Sun Jan 19 22:50:03 2014 +0000 Generate factors with all positive components, per discussion in https://github.com/apache/incubator-spark/pull/460 commit b6f7a8a61643a8209e8bc662e8e81f2d15c710c7 Author: Sean Owen <sowen@cloudera.com> Date: Sat Jan 18 15:54:42 2014 +0000 Choose initial user/item vectors uniformly on the unit sphere rather than within the unit square to possibly avoid bias in the initial state and improve convergence
This commit is contained in:
parent
c40619d487
commit
f67ce3e229
|
@ -18,6 +18,7 @@
|
|||
package org.apache.spark.mllib.recommendation
|
||||
|
||||
import scala.collection.mutable.{ArrayBuffer, BitSet}
|
||||
import scala.math.{abs, sqrt}
|
||||
import scala.util.Random
|
||||
import scala.util.Sorting
|
||||
|
||||
|
@ -301,7 +302,14 @@ class ALS private (var numBlocks: Int, var rank: Int, var iterations: Int, var l
|
|||
* Make a random factor vector with the given random.
|
||||
*/
|
||||
private def randomFactor(rank: Int, rand: Random): Array[Double] = {
|
||||
Array.fill(rank)(rand.nextDouble)
|
||||
// Choose a unit vector uniformly at random from the unit sphere, but from the
|
||||
// "first quadrant" where all elements are nonnegative. This can be done by choosing
|
||||
// elements distributed as Normal(0,1) and taking the absolute value, and then normalizing.
|
||||
// This appears to create factorizations that have a slightly better reconstruction
|
||||
// (<1%) compared picking elements uniformly at random in [0,1].
|
||||
val factor = Array.fill(rank)(abs(rand.nextGaussian()))
|
||||
val norm = sqrt(factor.map(x => x * x).sum)
|
||||
factor.map(x => x / norm)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue