각각 200개의 점들로 이루어진 8개의 2차원 가우시안 군집을 무작위로 만들고, 이를 kmeans 알고리즘을 써서 8개로 분할하였다. 아래의 시뮬레이션은 이 정보를 초기 조건으로 하여서 Gaussian Mixture Model (GMM)에 적용한 결과이다. 두 개의 군집에 대해서 kmeans 결과와 GMM의 결과가 서로 많이 차이가 남을 보여준다.
코드 추가: 2010.02.23
struct Data2d {
double x, y ;
int id ;
Data2d() { };
Data2d(double x, double y) : x(x), y(y), id(-1) { }
};
struct Gauss2d {
double cov[4];
double mx, my ; //mean ;
double mix;
//
double nfactor; //1/(2 * Pi * sqrt(det));
double det; //det(cov)
double icov[4];
void prepare();
//
double pdf(double x, double y);
} ;
void Gauss2d::prepare() {
// det(cov);
det = cov[0] * cov[3] - cov[1] * cov[2];
if (det < 1e-10) {
AfxMessageBox("not converging");
return ;
};
nfactor = 1. / (2. * MPI * sqrt(det)) ;
//inv(cov);
icov[0] = cov[3] / det;
icov[1] = -cov[1] / det;
icov[2] = -cov[2] / det;
icov[3] = cov[0] / det;
}
double Gauss2d::pdf(double x, double y) {
x -= mx ;
y -= my ;
double a = x * (icov[0] * x + icov[1] * y) +
y * (icov[2] * x + icov[3] * y);
return (nfactor * exp(-0.5 * a));
};
void init_classes(std::vector<Data2d>& data, std::vector<Gauss2d>& classes) {
/*
for (int i = 0; i < classes.size(); i++) {
Gauss2d& cls = classes[i] ;
cls.cov[0] = 10 + 50 * rand() / double(RAND_MAX);
cls.cov[1] = 0;
cls.cov[2] = 0;
cls.cov[3] = 10 + 50 * rand() / double(RAND_MAX);
cls.mx = 100 + 300 * rand() / double(RAND_MAX);
cls.my = 100 + 300 * rand() / double(RAND_MAX);
cls.mix = 1;
}
*/
KMeans(data, classes);
//use kmeans to locate initial positions;
}
void test_step(std::vector<Data2d>& data,
std::vector<Gauss2d>& classes,
std::vector<std::vector<double> >& prob_cls)
{
//E-step ;
for (int k = 0; k < classes.size(); k++) {
Gauss2d& cls = classes[k];
cls.prepare();
//
for (int i = 0; i < data.size(); i++) {
prob_cls[i][k] = cls.mix * cls.pdf(data[i].x, data[i].y);
};
}
// normalize-->임의의 데이터는 각 어떤 클레스에 속할 활률의 합=1;
for (int i = 0; i < data.size(); i++) {
double s = 0;
int bc = 0; double bp = 0; // to determine membership(debug);
for (int k = 0; k < classes.size(); ++k) {
s += prob_cls[i][k];
// find maximum posterior for each data;
if (bp < prob_cls[i][k]) {
bp = prob_cls[i][k] ;
bc = k ;
};
}
data[i].id = bc;
// normalize to 1;
for (int k = 0; k < classes.size(); ++k)
prob_cls[i][k] /= s;
}
//M-step;
for (int k = 0; k < classes.size(); k++) {
Gauss2d & cls = classes[k];
//get mean;
double meanx = 0;
double meany = 0;
double marginal = 0;
for (int i = 0; i < data.size(); i++) {
meanx += prob_cls[i][k] * data[i].x ;
meany += prob_cls[i][k] * data[i].y ;
marginal += prob_cls[i][k];
};
cls.mx = meanx = meanx / marginal ;
cls.my = meany = meany / marginal ;
// get mixing;
cls.mix = marginal / classes.size();
// get stdev;
double sxx = 0, syy = 0, sxy = 0;
for (int i = 0; i < data.size(); i++) {
double dx = data[i].x - meanx ;
double dy = data[i].y - meany ;
sxx += prob_cls[i][k] * dx * dx ;
syy += prob_cls[i][k] * dy * dy ;
sxy += prob_cls[i][k] * dx * dy ;
};
//set covariance;
cls.cov[0] = sxx / marginal;
cls.cov[1] = sxy / marginal;
cls.cov[3] = syy / marginal;
cls.cov[2] = cls.cov[1]; //symmetric;
}
}
void test() {
int max_iter = 100;
int nclass = 8;
int ndata = 500;
std::vector<Gauss2d> classes(nclass);
std::vector<Data2d> data(ndata);
// prepare posterior space;
std::vector<std::vector<double> > prob_cls;
for (int i = 0; i < data.size(); ++i) {
prob_cls.push_back(std::vector<double>(classes.size()));
} ;
// generate data...
..................................
//init_classes
init_classes(data, classes) ;
int iter = 0;
do {
iter++;
test_step(data, classes, prob_cls);
} while (iter < max_iter) ;
};
728x90
'Image Recognition' 카테고리의 다른 글
Watershed Algorithm 구현 (0) | 2010.03.19 |
---|---|
Retinex 알고리즘 (11) | 2010.02.03 |
Image Morphing (0) | 2010.01.24 |
Fant's Algorithm (0) | 2010.01.22 |
Affine Transformation (0) | 2010.01.20 |