Fix initializing clusters with random randoms
During the quantization process, an instance of a Quantizer is created. When quantization is run, the Quantizer may need to create starting points that are random. To keep results stable, meaning multiple runs of a quantizer output the same results, those starting points must be created using a Random with the same starting seed. Without specifying a starting seed, or if an instance of Random is reused across runs, the random starting points will vary across quantizer runs. With this patch, the Random used to create starting points is no longer used across multiple runs (i.e. it isn't a static variable anymore). Additionally, a starting seed is specified. Test: Add log dumps after the quantization process. Verify that results from Kmeans remain consistent as long as the input is consistent. Bug: 182333325 Change-Id: Ia0f984349b7885ae1b44536aaa1b286a28e50587
This commit is contained in:
@@ -22,20 +22,19 @@ import java.util.Random;
|
||||
* Represents a centroid in Kmeans algorithms.
|
||||
*/
|
||||
public class Mean {
|
||||
private static final Random RANDOM = new Random(0);
|
||||
|
||||
public float[] center;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param upperBound maximum value of a dimension in the space Kmeans is optimizing in
|
||||
* @param random used to generate a random center
|
||||
*/
|
||||
Mean(int upperBound) {
|
||||
Mean(int upperBound, Random random) {
|
||||
center =
|
||||
new float[]{
|
||||
RANDOM.nextInt(upperBound + 1), RANDOM.nextInt(upperBound + 1),
|
||||
RANDOM.nextInt(upperBound + 1)
|
||||
random.nextInt(upperBound + 1), random.nextInt(upperBound + 1),
|
||||
random.nextInt(upperBound + 1)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
@@ -57,9 +58,12 @@ public class WSMeansQuantizer implements Quantizer {
|
||||
}
|
||||
|
||||
if (maxColors > means.length) {
|
||||
// Always initialize Random with the same seed. Ensures the results of quantization
|
||||
// are consistent, even when random centroids are required.
|
||||
Random random = new Random(0x42688);
|
||||
int randomMeansToCreate = maxColors - means.length;
|
||||
for (int i = 0; i < randomMeansToCreate; i++) {
|
||||
mMeans[means.length + i] = new Mean(100);
|
||||
mMeans[means.length + i] = new Mean(100, random);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,8 +109,12 @@ public class WSMeansQuantizer implements Quantizer {
|
||||
/** Create random starting centroids for K-means. */
|
||||
public static float[][] randomMeans(int maxColors, int upperBound) {
|
||||
float[][] means = new float[maxColors][];
|
||||
|
||||
// Always initialize Random with the same seed. Ensures the results of quantization
|
||||
// are consistent, even when random centroids are required.
|
||||
Random random = new Random(0x42688);
|
||||
for (int i = 0; i < maxColors; i++) {
|
||||
means[i] = new Mean(upperBound).center;
|
||||
means[i] = new Mean(upperBound, random).center;
|
||||
}
|
||||
return means;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user