// Copyright (C) 1998-1999 Jean-Marc Valin
#include "gmm.h"
#include <typeinfo>
#include <vector>
#include "vec.h"
#ifdef HAVE_VALUES_H
#include <values.h>
#endif
#ifdef HAVE_FLOAT_H
#include <float.h>
#endif
using namespace std;
namespace FD {
DECLARE_TYPE(GMM)
//@implements GMM
//@require DGMM
void GMM::init(vector<float *> frames)
{
for (unsigned int i=0;i<frames.size();i++)
{
float * fr = frames[i];
int gaus = rand()%nb_gaussians;
#ifdef DEBUG
cerr << "going to: " << gaus << endl;
#endif
accum_to_gaussian(gaus,fr);
}
to_real();
}
void GMM::reset_to_accum_mode()
{
nb_frames_aligned=0;
for(int i=0;i<nb_gaussians;i++)
{
gaussians[i]->reset_to_accum_mode();
apriori[i]=0;
}
mode = accum;
}
void GMM::kmeans2(vector<float *> frames, GMM *gmm)
{
vector<Score> scores;
scores = gmm->minDistance(frames);
//scores = gmm->score(frames);
reset_to_accum_mode();
unsigned int i;
for (i=0;i<frames.size();i++)
{
#ifdef DEBUG
cerr << "going to: " << scores[i].gaussian_id << " score: " << scores[i].score << endl;
#endif
accum_to_gaussian(scores[i].gaussian_id,(frames[i]));
}
for (i=0;i<nb_gaussians;i++)
if (gaussians[i]->get_accum_count()==0)
{
//cerr << "accum zero\n";
accum_to_gaussian(i, (frames[rand()%frames.size()]));
}
to_real();
}
void GMM::adaptMAP(vector<float *> frames, GMM *gmm)
{
/*dimensions = gmm->dimensions;
apriori = gmm->apriori; //(vector<float>(nb_gauss,0.0))
nb_gaussians = gmm->nb_gaussians;
mode = real;
nb_frames_aligned=0;
using_gaussianIDs = false;
//for (int i=0;i<nb_gaussians;i++)
// gaussians.push_back(RCPtr<Gaussian> (new Gaussian(dimensions, NewDiagonalCovariance)));
*/
vector<Score> scores;
//scores = gmm->minDistance(frames);
scores = gmm->score(frames);
//reset_to_accum_mode();
for (int i=0;i<nb_gaussians;i++)
{
int adaptCount=0;
vector<float> adaptMean(dimensions, 0);
for (int j=0;j<frames.size();j++)
{
if (scores[j].gaussian_id == i)
{
for (int k=0;k<dimensions;k++)
adaptMean[k] += frames[j][k];
adaptCount++;
}
}
if (adaptCount)
{
for (int j=0;j<dimensions;j++)
adaptMean[j] /= adaptCount;
} else {
cerr << "no data for gaussian " << i << endl;
}
//FIXME: This is not a correct MAP implementation
//float weight = float(adaptCount)/30.0;
#if 0
float weight = 1 - exp(float(-adaptCount)/20);
if (weight > 1)
weight = 1;
#else
float weight = float(adaptCount)/(float(adaptCount)+15);
#endif
//weight=0;
Vector<double> &mean = *gaussians[i]->mean;
for (int j=0;j<mean.size();j++)
mean[j] = weight*adaptMean[j] + (1-weight)*mean[j];
//gaussians[i+old_size]= RCPtr<Gaussian> (new Gaussian(*(gaussians[i])));
//gaussians[i].
//perform adaptation
}
}
void GMM::kmeans1(vector<float *> frames, int nb_iterations)
{
for (int i=0;i<nb_iterations;i++)
kmeans2(frames,this);
}
void GMM::split1()
{
int max_gauss=0, max_accum=gaussians[0]->get_accum_count();
gaussians.resize(nb_gaussians+1);
apriori.resize(nb_gaussians+1);
for (int i=1;i<nb_gaussians;i++)
{
int accum=gaussians[i]->get_accum_count();
if (accum>max_accum)
{
max_gauss=i;
max_accum=accum;
}
}
//cout << "spliting " << max_gauss << endl;
gaussians[nb_gaussians]= RCPtr<Gaussian> (new Gaussian(*(gaussians[max_gauss])));
Vector <double> &mean = gaussians[nb_gaussians]->getMean();
for (unsigned int j=0;j<mean.size();j++)
mean[j]+=.00001*(rand()%100-49.5);
++nb_gaussians;
}
void GMM::binary_split()
{
int old_size=nb_gaussians;
nb_gaussians *= 2;
gaussians.resize(nb_gaussians);
apriori.resize(nb_gaussians);
for (int i=0;i<old_size;i++)
{
gaussians[i+old_size]= RCPtr<Gaussian> (new Gaussian(*(gaussians[i])));
Vector <double> &mean = gaussians[i+old_size]->getMean();
for (unsigned int j=0;j<mean.size();j++)
{
mean[j]*=1+.0002*(rand()%100-49.5);
//mean[j]+=.0001;
}
}
}
void GMM::to_real()
{
if (mode==real) return;
for (int i=0;i<nb_gaussians;i++)
{
apriori[i]=log(apriori[i]/nb_frames_aligned);
gaussians[i]->to_real();
}
for (int j=0;j<nb_gaussians;j++)
{
Gaussian &gauss = *gaussians[j];
Covariance &_cov = *gauss.covariance;
DiagonalCovariance *cov = dynamic_cast<DiagonalCovariance*> (&_cov);
if (!cov)
throw new GeneralException("Covariance not diagonal in GMM::createDiagGMM()",
__FILE__, __LINE__);
/* Covariance normalization
float norm = 0;
for (int i=0;i<dimensions;i++)
norm += .5*log((*cov).data[i]);
apriori[j] += norm;
*/
}
mode = real;
}
vector<Score> GMM::minDistance(vector <float * > fr) const
{
unsigned int i,j;
Covariance *cov = new DiagonalCovariance (dimensions);
for (j=0;j<dimensions;j++)
{
(*cov)[j]=0;
}
if (1) {
int cov_count = 0;
for (i=0;i<nb_gaussians;i++)
for (j=0;j<dimensions;j++)
{
(*cov)[j]+=gaussians[i]->get_accum_count()/(*(gaussians[i]->covariance))[j];
cov_count += gaussians[i]->get_accum_count();
}
for (j=0;j<dimensions;j++)
{
(*cov)[j]=cov_count/((*cov)[j]);
//cerr << (*cov)[j] << " ";
}
//cerr << endl;
}
cov->mode = (Covariance::inverted);
vector<Score> scores(fr.size());
for (i=0;i<fr.size();i++)
{
scores[i]=minDistance(fr[i],cov);
}
delete cov;
return scores;
}
vector<Score> GMM::score(vector <float * > fr) const
{
vector<Score> scores(fr.size());
for (unsigned int i=0;i<fr.size();i++)
{
scores[i]=score(fr[i]);
}
return scores;
}
Score GMM::minDistance(float * fr,Covariance *cov) const
{
int i,j;
float min_dist = FLT_MAX ;
int min_gauss = 0;
Score frame_score;
for (j=0;j<nb_gaussians;j++)
{
//float dist = gaussians[j]->euclidian(fr);
float dist = gaussians[j]->mahalanobis(fr,cov);
if (dist < min_dist)
{
min_dist=dist;
min_gauss = j;
}
//cerr << "mean " << j << ": " << dist << endl;
}
frame_score.score = min_dist;
frame_score.gaussian_id = min_gauss;
frame_score.gmm = this;
frame_score.frame = fr;
return frame_score;
}
Score GMM::score(float * fr) const
{
float min_dist = FLT_MAX ;
int min_gauss = 0;
Score frame_score;
for (int j=0;j<nb_gaussians;j++)
{
/* Covariance normalization
Gaussian &gauss = *gaussians[j];
Covariance &_cov = *gauss.covariance;
DiagonalCovariance *cov = dynamic_cast<DiagonalCovariance*> (&_cov);
if (!cov)
throw new GeneralException("Covariance not diagonal in GMM::createDiagGMM()",
__FILE__, __LINE__);
float norm = 0;
for (int i=0;i<dimensions;i++)
norm += .5*log((*cov).data[i]);
float dist = gaussians[j]->mahalanobis(fr)-apriori[j]-norm;
*/
float dist = gaussians[j]->mahalanobis(fr)-apriori[j];
//cerr << "apriori[j]: " << apriori[j] << endl;
if (dist < min_dist)
{
min_dist=dist;
min_gauss = j;
}
//cerr << "mean " << j << ": " << dist << " " << apriori[j] << endl;
}
frame_score.score = min_dist;
frame_score.gaussian_id = min_gauss;
frame_score.gmm = this;
frame_score.frame = fr;
return frame_score;
}
void GMM::toIDsUsing (GaussianSet &gauss)
{
if (using_gaussianIDs)
return;
gaussianIDs.resize(nb_gaussians);
using_gaussianIDs=true;
for (int i=0;i<nb_gaussians;i++)
gaussianIDs[i]=gauss.getIDFor(gaussians[i]);
}
void GMM::toPtrsUsing (const GaussianSet &gauss)
{
if (!using_gaussianIDs)
return;
using_gaussianIDs=false;
for (int i=0;i<nb_gaussians;i++)
gaussians[i]=gauss.getPtrFor(gaussianIDs[i]);
}
DiagGMM *GMM::createDiagGMM()
{
DiagGMM *dg = new DiagGMM;
dg->dim = dimensions;
dg->nbGauss = nb_gaussians;
dg->augDim = (dimensions+4)&0xfffffffc;
int allocSize = 2 * dg->augDim * dg->nbGauss * sizeof(float) + CACHE_LINES;
//allocSize += dg->augDim * sizeof(float);
dg->ptr = new char [allocSize];
dg->base = (float *) (((unsigned long)(dg->ptr) + (CACHE_LINES-1))&CACHE_MASK);
float *ptr = dg->base;
for (int k=0;k<nb_gaussians;k++)
{
Gaussian &gauss = *gaussians[k];
Mean &mean = *gauss.mean;
Covariance &_cov = *gauss.covariance;
DiagonalCovariance *cov = dynamic_cast<DiagonalCovariance*> (&_cov);
if (!cov)
throw new GeneralException("Covariance not diagonal in GMM::createDiagGMM()",
__FILE__, __LINE__);
for (int i=0;i<dimensions;i++)
ptr[i] = mean[i];
for (int i=dimensions;i<dg->augDim;i++)
ptr[i]=0;
ptr += dg->augDim;
float norm = 0;
for (int i=0;i<dimensions;i++)
{
norm += .5*log((*cov).data[i]);
ptr[i] = -(*cov).data[i];
}
ptr[dimensions] = apriori[k]+norm;
for (int i=dimensions+1;i<dg->augDim;i++)
ptr[i]=0;
ptr += dg->augDim;
}
return dg;
}
void GMM::printOn(ostream &out) const
{
out << "<GMM " << endl;
out << "<nb_gaussians " << nb_gaussians << ">" << endl;
out << "<mode " << mode << ">" << endl;
out << "<nb_frames_aligned " << nb_frames_aligned << ">" << endl;
out << "<dimensions " << dimensions << ">" << endl;
out << "<apriori " << apriori << ">" << endl;
if (using_gaussianIDs)
out << "<gaussianIDs " << gaussianIDs << ">" << endl;
else
out << "<gaussians " << gaussians << ">" << endl;
out << ">\n";
}
void GMM::readFrom (istream &in)
{
string tag;
while (1)
{
char ch;
in >> ch;
if (ch == '>') break;
else if (ch != '<')
throw new ParsingException ("GMM::readFrom : Parse error: '<' expected");
in >> tag;
if (tag == "nb_gaussians")
in >> nb_gaussians;
else if (tag == "apriori")
in >> apriori;
else if (tag == "dimensions")
in >> dimensions;
else if (tag == "gaussians")
{
in >> gaussians;
using_gaussianIDs = false;
}
else if (tag == "gaussianIDs")
{
in >> gaussianIDs;
using_gaussianIDs = true;
}
else if (tag == "mode")
in >> mode;
else if (tag == "nb_frames_aligned")
in >> nb_frames_aligned;
else
throw new ParsingException ("GMM::readFrom : unknown argument: " + tag);
if (!in) throw new ParsingException ("GMM::readFrom : Parse error trying to build " + tag);
in >> tag;
if (tag != ">")
throw new ParsingException ("GMM::readFrom : Parse error: '>' expected ");
}
}
istream &operator >> (istream &in, GMM &gmm)
{
if (!isValidType(in, "GMM")) return in;
gmm.readFrom(in);
return in;
}
}//namespace FD
syntax highlighted by Code2HTML, v. 0.9.1