Created
April 15, 2013 14:56
-
-
Save ahmetaa/5388710 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
library gmm; | |
import 'dart:math'; | |
class DiagonalGaussian { | |
List<double> means; | |
List<double> variances; | |
List<double> negativeHalfPrecisions; | |
double logPrecomputedDistance; | |
DiagonalGaussian(this.means, this.variances) { | |
// instead of using [-0.5 * 1/var[d]] during likelihood calculation we pre-compute the values. | |
// This saves 1 mul 1 div operation. | |
negativeHalfPrecisions = new List<double>(variances.length); | |
for (int i = 0; i < negativeHalfPrecisions.length; i++) { | |
negativeHalfPrecisions[i] = -0.5 / variances[i]; | |
} | |
// calculate the precomputed distance. | |
// -0.5*SUM[d=1..D] ( log(2*PI) + log(var[d]) ) = -0.5*log(2*PI)*D -0.5 SUM[d=1..D](log(var[d])) | |
double val = -0.5 * log(2 * PI) * variances.length; | |
for (double variance in variances) { | |
val -= (0.5 * log(variance)); | |
} | |
logPrecomputedDistance = val; | |
} | |
/// Calculates linear likelihood of a given vector. | |
double logLikelihood(List<double> data) { | |
double res = 0.0; | |
for (int i = 0; i < means.length; i++) { | |
final double dif = data[i] - means[i]; | |
res += ((dif * dif) * negativeHalfPrecisions[i]); | |
} | |
return logPrecomputedDistance + res; | |
} | |
/// Calculates linear likelihood of a given vector. | |
double likelihood(List<double> data) { | |
double result = 1.0; | |
for (int i = 0; i < means.length; i++) { | |
double meanDif = data[i] - means[i]; | |
result *= (1 / sqrt(2 * PI * variances[i])) * | |
exp(-0.5 * meanDif * meanDif / variances[i]); | |
} | |
return result; | |
} | |
int get dimension => means.length; | |
} | |
class Gmm { | |
List<double> mixtureWeights; | |
List<DiagonalGaussian> gaussians; | |
Gmm(this.mixtureWeights, this.gaussians); | |
double likelihood(List<double> data) { | |
double sum = 0.0; | |
for (int i = 0; i < gaussians.length; ++i) { | |
sum += mixtureWeights[i]*gaussians[i].likelihood(data); | |
} | |
return sum; | |
} | |
} | |
Random random = new Random(0xcafebabe); | |
double _random() { | |
return random.nextInt(10) / 10 + 0.1; | |
} | |
class GaussData { | |
List<double> means; | |
List<double> variances; | |
int dimension; | |
double weight; | |
GaussData(this.means, this.variances){ | |
this.dimension = means.length; | |
} | |
GaussData.random(this.dimension) { | |
means = new List(dimension); | |
variances = new List(dimension); | |
for(int i = 0 ; i<dimension; i++){ | |
means[i]=_random(); | |
variances[i] = _random(); | |
} | |
weight = _random(); | |
} | |
} | |
Gmm getGmm(List<GaussData> gd) { | |
var gaussList = new List(); | |
var weightList = new List(); | |
for(int a = 0; a<gd.length; a++) { | |
gaussList.add(new DiagonalGaussian(gd[a].means, gd[a].variances)); | |
weightList.add(gd[a].weight); | |
} | |
return new Gmm(weightList, gaussList); | |
} | |
class InputData { | |
List<List<double>> data; | |
int size; | |
int dimension; | |
InputData.random(this.size, this.dimension){ | |
data = new List<List<double>>(size); | |
for (int i = 0; i < data.length; i++) { | |
data[i] = new List<double>(dimension); | |
for (int j = 0; j < dimension; j++) { | |
data[i][j] = _random(); | |
} | |
} | |
} | |
} | |
void calculate(DiagonalGaussian gaussian, List data) { | |
Stopwatch sw = new Stopwatch()..start(); | |
double tot = 0.0; | |
for (int i = 0; i<data.length; ++i) { | |
tot= tot+ gaussian.likelihood(data[i]); | |
} | |
print("log-likelihood=$tot"); | |
} | |
int perfList(GaussData gauss, InputData input) { | |
var d = new DiagonalGaussian(gauss.means, gauss.variances); | |
Stopwatch sw = new Stopwatch()..start(); | |
double tot = 0.0; | |
for (int i = 0; i<input.size; ++i) { | |
tot= tot+ d.likelihood(input.data[i]); | |
} | |
sw.stop(); | |
print("log-likelihood=$tot"); | |
print("List Elapsed: ${sw.elapsedMilliseconds}"); | |
return sw.elapsedMilliseconds; | |
} | |
main() { | |
print("Generating test data"); | |
int gmmCount = 1000; | |
int gaussPerGmm = 8; | |
int dimension = 40; | |
int inputAmount = 1000; | |
int iterationCount = 7; | |
List<Gmm> gmms = new List(gmmCount); | |
for(int i = 0; i<gmmCount;i++) { | |
List<GaussData> gaussDataList = new List(gaussPerGmm); | |
for(int j = 0; j<gaussPerGmm;j++) { | |
gaussDataList[j]= new GaussData.random(40); | |
} | |
gmms[i]=getGmm(gaussDataList); | |
} | |
InputData dataLarge = new InputData.random(inputAmount,40); | |
List<int> times = new List(iterationCount); | |
print("calculating.."); | |
for(int it = 0; it<iterationCount; it++) { | |
Stopwatch sw = new Stopwatch()..start(); | |
double total = 0.0; | |
for(int i = 0; i<inputAmount;i++) { | |
for(int j = 0; j<gmmCount;j++) { | |
total+= gmms[j].likelihood(dataLarge.data[i]); | |
} | |
} | |
sw.stop(); | |
times[it] = sw.elapsedMilliseconds; | |
print("List Elapsed: ${sw.elapsedMilliseconds}"); | |
} | |
times.sort(); | |
double tot = 0.0; | |
for(int it = 0; it<iterationCount; it++) { | |
if(it!=0 && it!=iterationCount-1) | |
tot = tot + times[it]; | |
} | |
print("mean = ${tot/(iterationCount-2).toDouble()}"); | |
print("Done."); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment