gaussianHMM.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 "gaussianHMM.h"
00041 
00042 using namespace hmm_support;
00043 
00044 void GaussianHMM::setModel(const Matrix& transmission,  const ArrayList<Vector>& list_mean_vec,const ArrayList<Matrix>& list_covariance_mat) {
00045   DEBUG_ASSERT(transmission.n_rows() == transmission.n_cols());
00046   DEBUG_ASSERT(transmission.n_rows() == list_mean_vec.size());
00047   DEBUG_ASSERT(transmission.n_rows() == list_covariance_mat.size());
00048   for (int i = 1; i < list_mean_vec.size(); i++) {
00049     DEBUG_ASSERT(list_mean_vec[0].length() == list_covariance_mat[i].n_rows());
00050     DEBUG_ASSERT(list_mean_vec[0].length() == list_covariance_mat[i].n_cols());
00051     DEBUG_ASSERT(list_mean_vec[0].length() == list_mean_vec[i].length());
00052   }
00053   transmission_.Destruct();
00054   list_mean_vec_.Renew();
00055   list_covariance_mat_.Renew();
00056   transmission_.Copy(transmission);
00057   list_mean_vec_.InitCopy(list_mean_vec);
00058   list_covariance_mat_.InitCopy(list_covariance_mat);
00059   CalculateInverse();
00060 }
00061 
00062 void GaussianHMM::Init(const Matrix& transmission,  const ArrayList<Vector>& list_mean_vec,const ArrayList<Matrix>& list_covariance_mat) {
00063   transmission_.Copy(transmission);
00064   list_mean_vec_.InitCopy(list_mean_vec);
00065   list_covariance_mat_.InitCopy(list_covariance_mat);
00066   DEBUG_ASSERT(transmission.n_rows() == transmission.n_cols());
00067   DEBUG_ASSERT(transmission.n_rows() == list_mean_vec.size());
00068   DEBUG_ASSERT(transmission.n_rows() == list_covariance_mat.size());
00069   for (int i = 1; i < list_mean_vec.size(); i++) {
00070     DEBUG_ASSERT(list_mean_vec[0].length() == list_covariance_mat[i].n_rows());
00071     DEBUG_ASSERT(list_mean_vec[0].length() == list_covariance_mat[i].n_cols());
00072     DEBUG_ASSERT(list_mean_vec[0].length() == list_mean_vec[i].length());
00073   }  
00074   CalculateInverse();
00075 }
00076 
00077 void GaussianHMM::InitFromFile(const char* profile) {
00078   if (!PASSED(GaussianHMM::LoadProfile(profile, &transmission_, &list_mean_vec_, &list_covariance_mat_)))
00079     FATAL("Couldn't open '%s' for reading.", profile);
00080   list_inverse_cov_mat_.InitCopy(list_covariance_mat_);
00081   gauss_const_vec_.Init(list_covariance_mat_.size());
00082   CalculateInverse();
00083 }
00084 
00085 void GaussianHMM::InitFromData(const ArrayList<Matrix>& list_data_seq, int numstate) {
00086   GaussianHMM::InitGaussParameter(numstate, list_data_seq, &transmission_, &list_mean_vec_, &list_covariance_mat_);
00087   list_inverse_cov_mat_.InitCopy(list_covariance_mat_);
00088   gauss_const_vec_.Init(list_covariance_mat_.size());
00089   CalculateInverse();
00090 }
00091 
00092 void GaussianHMM::InitFromData(const Matrix& data_seq, const Vector& state_seq)  {
00093   GaussianHMM::EstimateInit(data_seq, state_seq, &transmission_, 
00094                             &list_mean_vec_, &list_covariance_mat_);
00095   CalculateInverse();
00096 }
00097 
00098 void GaussianHMM::LoadProfile(const char* profile) {
00099   transmission_.Destruct();
00100   list_mean_vec_.Renew();
00101   list_covariance_mat_.Renew();
00102   list_inverse_cov_mat_.Renew();
00103   gauss_const_vec_.Destruct();
00104   InitFromFile(profile);
00105 }
00106 
00107 void GaussianHMM::SaveProfile(const char* profile) const {
00108   GaussianHMM::SaveProfile(profile, transmission_, list_mean_vec_, list_covariance_mat_);
00109 }
00110 
00111 void GaussianHMM::CalculateInverse() {
00112   int M = transmission_.n_rows();
00113   int N = list_mean_vec_[0].length();
00114   for (int i = 0; i < M; i++) {
00115     la::InverseOverwrite(list_covariance_mat_[i], &list_inverse_cov_mat_[i]);
00116     gauss_const_vec_[i] = pow(2.0*math::PI, -N/2.0) * pow(la::Determinant(list_covariance_mat_[i]), -0.5);
00117   }
00118 }
00119 
00120 void GaussianHMM::GenerateSequence(int L, Matrix* data_seq, Vector* state_seq) const {
00121   GaussianHMM::GenerateInit(L, transmission_, list_mean_vec_, list_covariance_mat_, data_seq, state_seq);
00122 }
00123 
00124 void GaussianHMM::EstimateModel(const Matrix& data_seq, const Vector& state_seq) {
00125   transmission_.Destruct();
00126   list_mean_vec_.Renew();
00127   list_covariance_mat_.Renew();
00128   GaussianHMM::EstimateInit(data_seq, state_seq, &transmission_, 
00129                             &list_mean_vec_, &list_covariance_mat_);
00130   CalculateInverse();
00131 }
00132 
00133 void GaussianHMM::EstimateModel(int numstate, const Matrix& data_seq, const Vector& state_seq) {
00134   transmission_.Destruct();
00135   list_mean_vec_.Renew();
00136   list_covariance_mat_.Renew();
00137   GaussianHMM::EstimateInit(numstate, data_seq, state_seq, &transmission_, 
00138                             &list_mean_vec_, &list_covariance_mat_);
00139   CalculateInverse();
00140 }
00141 
00142 void GaussianHMM::DecodeOverwrite(const Matrix& data_seq, Matrix* state_prob_mat, 
00143                                   Matrix* forward_prob_mat, Matrix* backward_prob_mat, Vector* scale_vec) const {
00144   int M = transmission_.n_rows();
00145   int L = data_seq.n_cols();  
00146   Matrix emission_prob_mat(M, L);
00147   GaussianHMM::CalculateEmissionProb(data_seq, list_mean_vec_, list_inverse_cov_mat_,
00148                                      gauss_const_vec_, &emission_prob_mat);
00149   GaussianHMM::Decode(transmission_, emission_prob_mat, state_prob_mat, forward_prob_mat,
00150                       backward_prob_mat, scale_vec);
00151 }
00152 
00153 void GaussianHMM::DecodeInit(const Matrix& data_seq, Matrix* state_prob_mat, 
00154                              Matrix* forward_prob_mat, Matrix* backward_prob_mat, Vector* scale_vec) const {
00155   int M = transmission_.n_rows();
00156   int L = data_seq.n_cols();  
00157   state_prob_mat->Init(M, L);
00158   forward_prob_mat->Init(M, L);
00159   backward_prob_mat->Init(M, L);
00160   scale_vec->Init(L);
00161   Matrix emission_prob_mat(M, L);
00162   GaussianHMM::CalculateEmissionProb(data_seq, list_mean_vec_, list_inverse_cov_mat_,
00163                                      gauss_const_vec_, &emission_prob_mat);
00164   GaussianHMM::Decode(transmission_, emission_prob_mat, state_prob_mat, forward_prob_mat,
00165                       backward_prob_mat, scale_vec);
00166 }
00167 
00168 double GaussianHMM::ComputeLogLikelihood(const Matrix& data_seq) const {
00169   int L = data_seq.n_cols();
00170   int M = transmission_.n_rows();
00171   Matrix fs(M, L), emis_prob(M, L);
00172   Vector sc;
00173   sc.Init(L);
00174   GaussianHMM::CalculateEmissionProb(data_seq, list_mean_vec_, list_inverse_cov_mat_, gauss_const_vec_, &emis_prob);
00175   GaussianHMM::ForwardProcedure(L, transmission_, emis_prob, &sc, &fs);
00176   double loglik = 0;
00177   for (int t = 0; t < L; t++)
00178     loglik += log(sc[t]);
00179   return loglik;
00180 }
00181 
00182 void GaussianHMM::ComputeLogLikelihood(const ArrayList<Matrix>& list_data_seq, ArrayList<double>* list_likelihood) const {
00183   int L = 0;
00184   for (int i = 0; i < list_data_seq.size(); i++)
00185     if (list_data_seq[i].n_cols() > L) L = list_data_seq[i].n_cols();
00186   int M = transmission_.n_rows();
00187   Matrix fs(M, L), emis_prob(M, L);
00188   Vector sc;
00189   sc.Init(L);
00190   list_likelihood->Init();
00191   for (int i = 0; i < list_data_seq.size(); i++) {
00192     int L = list_data_seq[i].n_cols();
00193     GaussianHMM::CalculateEmissionProb(list_data_seq[i], list_mean_vec_, list_inverse_cov_mat_, gauss_const_vec_, &emis_prob);
00194     GaussianHMM::ForwardProcedure(L, transmission_, emis_prob, &sc, &fs);
00195     double loglik = 0;
00196     for (int t = 0; t < L; t++)
00197       loglik += log(sc[t]);
00198     list_likelihood->PushBackCopy(loglik);
00199   }
00200 }
00201 
00202 void GaussianHMM::ComputeViterbiStateSequence(const Matrix& data_seq, Vector* state_seq) const {
00203   int M = transmission_.n_rows();
00204   int L = data_seq.n_cols();
00205   Matrix emis_prob(M, L);
00206   GaussianHMM::CalculateEmissionProb(data_seq, list_mean_vec_, list_inverse_cov_mat_, gauss_const_vec_, &emis_prob);
00207   GaussianHMM::ViterbiInit(transmission_, emis_prob, state_seq);
00208 }
00209 
00210 void GaussianHMM::TrainBaumWelch(const ArrayList<Matrix>& list_data_seq, int max_iteration, double tolerance) {
00211   GaussianHMM::Train(list_data_seq, &transmission_, &list_mean_vec_, &list_covariance_mat_, max_iteration, tolerance);
00212   CalculateInverse();
00213 }
00214 
00215 void GaussianHMM::TrainViterbi(const ArrayList<Matrix>& list_data_seq, int max_iteration, double tolerance) {
00216   GaussianHMM::TrainViterbi(list_data_seq, &transmission_, &list_mean_vec_, &list_covariance_mat_, max_iteration, tolerance);
00217   CalculateInverse();
00218 }
00219 
00220 success_t GaussianHMM::LoadProfile(const char* profile, Matrix* trans, ArrayList<Vector>* means, ArrayList<Matrix>* covs) {
00221   ArrayList<Matrix> matlst;
00222   if (!PASSED(load_matrix_list(profile, &matlst)))
00223     return SUCCESS_FAIL;
00224 
00225   DEBUG_ASSERT(matlst.size() > 0);
00226   trans->Copy(matlst[0]);
00227   means->Init();
00228   covs->Init();
00229   int M = trans->n_rows(); // num of states
00230   DEBUG_ASSERT(matlst.size() == 2*M+1);
00231   int N = matlst[1].n_rows(); // dimension
00232   for (int i = 1; i < 2*M+1; i+=2) {
00233     DEBUG_ASSERT(matlst[i].n_rows()==N && matlst[i].n_cols()==1);
00234     DEBUG_ASSERT(matlst[i+1].n_rows()==N && matlst[i+1].n_cols()==N);
00235     Vector m;
00236     matlst[i].MakeColumnVector(0, &m);
00237     means->PushBackCopy(m);
00238     covs->PushBackCopy(matlst[i+1]);
00239   }
00240   return SUCCESS_PASS;
00241 }
00242 
00243 success_t GaussianHMM::SaveProfile(const char* profile, const Matrix& trans, const ArrayList<Vector>& means, const ArrayList<Matrix>& covs) {
00244   TextWriter w_pro;
00245   if (!PASSED(w_pro.Open(profile))) {
00246     NONFATAL("Couldn't open '%s' for writing.", profile);
00247     return SUCCESS_FAIL;
00248   }
00249   int M = trans.n_rows(); // num of states
00250   DEBUG_ASSERT(means.size() == M && covs.size() == M);
00251   int N = means[0].length(); // dimension
00252   print_matrix(w_pro, trans, "% transmission", "%f,");
00253   for (int i = 0; i < M; i++) {
00254     DEBUG_ASSERT(means[i].length() == N);
00255     DEBUG_ASSERT(covs[i].n_rows()==N && covs[i].n_cols()==N);
00256     char s[100];
00257     sprintf(s, "%% mean - state %d", i);
00258     print_vector(w_pro, means[i], s, "%f,");    
00259     sprintf(s, "%% covariance - state%d", i);
00260     print_matrix(w_pro, covs[i], s, "%f,");    
00261   }
00262   return SUCCESS_PASS;
00263 }
00264 
00265 void GaussianHMM::GenerateInit(int L, const Matrix& trans, const ArrayList<Vector>& means, const ArrayList<Matrix>& covs, Matrix* seq, Vector* states){
00266   DEBUG_ASSERT_MSG((trans.n_rows()==trans.n_cols() && trans.n_rows()==means.size() && trans.n_rows()==covs.size()), "hmm_generateG_init: matrices sizes do not match");
00267   Matrix trsum;
00268   Matrix& seq_ = *seq;
00269   Vector& states_ = *states;
00270   int M, N;
00271   int cur_state;
00272 
00273   M = trans.n_rows();
00274   N = means[0].length();  // emission vector length
00275 
00276   trsum.Copy(trans);
00277 
00278   for (int i = 0; i < M; i++)
00279     for (int j = 1; j < M; j++)
00280       trsum.set(i, j, trsum.get(i, j) + trsum.get(i, j-1));
00281 
00282   seq_.Init(N, L);
00283   states_.Init(L);
00284 
00285   cur_state = 0; // starting state is 0
00286   
00287   for (int i = 0; i < L; i++) {
00288     int j;
00289 
00290     // next state
00291     double r = RAND_UNIFORM_01();
00292     for (j = 0; j < M; j++)
00293       if (r <= trsum.get(cur_state, j)) break;
00294     cur_state = j;
00295         
00296     // emission
00297     Vector e;
00298     RAND_NORMAL_INIT(means[cur_state], covs[cur_state], &e);
00299     for (j = 0; j < N; j++)
00300       seq_.ref(j, i) = e[j];
00301     states_[i] = cur_state;
00302   }
00303 }
00304 
00305 void GaussianHMM::EstimateInit(const Matrix& seq, const Vector& states, Matrix* trans, ArrayList<Vector>* means, ArrayList<Matrix>* covs) {
00306   DEBUG_ASSERT_MSG((seq.n_cols()==states.length()), "hmm_estimateG_init: sequence and states length must be the same");
00307   int M = 0;
00308   for (int i = 0; i < seq.n_cols(); i++)
00309     if (states[i] > M) M = (int) states[i];
00310   M++;
00311   GaussianHMM::EstimateInit(M, seq, states, trans, means, covs);
00312 }
00313 
00314 void GaussianHMM::EstimateInit(int numStates, const Matrix& seq, const Vector& states, Matrix* trans, ArrayList<Vector>* means, ArrayList<Matrix>* covs) {
00315   DEBUG_ASSERT_MSG((seq.n_cols()==states.length()), "hmm_estimateD_init: sequence and states length must be the same");
00316   
00317   int N = seq.n_rows(); // emission vector length
00318   int M = numStates;    // number of states
00319   int L = seq.n_cols(); // sequence length
00320   
00321   Matrix &trans_ = *trans;
00322   ArrayList<Vector>& mean_ = *means;
00323   ArrayList<Matrix>& cov_ = *covs;
00324   Vector stateSum;
00325 
00326   trans_.Init(M, M);
00327   mean_.Init();
00328   cov_.Init();
00329   stateSum.Init(M);
00330 
00331   trans_.SetZero();
00332   for (int i = 0; i < M; i++) {
00333     Vector m;
00334     m.Init(N); m.SetZero();
00335     mean_.PushBackCopy(m);
00336 
00337     Matrix c;
00338     c.Init(N, N); c.SetZero();
00339     cov_.PushBackCopy(c);
00340   }
00341 
00342   stateSum.SetZero();
00343   for (int i = 0; i < L-1; i++) {
00344     int state = (int) states[i];
00345     int next_state = (int) states[i+1];
00346     stateSum[state]++;
00347     trans_.ref(state, next_state)++;
00348   }
00349   for (int i = 0; i < M; i++) {
00350     if (stateSum[i] == 0) stateSum[i] = -INFINITY;
00351     for (int j = 0; j < M; j++)
00352       trans_.ref(i, j) /= stateSum[i];
00353   }
00354 
00355   stateSum.SetZero();
00356   for (int i = 0; i < L; i++) {
00357     int state = (int) states[i];
00358     Vector e;
00359     seq.MakeColumnVector(i, &e);
00360 
00361     stateSum[state]++;
00362     la::AddTo(e, &mean_[state]);
00363   }
00364 
00365   for (int i = 0; i < M; i++)
00366     if (stateSum[i] != 0) 
00367       la::Scale(1.0/stateSum[i], &mean_[i]);
00368   
00369   for (int i = 0; i < L; i++) {
00370     int state = (int) states[i];
00371     Vector e;
00372     seq.MakeColumnVector(i, &e);
00373     Vector d;
00374     la::SubInit(e, mean_[state], &d);
00375     Matrix D;
00376     D.AliasColVector(d);
00377     la::MulExpert(1.0, false, D, true, D, 1.0, &cov_[state]);
00378   }
00379 
00380   for (int i = 0; i < M; i++)
00381     if (stateSum[i] != 0)
00382       la::Scale(1.0/stateSum[i], &cov_[i]);
00383 }
00384 
00385 void GaussianHMM::ForwardProcedure(int L, const Matrix& trans, const Matrix& emis_prob, Vector *scales, Matrix* fs) {
00386   int M = trans.n_rows();
00387 
00388   Matrix& fs_ = *fs;
00389   Vector& s_ = *scales;
00390 
00391   fs_.SetZero();
00392   s_.SetZero();
00393   // NOTE: start state is 0
00394   // time t = 0
00395   for (int i = 0; i < M; i++) {
00396     fs_.ref(i, 0) = trans.get(0, i) * emis_prob.get(i, 0);
00397     s_[0] += fs_.get(i, 0);
00398   }
00399   for (int i = 0; i < M; i++)
00400     fs_.ref(i, 0) /= s_[0];
00401 
00402   // time t = 1 -> L-1
00403   for (int t = 1; t < L; t++) {
00404     for (int j = 0; j < M; j++) {
00405       for (int i = 0; i < M; i++)
00406         fs_.ref(j, t) += fs_.get(i, t-1)*trans.get(i, j);
00407       fs_.ref(j, t) *= emis_prob.get(j, t);
00408       s_[t] += fs_.get(j, t);
00409     }
00410     for (int j = 0; j < M; j++)
00411       fs_.ref(j, t) /= s_[t];
00412   }
00413 }
00414 
00415 void GaussianHMM::BackwardProcedure(int L, const Matrix& trans, const Matrix& emis_prob, const Vector& scales, Matrix* bs) {
00416   int M = trans.n_rows();
00417 
00418   Matrix& bs_ = *bs;
00419   bs_.SetZero();
00420   for (int i = 0; i < M; i++)
00421     bs_.ref(i, L-1) = 1.0;
00422 
00423   for (int t = L-2; t >= 0; t--) {
00424     for (int i = 0; i < M; i++) {
00425       for (int j = 0; j < M; j++)
00426         bs_.ref(i, t) += trans.get(i, j) * bs_.ref(j, t+1) * emis_prob.get(j, t+1);
00427       bs_.ref(i, t) /= scales[t+1];
00428     }
00429   }
00430 }
00431 
00432 double GaussianHMM::Decode(int L, const Matrix& trans, const Matrix& emis_prob, Matrix* pstates, Matrix* fs, Matrix* bs, Vector* scales) {
00433   int M = trans.n_rows();
00434 
00435   DEBUG_ASSERT_MSG((L==pstates->n_cols() && L==fs->n_cols() && L == bs->n_cols() && 
00436                     M==trans.n_cols() && M==emis_prob.n_rows()),"hmm_decodeG: sizes do not match");
00437   
00438   Matrix& ps_ = *pstates;
00439   Vector& s_ = *scales;
00440 
00441   GaussianHMM::ForwardProcedure(L, trans, emis_prob, &s_, fs);
00442   GaussianHMM::BackwardProcedure(L, trans, emis_prob, s_, bs);
00443 
00444   for (int i = 0; i < M; i++)
00445     for (int t = 0; t < L; t++)
00446       ps_.ref(i, t) = fs->get(i,t) * bs->get(i,t);
00447 
00448   double logpseq = 0;
00449   for (int t = 0; t < L; t++) 
00450     logpseq += log(s_[t]);
00451 
00452   return logpseq;
00453 }
00454 
00455 double GaussianHMM::Decode(const Matrix& trans, const Matrix& emis_prob, Matrix* pstates, Matrix* fs, Matrix* bs, Vector* scales) {
00456   int L = emis_prob.n_cols();
00457   return GaussianHMM::Decode(L, trans, emis_prob, pstates, fs, bs, scales);
00458 }
00459 
00460 double GaussianHMM::ViterbiInit(const Matrix& trans, const Matrix& emis_prob, Vector* states) {
00461   int L = emis_prob.n_cols();
00462   return GaussianHMM::ViterbiInit(L, trans, emis_prob, states);
00463 }
00464 
00465 double GaussianHMM::ViterbiInit(int L, const Matrix& trans, const Matrix& emis_prob, Vector* states) {
00466   int M = trans.n_rows();
00467   DEBUG_ASSERT_MSG((M==trans.n_cols() && M==emis_prob.n_rows()),"hmm_viterbiG: sizes do not match");
00468   
00469   Vector& s_ = *states;
00470   s_.Init(L);
00471   
00472   Vector v, vOld;
00473   v.Init(M);
00474   v.SetAll(-INFINITY);
00475   v[0] = 0;
00476   vOld.Copy(v);
00477 
00478   Matrix w;
00479   w.Init(M, L);
00480 
00481   Matrix logtrans;
00482   logtrans.Init(M, M);
00483 
00484   for (int i = 0; i < M; i++)
00485     for (int j = 0; j < M; j++) logtrans.ref(i, j) = log(trans.get(i, j));
00486 
00487 
00488   for (int t = 0; t < L; t++) {
00489     for (int j = 0; j < M; j++) {
00490       double bestVal = -INFINITY;
00491       double bestPtr = -1;      
00492       for (int i = 0; i < M; i++) {
00493         double val = vOld[i] + logtrans.get(i, j);
00494         if (val > bestVal) {
00495           bestVal = val;
00496           bestPtr = i;
00497         }
00498       }
00499       v[j] = bestVal + log(emis_prob.get(j, t));
00500       w.ref(j, t) = bestPtr;
00501     }
00502     vOld.CopyValues(v);
00503   }
00504 
00505   double bestVal = -INFINITY;
00506   double bestPtr = -1;
00507   for (int i = 0; i < M; i++)
00508     if (v[i] > bestVal) {
00509       bestVal = v[i];
00510       bestPtr = i;
00511     }
00512   
00513   s_[L-1] = bestPtr;
00514   for (int t = L-2; t >= 0; t--) {
00515     s_[t] = w.get((int)s_[t+1], t+1);
00516   }
00517 
00518   return bestVal;
00519 }
00520 
00521 void GaussianHMM::CalculateEmissionProb(const Matrix& seq, const ArrayList<Vector>& means, const ArrayList<Matrix>& inv_covs, const Vector& det, Matrix* emis_prob) {
00522   int L = seq.n_cols();
00523   int M = means.size();
00524   for (int t = 0; t < L; t++) {
00525     Vector e;
00526     seq.MakeColumnVector(t, &e);
00527     for (int i = 0; i < M; i++)
00528       emis_prob->ref(i, t) = NORMAL_DENSITY(e, means[i], inv_covs[i], det[i]);
00529   }
00530 }
00531 
00532 void GaussianHMM::InitGaussParameter(int M, const ArrayList<Matrix>& seqs, Matrix* guessTR, ArrayList<Vector>* guessME, ArrayList<Matrix>* guessCO) {
00533   int N = seqs[0].n_rows();
00534   Matrix& gTR = *guessTR;
00535   ArrayList<Vector>& gME = *guessME;
00536   ArrayList<Matrix>& gCO = *guessCO;
00537   ArrayList<int> labels;
00538   Vector sumState;
00539 
00540   kmeans(seqs, M, &labels, &gME, 1000, 1e-5);
00541 
00542   //for (int i = 0; i < labels.size(); i++) printf("%8d", labels[i]);
00543   //printf("---1---\n");
00544 
00545   gTR.Init(M, M); gTR.SetZero();
00546   sumState.Init(M); sumState.SetZero();
00547   gCO.Init();
00548   for (int i = 0; i < M; i++) {
00549     Matrix m;
00550     m.Init(N, N); m.SetZero();
00551     gCO.PushBackCopy(m);
00552   }
00553   //printf("---2---\n");
00554 
00555   int t = 0;
00556   for (int p=0; p < seqs.size(); p++) {
00557     for (int q=0; q < seqs[p].n_cols(); q++,t++)  {
00558       if (q == seqs[p].n_cols() -1) continue;
00559       int i = labels[t];
00560       int j = labels[t+1];
00561 
00562       gTR.ref(i, j)++;
00563       sumState[i]++;
00564       
00565       Vector data_j_Vec, sub_Vec;
00566       Matrix tmp_cov;
00567 
00568       seqs[p].MakeColumnVector(q, &data_j_Vec);
00569       la::SubInit(gME[i], data_j_Vec, &sub_Vec);
00570       tmp_cov.AliasColVector(sub_Vec);
00571       //printf("t = %d x = %8.3f\n", t, sub_Vec[0]);
00572       la::MulExpert(1, false, tmp_cov, true, tmp_cov, 1, &gCO[i]);
00573     }
00574   }
00575   //printf("---3---\n");
00576 
00577   for (int i = 0; i < M; i++) 
00578     if (sumState[i] == 0) {
00579       for (int j = 0; j < M; j++) gTR.ref(i, j) = 0;
00580       gTR.ref(i, i) = 1;
00581       gME[i].SetZero();
00582       gCO[i].SetZero();
00583       for (int j = 0; j < N; j++) gCO[i].ref(j, j) = 1;
00584     }
00585     else {
00586       for (int j = 0; j < M; j++) gTR.ref(i, j) /= sumState[i];
00587       la::Scale(1.0/sumState[i], &gCO[i]);
00588       for (int j = 0; j < N; j++) gCO[i].ref(j, j) += 1e-3; // make sure the diagonal elements are not too small
00589     }
00590   //printf("---4---\n");
00591 }
00592 
00593 void GaussianHMM::TrainViterbi(const ArrayList<Matrix>& seqs, Matrix* guessTR, ArrayList<Vector>* guessME, ArrayList<Matrix>* guessCO, int max_iter, double tol) {
00594   Matrix &gTR = *guessTR;
00595   ArrayList<Vector>& gME = *guessME;
00596   ArrayList<Matrix>& gCO = *guessCO;
00597   int L = -1;
00598   int M = gTR.n_rows();
00599   int N = gME[0].length();
00600   DEBUG_ASSERT_MSG((M==gTR.n_cols() && M==gME.size() && M == gCO.size()),"hmm_trainD: sizes do not match");
00601   
00602   for (int i = 0; i < seqs.size(); i++)
00603     if (seqs[i].n_cols() > L) L = seqs[i].n_cols();
00604 
00605   Matrix TR; // accumulating transition
00606   ArrayList<Vector> ME; // accumulating mean
00607   ArrayList<Matrix> CO; // accumulating covariance
00608   ArrayList<Matrix> INV_CO; // inverse matrix of the covariance
00609   Vector DET; // the determinant * constant of the Normal PDF formula
00610   TR.Init(M, M);
00611   ME.InitCopy(gME);
00612   CO.InitCopy(gCO);
00613   INV_CO.InitCopy(CO);
00614   DET.Init(M);
00615 
00616   Matrix emis_prob;
00617   Vector sumState; // the denominator for each state
00618 
00619   emis_prob.Init(M, L);
00620   sumState.Init(M);
00621 
00622   double loglik = 0, oldlog;
00623   for (int iter = 0; iter < max_iter; iter++) {
00624     oldlog = loglik;
00625     loglik = 0;
00626 
00627     // set the accumulating values to zeros and compute the inverse matrices and determinant constants
00628     TR.SetZero();
00629     for (int i = 0; i < M; i++) {
00630       ME[i].SetZero();
00631       CO[i].SetZero();
00632       la::InverseOverwrite(gCO[i], &INV_CO[i]);
00633       DET[i] = pow(2.0*math::PI, -N/2.0) * pow(la::Determinant(gCO[i]), -0.5);
00634     }
00635     sumState.SetZero();
00636 
00637     // for each sequence, we will use forward-backward procedure and then accumulate
00638     for (int idx = 0; idx < seqs.size(); idx++) {
00639       L = seqs[idx].n_cols();
00640       Vector states;
00641       GaussianHMM::CalculateEmissionProb(seqs[idx], gME, INV_CO, DET, &emis_prob); // first calculate the emission probabilities of the sequence
00642       loglik += GaussianHMM::ViterbiInit(L, gTR, emis_prob, &states); // get the most probable state sequence
00643       
00644       // accumulate expected transition & mean & covariance
00645       for (int t = 0; t < L-1; t++) {
00646         int i = (int) states[t];
00647         int j = (int) states[t+1];
00648         TR.ref(i, j) ++;
00649       }
00650       
00651       for (int t = 0; t < L; t++) {
00652         Vector e;
00653         seqs[idx].MakeColumnVector(t, &e);
00654         int i = (int) states[t];
00655         sumState[i] ++;
00656         la::AddTo(e, &ME[i]);
00657 
00658         Vector d;
00659         la::SubInit(e, gME[i], &d);
00660         Matrix D;
00661         D.AliasColVector(d);
00662         la::MulExpert(1, false, D, true, D, 1.0, &CO[i]);
00663       }
00664       // end accumulate
00665     }
00666 
00667     // after accumulate all sequences: re-estimate transition & mean & covariance for the next iteration
00668     for (int i = 0; i < M; i++) {
00669       double s = 0;
00670       for (int j = 0; j < M; j++) s += TR.get(i, j);
00671       if (s == 0) {
00672         for (int j = 0; j < M; j++) gTR.ref(i, j) = 0;
00673         gTR.ref(i, i) = 1;
00674       }
00675       else {
00676         for (int j = 0; j < M; j++) gTR.ref(i, j) = TR.get(i, j) / s;
00677       }
00678       
00679       if (sumState[i] != 0) {
00680         la::ScaleOverwrite(1.0/sumState[i], ME[i], &gME[i]);
00681         la::ScaleOverwrite(1.0/sumState[i], CO[i], &gCO[i]);
00682       }
00683     }
00684     // end re-estimate
00685 
00686     printf("Iter = %d Loglik = %8.4f\n", iter, loglik);
00687     if (fabs(oldlog - loglik) < tol) {
00688       printf("\nConverged after %d iterations\n", iter);
00689       break;
00690     }
00691     oldlog = loglik;
00692   }
00693 }
00694 
00695 
00696 void GaussianHMM::Train(const ArrayList<Matrix>& seqs, Matrix* guessTR, ArrayList<Vector>* guessME, ArrayList<Matrix>* guessCO, int max_iter, double tol) {
00697   Matrix &gTR = *guessTR;
00698   ArrayList<Vector>& gME = *guessME;
00699   ArrayList<Matrix>& gCO = *guessCO;
00700   int L = -1;
00701   int M = gTR.n_rows();
00702   int N = gME[0].length();
00703   DEBUG_ASSERT_MSG((M==gTR.n_cols() && M==gME.size() && M == gCO.size()),"hmm_trainD: sizes do not match");
00704   
00705   for (int i = 0; i < seqs.size(); i++)
00706     if (seqs[i].n_cols() > L) L = seqs[i].n_cols();
00707 
00708   Matrix TR; // guess transition and emission matrix
00709   ArrayList<Vector> ME; // accumulating mean
00710   ArrayList<Matrix> CO; // accumulating covariance
00711   ArrayList<Matrix> INV_CO; // inverse matrix of the covariance
00712   Vector DET; // the determinant * constant of the Normal PDF formula
00713   TR.Init(M, M);
00714   ME.InitCopy(gME);
00715   CO.InitCopy(gCO);
00716   INV_CO.InitCopy(CO);
00717   DET.Init(M);
00718 
00719   Matrix ps, fs, bs, emis_prob; // to hold hmm_decodeG results
00720   Vector s; // scaling factors
00721   Vector sumState; // the denominator for each state
00722 
00723   ps.Init(M, L);
00724   fs.Init(M, L);
00725   bs.Init(M, L);
00726   s.Init(L);
00727   emis_prob.Init(M, L);
00728   sumState.Init(M);
00729 
00730   double loglik = 0, oldlog;
00731   for (int iter = 0; iter < max_iter; iter++) {
00732     oldlog = loglik;
00733     loglik = 0;
00734 
00735     // set the accumulating values to zeros and compute the inverse matrices and determinant constants
00736     TR.SetZero();
00737     for (int i = 0; i < M; i++) {
00738       ME[i].SetZero();
00739       CO[i].SetZero();
00740       la::InverseOverwrite(gCO[i], &INV_CO[i]);
00741       DET[i] = pow(2.0*math::PI, -N/2.0) * pow(la::Determinant(gCO[i]), -0.5);
00742     }
00743     sumState.SetZero();
00744 
00745     // for each sequence, we will use forward-backward procedure and then accumulate
00746     for (int idx = 0; idx < seqs.size(); idx++) {
00747       // first calculate the emission probabilities of the sequence
00748       L = seqs[idx].n_cols();
00749       for (int t = 0; t < L; t++) {
00750         Vector e;
00751         seqs[idx].MakeColumnVector(t, &e);
00752         for (int i = 0; i < M; i++)
00753           emis_prob.ref(i, t) = NORMAL_DENSITY(e, gME[i], INV_CO[i], DET[i]);
00754       }
00755       
00756       loglik += GaussianHMM::Decode(L, gTR, emis_prob, &ps, &fs, &bs, &s); // forward - backward procedure
00757       
00758       // accumulate expected transition & mean & covariance
00759       for (int t = 0; t < L-1; t++) {
00760         for (int i = 0; i < M; i++)
00761           for (int j = 0; j < M; j++)
00762             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];
00763       }
00764       
00765       for (int t = 0; t < L; t++) {
00766         Vector e;
00767         seqs[idx].MakeColumnVector(t, &e);
00768         for (int i = 0; i < M; i++) {
00769           sumState[i] += ps.get(i, t);
00770           la::AddExpert(ps.get(i, t), e, &ME[i]);
00771 
00772           Matrix D;
00773           D.AliasColVector(e);
00774           la::MulExpert(ps.get(i, t), false, D, true, D, 1.0, &CO[i]);
00775         }
00776       }
00777       // end accumulate
00778     }
00779 
00780     // after accumulate all sequences: re-estimate transition & mean & covariance for the next iteration
00781     for (int i = 0; i < M; i++) {
00782       double s = 0;
00783       for (int j = 0; j < M; j++) s += TR.get(i, j);
00784       if (s == 0) {
00785         for (int j = 0; j < M; j++) gTR.ref(i, j) = 0;
00786         gTR.ref(i, i) = 1;
00787       }
00788       else {
00789         for (int j = 0; j < M; j++) gTR.ref(i, j) = TR.get(i, j) / s;
00790       }
00791       
00792       if (sumState[i] != 0) {
00793         la::ScaleOverwrite(1.0/sumState[i], ME[i], &gME[i]);
00794         Matrix D;
00795         D.AliasColVector(gME[i]);
00796         la::MulExpert(-1.0, false, D, true, D, 1.0/sumState[i], &CO[i]);
00797         gCO[i].CopyValues(CO[i]);
00798       }
00799     }
00800     // end re-estimate
00801 
00802     printf("Iter = %d Loglik = %8.4f\n", iter, loglik);
00803     if (fabs(oldlog - loglik) < tol) {
00804       printf("\nConverged after %d iterations\n", iter);
00805       break;
00806     }
00807     oldlog = loglik;
00808   }
00809 }
Generated on Mon Jan 24 12:04:38 2011 for FASTlib by  doxygen 1.6.3