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