00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00038 #include "fastlib/fastlib.h"
00039 #include "support.h"
00040 #include "mixgaussHMM.h"
00041 #include "gaussianHMM.h"
00042
00043 using namespace hmm_support;
00044
00045 void MixtureofGaussianHMM::setModel(const Matrix& transmission,
00046 const ArrayList<MixtureGauss>& list_mixture_gauss) {
00047 DEBUG_ASSERT(transmission.n_rows() == transmission.n_cols());
00048 DEBUG_ASSERT(transmission.n_rows() == list_mixture_gauss.size());
00049 transmission_.Destruct();
00050 list_mixture_gauss_.Renew();
00051 transmission_.Copy(transmission);
00052 list_mixture_gauss_.InitCopy(list_mixture_gauss);
00053 }
00054
00055 void MixtureofGaussianHMM::InitFromFile(const char* profile) {
00056 if (!PASSED(MixtureofGaussianHMM::LoadProfile(profile, &transmission_, &list_mixture_gauss_)))
00057 FATAL("Couldn't open '%s' for reading.", profile);
00058 }
00059
00060 void MixtureofGaussianHMM::LoadProfile(const char* profile) {
00061 transmission_.Destruct();
00062 list_mixture_gauss_.Renew();
00063 InitFromFile(profile);
00064 }
00065
00066 void MixtureofGaussianHMM::SaveProfile(const char* profile) const {
00067 MixtureofGaussianHMM::SaveProfile(profile, transmission_, list_mixture_gauss_);
00068 }
00069
00070 void MixtureofGaussianHMM::GenerateSequence(int L, Matrix* data_seq, Vector* state_seq) const {
00071 MixtureofGaussianHMM::GenerateInit(L, transmission_, list_mixture_gauss_, data_seq, state_seq);
00072 }
00073
00074 void MixtureofGaussianHMM::EstimateModel(int numcluster, const Matrix& data_seq,
00075 const Vector& state_seq) {
00076 transmission_.Destruct();
00077 list_mixture_gauss_.Renew();
00078 MixtureofGaussianHMM::EstimateInit(numcluster, data_seq, state_seq, &transmission_,
00079 &list_mixture_gauss_);
00080 }
00081
00082 void MixtureofGaussianHMM::EstimateModel(int numstate, int numcluster,
00083 const Matrix& data_seq, const Vector& state_seq) {
00084 transmission_.Destruct();
00085 list_mixture_gauss_.Renew();
00086 MixtureofGaussianHMM::EstimateInit(numstate, numcluster, data_seq, state_seq,
00087 &transmission_, &list_mixture_gauss_);
00088 }
00089
00090 void MixtureofGaussianHMM::DecodeOverwrite(const Matrix& data_seq, Matrix* state_prob_mat,
00091 Matrix* forward_prob_mat,
00092 Matrix* backward_prob_mat, Vector* scale_vec) const {
00093 int M = transmission_.n_rows();
00094 int L = data_seq.n_cols();
00095 Matrix emission_prob_mat(M, L);
00096 MixtureofGaussianHMM::CalculateEmissionProb(data_seq, list_mixture_gauss_,
00097 &emission_prob_mat);
00098 MixtureofGaussianHMM::Decode(transmission_, emission_prob_mat, state_prob_mat,
00099 forward_prob_mat, backward_prob_mat, scale_vec);
00100 }
00101
00102 void MixtureofGaussianHMM::DecodeInit(const Matrix& data_seq, Matrix* state_prob_mat,
00103 Matrix* forward_prob_mat, Matrix* backward_prob_mat,
00104 Vector* scale_vec) const {
00105 int M = transmission_.n_rows();
00106 int L = data_seq.n_cols();
00107 state_prob_mat->Init(M, L);
00108 forward_prob_mat->Init(M, L);
00109 backward_prob_mat->Init(M, L);
00110 scale_vec->Init(L);
00111 Matrix emission_prob_mat(M, L);
00112 MixtureofGaussianHMM::CalculateEmissionProb(data_seq, list_mixture_gauss_,
00113 &emission_prob_mat);
00114 MixtureofGaussianHMM::Decode(transmission_, emission_prob_mat, state_prob_mat,
00115 forward_prob_mat, backward_prob_mat, scale_vec);
00116 }
00117
00118 double MixtureofGaussianHMM::ComputeLogLikelihood(const Matrix& data_seq) const {
00119 int L = data_seq.n_cols();
00120 int M = transmission_.n_rows();
00121 Matrix fs(M, L), emis_prob(M, L);
00122 Vector sc;
00123 sc.Init(L);
00124
00125 MixtureofGaussianHMM::CalculateEmissionProb(data_seq, list_mixture_gauss_, &emis_prob);
00126 MixtureofGaussianHMM::ForwardProcedure(L, transmission_, emis_prob, &sc, &fs);
00127 double loglik = 0;
00128 for (int t = 0; t < L; t++)
00129 loglik += log(sc[t]);
00130 return loglik;
00131 }
00132
00133 void MixtureofGaussianHMM::ComputeLogLikelihood(const ArrayList<Matrix>& list_data_seq, ArrayList<double>* list_likelihood) const {
00134 int L = 0;
00135 for (int i = 0; i < list_data_seq.size(); i++)
00136 if (list_data_seq[i].n_cols() > L) L = list_data_seq[i].n_cols();
00137 int M = transmission_.n_rows();
00138 Matrix fs(M, L), emis_prob(M, L);
00139 Vector sc;
00140 sc.Init(L);
00141 list_likelihood->Init();
00142 for (int i = 0; i < list_data_seq.size(); i++) {
00143 int L = list_data_seq[i].n_cols();
00144 MixtureofGaussianHMM::CalculateEmissionProb(list_data_seq[i], list_mixture_gauss_, &emis_prob);
00145 MixtureofGaussianHMM::ForwardProcedure(L, transmission_, emis_prob, &sc, &fs);
00146 double loglik = 0;
00147 for (int t = 0; t < L; t++)
00148 loglik += log(sc[t]);
00149 list_likelihood->PushBackCopy(loglik);
00150 }
00151 }
00152
00153 void MixtureofGaussianHMM::ComputeViterbiStateSequence(const Matrix& data_seq, Vector* state_seq) const {
00154 int M = transmission_.n_rows();
00155 int L = data_seq.n_cols();
00156 Matrix emis_prob(M, L);
00157 MixtureofGaussianHMM::CalculateEmissionProb(data_seq, list_mixture_gauss_, &emis_prob);
00158 MixtureofGaussianHMM::ViterbiInit(transmission_, emis_prob, state_seq);
00159 }
00160
00161 void MixtureofGaussianHMM::TrainBaumWelch(const ArrayList<Matrix>& list_data_seq, int max_iteration, double tolerance) {
00162 MixtureofGaussianHMM::Train(list_data_seq, &transmission_, &list_mixture_gauss_, max_iteration, tolerance);
00163 }
00164
00165 void MixtureofGaussianHMM::TrainViterbi(const ArrayList<Matrix>& list_data_seq, int max_iteration, double tolerance) {
00166 MixtureofGaussianHMM::TrainViterbi(list_data_seq, &transmission_, &list_mixture_gauss_, max_iteration, tolerance);
00167 }
00168
00169 success_t MixtureofGaussianHMM::LoadProfile(const char* profile, Matrix* trans, ArrayList<MixtureGauss>* mixs) {
00170 ArrayList<Matrix> matlst;
00171 if (!PASSED(load_matrix_list(profile, &matlst))) {
00172 NONFATAL("Couldn't open '%s' for reading.", profile);
00173 return SUCCESS_FAIL;
00174 }
00175 DEBUG_ASSERT(matlst.size() >= 4);
00176 trans->Copy(matlst[0]);
00177 mixs->Init();
00178 int M = trans->n_rows();
00179 int N = matlst[2].n_rows();
00180 int p = 1;
00181 for (int i = 0; i < M; i++) {
00182 int K = matlst[p].n_rows();
00183
00184 DEBUG_ASSERT(matlst.size() > p+2*K);
00185 MixtureGauss mix;
00186 mix.InitFromProfile(matlst, p, N);
00187 mixs->PushBackCopy(mix);
00188 p += 2*K+1;
00189 }
00190 return SUCCESS_PASS;
00191 }
00192
00193 success_t MixtureofGaussianHMM::SaveProfile(const char* profile, const Matrix& trans, const ArrayList<MixtureGauss>& mixs) {
00194 TextWriter w_pro;
00195 if (!PASSED(w_pro.Open(profile))) {
00196 NONFATAL("Couldn't open '%s' for writing.", profile);
00197 return SUCCESS_FAIL;
00198 }
00199 int M = trans.n_rows();
00200 print_matrix(w_pro, trans, "% transmission", "%E,");
00201 for (int i = 0; i < M; i++) {
00202 int K = mixs[i].n_clusters();
00203 char s[100];
00204 sprintf(s, "%% prior - state %d", i);
00205 print_vector(w_pro, mixs[i].get_prior(), s, "%E,");
00206 for (int k=0; k < K; k++) {
00207 sprintf(s, "%% mean %d - state %d", k, i);
00208 print_vector(w_pro, mixs[i].get_mean(k), s, "%E,");
00209 sprintf(s, "%% covariance %d - state %d", k, i);
00210 print_matrix(w_pro, mixs[i].get_cov(k), s, "%E,");
00211 }
00212 }
00213 return SUCCESS_PASS;
00214 }
00215
00216 void MixtureofGaussianHMM::GenerateInit(int L, const Matrix& trans, const ArrayList<MixtureGauss>& mixs, Matrix* seq, Vector* states){
00217 DEBUG_ASSERT_MSG((trans.n_rows()==trans.n_cols() && trans.n_rows()==mixs.size()), "hmm_generateM_init: matrices sizes do not match");
00218 Matrix trsum;
00219 Matrix& seq_ = *seq;
00220 Vector& states_ = *states;
00221 int M, N;
00222 int cur_state;
00223
00224 M = trans.n_rows();
00225 N = mixs[0].v_length();
00226
00227 trsum.Copy(trans);
00228
00229 for (int i = 0; i < M; i++)
00230 for (int j = 1; j < M; j++)
00231 trsum.set(i, j, trsum.get(i, j) + trsum.get(i, j-1));
00232
00233 seq_.Init(N, L);
00234 states_.Init(L);
00235
00236 cur_state = 0;
00237
00238 for (int i = 0; i < L; i++) {
00239 int j;
00240
00241
00242 double r = RAND_UNIFORM_01();
00243 for (j = 0; j < M; j++)
00244 if (r <= trsum.get(cur_state, j)) break;
00245 cur_state = j;
00246
00247
00248 Vector e;
00249 mixs[cur_state].generate(&e);
00250 for (j = 0; j < N; j++)
00251 seq_.ref(j, i) = e[j];
00252 states_[i] = cur_state;
00253 }
00254 }
00255
00256 void MixtureofGaussianHMM::EstimateInit(int numStates, int numClusters, const Matrix& seq, const Vector& states, Matrix* trans, ArrayList<MixtureGauss>* mixs) {
00257 DEBUG_ASSERT_MSG((seq.n_cols()==states.length()), "hmm_estimateM_init: sequence and states length must be the same");
00258
00259 int N = seq.n_rows();
00260 int M = numStates;
00261 int L = seq.n_cols();
00262 int K = numClusters;
00263
00264 Matrix &trans_ = *trans;
00265 ArrayList<MixtureGauss>& mix_ = *mixs;
00266 Vector stateSum;
00267
00268 trans_.Init(M, M);
00269 mix_.Init();
00270 stateSum.Init(M);
00271
00272 trans_.SetZero();
00273
00274 stateSum.SetZero();
00275 for (int i = 0; i < L-1; i++) {
00276 int state = (int) states[i];
00277 int next_state = (int) states[i+1];
00278 stateSum[state]++;
00279 trans_.ref(state, next_state)++;
00280 }
00281 for (int i = 0; i < M; i++) {
00282 if (stateSum[i] == 0) stateSum[i] = -INFINITY;
00283 for (int j = 0; j < M; j++)
00284 trans_.ref(i, j) /= stateSum[i];
00285 }
00286
00287 ArrayList<Matrix> data;
00288 data.Init();
00289 Vector n_data;
00290 n_data.Init(M); n_data.SetZero();
00291 for (int i = 0; i < L; i++) {
00292 int state = (int) states[i];
00293 n_data[state]++;
00294 }
00295 for (int i = 0; i < M; i++) {
00296 Matrix m;
00297
00298 m.Init(N, (int)n_data[i]);
00299 data.PushBackCopy(m);
00300 }
00301 n_data.SetZero();
00302 for (int i = 0; i < L; i++) {
00303 int state = (int) states[i];
00304 for (int j = 0; j < N; j++) data[state].ref(j, (int)n_data[state]) = seq.get(j, i);
00305 n_data[state]++;
00306
00307 }
00308 for (int i = 0; i < M; i++) {
00309 ArrayList<int> labels;
00310 ArrayList<Vector> means;
00311 kmeans(data[i], K, &labels, &means, 500, 1e-3);
00312
00313
00314 MixtureGauss m;
00315 m.Init(K, data[i], labels);
00316 mix_.PushBackCopy(m);
00317 }
00318 }
00319
00320 void MixtureofGaussianHMM::EstimateInit(int NumClusters, const Matrix& seq, const Vector& states, Matrix* trans, ArrayList<MixtureGauss>* mixs) {
00321 DEBUG_ASSERT_MSG((seq.n_cols()==states.length()), "hmm_estimateG_init: sequence and states length must be the same");
00322 int M = 0;
00323 for (int i = 0; i < seq.n_cols(); i++)
00324 if (states[i] > M) M = (int) states[i];
00325 M++;
00326 MixtureofGaussianHMM::EstimateInit(M, NumClusters, seq, states, trans, mixs);
00327 }
00328
00329 void MixtureofGaussianHMM::ForwardProcedure(int L, const Matrix& trans, const Matrix& emis_prob,
00330 Vector *scales, Matrix* fs) {
00331 GaussianHMM::ForwardProcedure(L, trans, emis_prob, scales, fs);
00332 }
00333
00334 void MixtureofGaussianHMM::BackwardProcedure(int L, const Matrix& trans, const Matrix& emis_prob,
00335 const Vector& scales, Matrix* bs) {
00336 GaussianHMM::BackwardProcedure(L, trans, emis_prob, scales, bs);
00337 }
00338
00339 double MixtureofGaussianHMM::Decode(const Matrix& trans, const Matrix& emis_prob, Matrix* pstates,
00340 Matrix* fs, Matrix* bs, Vector* scales) {
00341 return GaussianHMM::Decode(trans, emis_prob, pstates, fs, bs, scales);
00342 }
00343
00344 double MixtureofGaussianHMM::Decode(int L, const Matrix& trans, const Matrix& emis_prob,
00345 Matrix* pstates, Matrix* fs, Matrix* bs, Vector* scales) {
00346 return GaussianHMM::Decode(L, trans, emis_prob, pstates, fs, bs, scales);
00347 }
00348
00349 double MixtureofGaussianHMM::ViterbiInit(const Matrix& trans, const Matrix& emis_prob, Vector* states) {
00350 return GaussianHMM::ViterbiInit(trans, emis_prob, states);
00351 }
00352
00353 double MixtureofGaussianHMM::ViterbiInit(int L, const Matrix& trans, const Matrix& emis_prob, Vector* states) {
00354 return GaussianHMM::ViterbiInit(L, trans, emis_prob, states);
00355 }
00356
00357 void MixtureofGaussianHMM::CalculateEmissionProb(const Matrix& seq, const ArrayList<MixtureGauss>& mixs, Matrix* emis_prob) {
00358 int M = mixs.size();
00359 int L = seq.n_cols();
00360 for (int t = 0; t < L; t++) {
00361 Vector e;
00362 seq.MakeColumnVector(t, &e);
00363 for (int i = 0; i < M; i++)
00364 emis_prob->ref(i, t) = mixs[i].getPDF(e);
00365 }
00366 }
00367
00368 void MixtureofGaussianHMM::Train(const ArrayList<Matrix>& seqs, Matrix* guessTR, ArrayList<MixtureGauss>* guessMG, int max_iter, double tol) {
00369 Matrix &gTR = *guessTR;
00370 ArrayList<MixtureGauss>& gMG = *guessMG;
00371 int L = -1;
00372 int M = gTR.n_rows();
00373 DEBUG_ASSERT_MSG((M==gTR.n_cols() && M==gMG.size()),"hmm_trainM: sizes do not match");
00374
00375 for (int i = 0; i < seqs.size(); i++)
00376 if (seqs[i].n_cols() > L) L = seqs[i].n_cols();
00377
00378 Matrix TR;
00379 TR.Init(M, M);
00380
00381 Matrix ps, fs, bs, emis_prob;
00382 ArrayList<Matrix> emis_prob_cluster;
00383 Vector s;
00384 Vector sumState;
00385
00386 ps.Init(M, L);
00387 fs.Init(M, L);
00388 bs.Init(M, L);
00389 s.Init(L);
00390 emis_prob.Init(M, L);
00391 sumState.Init(M);
00392 emis_prob_cluster.Init();
00393 for (int i = 0; i < M; i++) {
00394 Matrix m;
00395 int K = gMG[i].n_clusters();
00396 m.Init(K, L);
00397 emis_prob_cluster.PushBackCopy(m);
00398 }
00399
00400 double loglik = 0, oldlog;
00401 for (int iter = 0; iter < max_iter; iter++) {
00402 oldlog = loglik;
00403 loglik = 0;
00404
00405
00406 TR.SetZero();
00407 for (int i = 0; i < M; i++)
00408 gMG[i].start_accumulate();
00409
00410 sumState.SetZero();
00411
00412
00413 for (int idx = 0; idx < seqs.size(); idx++) {
00414
00415 L = seqs[idx].n_cols();
00416 for (int t = 0; t < L; t++) {
00417 Vector e;
00418 seqs[idx].MakeColumnVector(t, &e);
00419 for (int i = 0; i < M; i++) {
00420 double s = 0;
00421 int K = gMG[i].n_clusters();
00422 for (int j = 0; j < K; j++) {
00423 emis_prob_cluster[i].ref(j, t) = gMG[i].getPDF(j, e);
00424 s += emis_prob_cluster[i].ref(j, t);
00425 }
00426 emis_prob.ref(i, t) = s;
00427 }
00428 }
00429
00430 loglik += MixtureofGaussianHMM::Decode(L, gTR, emis_prob, &ps, &fs, &bs, &s);
00431
00432
00433 for (int t = 0; t < L-1; t++) {
00434 for (int i = 0; i < M; i++)
00435 for (int j = 0; j < M; j++)
00436 TR.ref(i, j) += fs.get(i, t) * gTR.get(i, j) * emis_prob.get(j, t+1) * bs.get(j, t+1) / s[t+1];
00437 }
00438
00439 for (int t = 0; t < L; t++) {
00440 Vector e;
00441 seqs[idx].MakeColumnVector(t, &e);
00442 for (int i = 0; i < M; i++) {
00443 double v = ps.get(i, t);
00444 int K = gMG[i].n_clusters();
00445 for (int j = 0; j < K; j++)
00446 gMG[i].accumulate(v * emis_prob_cluster[i].get(j, t) / emis_prob.get(i, t), j, e);
00447 }
00448 }
00449
00450 }
00451
00452
00453 for (int i = 0; i < M; i++) {
00454 double s = 0;
00455 for (int j = 0; j < M; j++) s += TR.get(i, j);
00456 if (s == 0) {
00457 for (int j = 0; j < M; j++) gTR.ref(i, j) = 0;
00458 gTR.ref(i, i) = 1;
00459 }
00460 else {
00461 for (int j = 0; j < M; j++) gTR.ref(i, j) = TR.get(i, j) / s;
00462 }
00463
00464 gMG[i].end_accumulate();
00465 }
00466
00467
00468 printf("Iter = %d Loglik = %8.4f\n", iter, loglik);
00469 if (fabs(oldlog - loglik) < tol) {
00470 printf("\nConverged after %d iterations\n", iter);
00471 break;
00472 }
00473 oldlog = loglik;
00474 }
00475 }
00476
00477 void MixtureofGaussianHMM::TrainViterbi(const ArrayList<Matrix>& seqs, Matrix* guessTR, ArrayList<MixtureGauss>* guessMG, int max_iter, double tol) {
00478 Matrix &gTR = *guessTR;
00479 ArrayList<MixtureGauss>& gMG = *guessMG;
00480 int L = -1;
00481 int M = gTR.n_rows();
00482 DEBUG_ASSERT_MSG((M==gTR.n_cols() && M==gMG.size()),"hmm_trainM: sizes do not match");
00483
00484 for (int i = 0; i < seqs.size(); i++)
00485 if (seqs[i].n_cols() > L) L = seqs[i].n_cols();
00486
00487 Matrix TR;
00488 TR.Init(M, M);
00489
00490 Matrix emis_prob;
00491 ArrayList<Matrix> emis_prob_cluster;
00492
00493 emis_prob.Init(M, L);
00494 emis_prob_cluster.Init();
00495 for (int i = 0; i < M; i++) {
00496 Matrix m;
00497 int K = gMG[i].n_clusters();
00498 m.Init(K, L);
00499 emis_prob_cluster.PushBackCopy(m);
00500 }
00501
00502 double loglik = 0, oldlog;
00503 for (int iter = 0; iter < max_iter; iter++) {
00504 oldlog = loglik;
00505 loglik = 0;
00506
00507
00508 TR.SetZero();
00509 for (int i = 0; i < M; i++)
00510 gMG[i].start_accumulate();
00511
00512
00513 for (int idx = 0; idx < seqs.size(); idx++) {
00514 Vector states;
00515
00516 L = seqs[idx].n_cols();
00517 for (int t = 0; t < L; t++) {
00518 Vector e;
00519 seqs[idx].MakeColumnVector(t, &e);
00520 for (int i = 0; i < M; i++) {
00521 double s = 0;
00522 int K = gMG[i].n_clusters();
00523 for (int j = 0; j < K; j++) {
00524 emis_prob_cluster[i].ref(j, t) = gMG[i].getPDF(j, e);
00525 s += emis_prob_cluster[i].ref(j, t);
00526 }
00527 emis_prob.ref(i, t) = s;
00528 }
00529 }
00530
00531 loglik += GaussianHMM::ViterbiInit(L, gTR, emis_prob, &states);
00532
00533
00534 for (int t = 0; t < L-1; t++) {
00535 int i = (int) states[t];
00536 int j = (int) states[t+1];
00537 TR.ref(i, j)++;
00538 }
00539
00540 for (int t = 0; t < L; t++) {
00541 Vector e;
00542 int i = (int) states[t];
00543 seqs[idx].MakeColumnVector(t, &e);
00544 int K = gMG[i].n_clusters();
00545 for (int j = 0; j < K; j++)
00546 gMG[i].accumulate(emis_prob_cluster[i].get(j, t) / emis_prob.get(i, t), j, e);
00547 }
00548
00549 }
00550
00551
00552 for (int i = 0; i < M; i++) {
00553 double s = 0;
00554 for (int j = 0; j < M; j++) s += TR.get(i, j);
00555 if (s == 0) {
00556 for (int j = 0; j < M; j++) gTR.ref(i, j) = 0;
00557 gTR.ref(i, i) = 1;
00558 }
00559 else {
00560 for (int j = 0; j < M; j++) gTR.ref(i, j) = TR.get(i, j) / s;
00561 }
00562
00563 gMG[i].end_accumulate();
00564 }
00565
00566
00567 printf("Iter = %d Loglik = %8.4f\n", iter, loglik);
00568 if (fabs(oldlog - loglik) < tol) {
00569 printf("\nConverged after %d iterations\n", iter);
00570 break;
00571 }
00572 oldlog = loglik;
00573 }
00574 }
00575