mixgaussHMM.cc

Go to the documentation of this file.
00001 /* MLPACK 0.2
00002  *
00003  * Copyright (c) 2008, 2009 Alexander Gray,
00004  *                          Garry Boyer,
00005  *                          Ryan Riegel,
00006  *                          Nikolaos Vasiloglou,
00007  *                          Dongryeol Lee,
00008  *                          Chip Mappus, 
00009  *                          Nishant Mehta,
00010  *                          Hua Ouyang,
00011  *                          Parikshit Ram,
00012  *                          Long Tran,
00013  *                          Wee Chin Wong
00014  *
00015  * Copyright (c) 2008, 2009 Georgia Institute of Technology
00016  *
00017  * This program is free software; you can redistribute it and/or
00018  * modify it under the terms of the GNU General Public License as
00019  * published by the Free Software Foundation; either version 2 of the
00020  * License, or (at your option) any later version.
00021  *
00022  * This program is distributed in the hope that it will be useful, but
00023  * WITHOUT ANY WARRANTY; without even the implied warranty of
00024  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00025  * General Public License for more details.
00026  *
00027  * You should have received a copy of the GNU General Public License
00028  * along with this program; if not, write to the Free Software
00029  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00030  * 02110-1301, USA.
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); // at least 1 trans, 1 prior, 1 mean, 1 cov
00176   trans->Copy(matlst[0]);
00177   mixs->Init();
00178   int M = trans->n_rows(); // num of states
00179   int N = matlst[2].n_rows(); // dimension
00180   int p = 1;
00181   for (int i = 0; i < M; i++) {
00182     int K = matlst[p].n_rows(); // num of clusters
00183     //DEBUG: printf("load p=%d K=%d\n", p, K);
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(); // num of states
00200   print_matrix(w_pro, trans, "% transmission", "%E,");
00201   for (int i = 0; i < M; i++) {
00202     int K = mixs[i].n_clusters(); // num of 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();  // emission vector 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; // starting state is 0
00237   
00238   for (int i = 0; i < L; i++) {
00239     int j;
00240 
00241     // next state
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     // emission
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(); // emission vector length
00260   int M = numStates;    // number of states
00261   int L = seq.n_cols(); // sequence length
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     //printf("n[%d]=%8.0f\n", i, n_data[i]);
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     //printf("%d %d %8.0f\n", i, state, n_data[state]);
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     //printf("STATE #%d %d\n", i, K);
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; // guess transition and emission matrix
00379   TR.Init(M, M);
00380 
00381   Matrix ps, fs, bs, emis_prob; // to hold hmm_decodeG results
00382   ArrayList<Matrix> emis_prob_cluster;
00383   Vector s; // scaling factors
00384   Vector sumState; // the denominator for each state
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     // set the accumulating values to zeros and compute the inverse matrices and determinant constants
00406     TR.SetZero();
00407     for (int i = 0; i < M; i++) 
00408       gMG[i].start_accumulate();
00409 
00410     sumState.SetZero();
00411 
00412     // for each sequence, we will use forward-backward procedure and then accumulate
00413     for (int idx = 0; idx < seqs.size(); idx++) {
00414       // first calculate the emission probabilities of the sequence
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); // forward - backward procedure
00431       
00432       // accumulate expected transition & gaussian mixture parameters
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       // end accumulate
00450     }
00451 
00452     // after accumulate all sequences: re-estimate transition & mean & covariance for the next iteration
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     // end re-estimate
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; // guess transition and emission matrix
00488   TR.Init(M, M);
00489 
00490   Matrix emis_prob; // to hold hmm_decodeG results
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     // set the accumulating values to zeros and compute the inverse matrices and determinant constants
00508     TR.SetZero();
00509     for (int i = 0; i < M; i++) 
00510       gMG[i].start_accumulate();
00511 
00512     // for each sequence, we will use viterbi procedure to find the most probable state sequence and then accumulate
00513     for (int idx = 0; idx < seqs.size(); idx++) {
00514       Vector states;
00515       // first calculate the emission probabilities of the sequence
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); // viterbi procedure
00532       
00533       // accumulate expected transition & gaussian mixture parameters
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       // end accumulate
00549     }
00550 
00551     // after accumulate all sequences: re-estimate transition & mean & covariance for the next iteration
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     // end re-estimate
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 
Generated on Mon Jan 24 12:04:38 2011 for FASTlib by  doxygen 1.6.3