00001 #include <iostream>
00002 #include <cmath>
00003 #include "Learn/WiimoteGR/HMMLib.h"
00004
00005 using namespace std;
00006
00007 namespace WiimoteGR{
00008
00009 HMM::HMM(const char* gestureName, const Quantizer& quantizer,
00010 const char* modelStyle, bool trained, size_t N,
00011 double *const A_in, double *const B_in, double *const pi_in)
00012 : gestureName(gestureName),
00013 quantizerName(quantizer.name),
00014 modelStyle(modelStyle),
00015 trained(trained),
00016 N(N),
00017 M(quantizer.M)
00018 {
00019 A.assign(A_in, A_in+N*N);
00020 B.assign(B_in, B_in+N*M);
00021 pi.assign(pi_in, pi_in+N);
00022 }
00023
00024 void HMMLib::ShowHMM(HMM& hmm)
00025 {
00026 cout.width(15);
00027 cout << "----------------------------------------------------------------------" << endl;
00028 cout << "A " << (hmm.trained?"trained":"initial") << " HMM of " << hmm.gestureName << " gesture, " << endl;
00029 cout << "Trained with observation sequences quantized by " << hmm.quantizerName << "." << endl;
00030 cout << "with " << hmm.N << " states and " << hmm.M << " observable symbols." << endl << endl;
00031 cout << "pi:" << endl;
00032 for(size_t i=0; i<hmm.N-1; i++){
00033 cout.width(15);
00034 cout << hmm.pi[i];
00035 }
00036 cout.width(15);
00037 cout << hmm.pi[hmm.N-1] << endl;
00038 cout << endl;
00039 cout << "A:" << endl;
00040 for(size_t i=0; i<hmm.N; i++){
00041 for(size_t j=0; j<hmm.N-1; j++){
00042 cout.width(15);
00043 cout << hmm.TranProb(i,j);
00044 }
00045 cout.width(15);
00046 cout << hmm.TranProb(i,hmm.N-1) << endl;
00047 }
00048 cout << endl;
00049 cout << "B^T:" << endl;
00050 for(size_t k=0; k<hmm.M; k++){
00051 for(size_t j=0; j<hmm.N-1; j++){
00052 cout.width(15);
00053 cout << hmm.ObsProb(j,k);
00054 }
00055 cout.width(15);
00056 cout << hmm.ObsProb(hmm.N-1,k) << endl;
00057 }
00058 cout << endl;
00059 }
00060
00061 const HMM& HMMLib::Recognize(const vector<HMM>& HMMVec, TimeSlot& seq)
00062 {
00063 vector<HMM>::const_iterator recognizedHMM = HMMVec.begin();
00064 for(vector<HMM>::const_iterator curHMM = HMMVec.begin()+1; curHMM < HMMVec.end(); curHMM++){
00065 if( SeqLogProb(*curHMM,seq,false) > SeqLogProb(*recognizedHMM,seq,false) )
00066 recognizedHMM = curHMM;
00067 }
00068 return *recognizedHMM;
00069 }
00070
00071 double HMMLib::SeqLogProb(const HMM& hmm, TimeSlot& seq, bool restart)
00072 {
00073 Forward(hmm, seq, restart);
00074 return seq.logProb[&hmm];
00075 }
00076
00077 int HMMLib::EstimateModel(HMM& hmm, TimeSlot& seq, size_t maxIteration)
00078 {
00079 if(hmm.M != seq.M)
00080 return -1;
00081
00082 vector<size_t>& o = seq.o;
00083
00084
00085 vector< vector<double> >& gamma = seq.gamma;
00086 vector< vector< vector<double> > >& xi = seq.xi;
00087
00088
00089 size_t T = o.size();
00090
00091
00092 size_t i, j, k;
00093 size_t t;
00094
00095 size_t loopCount = 0;
00096
00097 double numeratorA, denominatorA;
00098 double numeratorB, denominatorB;
00099
00100
00101 double logProb_prev;
00102
00103 double delta;
00104
00105
00106
00107
00108
00109
00110 seq.beta.resize(T);
00111 seq.gamma.resize(T);
00112 seq.xi.resize(T);
00113 for(size_t t=0; t<T; t++){
00114 seq.beta[t].resize(hmm.N);
00115 seq.gamma[t].resize(hmm.N);
00116 seq.xi[t].resize(hmm.N);
00117 for(size_t i=0; i<hmm.N; i++)
00118 seq.xi[t][i].resize(hmm.N);
00119 }
00120
00121
00122 Forward(hmm,seq,true);
00123 Backward(hmm,seq);
00124 ComputeGamma(hmm,seq);
00125 ComputeXi(hmm,seq);
00126
00127 logProb_prev = seq.logProb[&hmm];
00128
00129
00130
00131
00132 do{
00133
00134 for(i = 0; i < hmm.N; i++)
00135 hmm.pi[i] = 0.0001 + 0.9999*gamma[1][i];
00136
00137
00138 for(i = 0; i < hmm.N; i++) {
00139 denominatorA = 0.0;
00140 for(t = 0; t < T - 1; t++)
00141 denominatorA += gamma[t][i];
00142
00143 for(j = 0; j < hmm.N; j++) {
00144 numeratorA = 0.0;
00145 for(t = 0; t < T - 1; t++)
00146 numeratorA += xi[t][i][j];
00147 hmm.TranProb(i,j) = 0.0001 + 0.9999*numeratorA/denominatorA;
00148 }
00149
00150 denominatorB = denominatorA + gamma[T-1][i];
00151 for(k = 0; k < hmm.M; k++) {
00152 numeratorB = 0.0;
00153 for(t = 0; t < T; t++) {
00154 if(o[t] == k)
00155 numeratorB += gamma[t][i];
00156 }
00157 hmm.ObsProb(i,k) = 0.0001 + 0.9999*numeratorB/denominatorB;
00158 }
00159 }
00160
00161
00162 Forward(hmm,seq,true);
00163 Backward(hmm,seq);
00164 ComputeGamma(hmm,seq);
00165 ComputeXi(hmm,seq);
00166
00167
00168 delta = seq.logProb[&hmm] - logProb_prev;
00169 logProb_prev = seq.logProb[&hmm];
00170 loopCount++;
00171 }while(loopCount < maxIteration);
00172 return loopCount;
00173 }
00174
00175
00176 int HMMLib::EstimateModelBySeqs(HMM& hmm, vector<TimeSlot>& seqs, size_t maxIteration)
00177 {
00178 if( !CheckAndAllocateMemory(hmm,seqs) )
00179 return -1;
00180
00181 size_t i, j, k;
00182 size_t t;
00183 size_t T;
00184
00185 size_t loopCount = 0;
00186
00187 double numeratorA, numeratorA_partial, denominatorA, denominatorA_partial;
00188 double numeratorB, numeratorB_partial, denominatorB, denominatorB_partial;
00189
00190 double logProbSum_prev = 0.0;
00191 double logProbSum = 0.0;
00192 double delta;
00193
00194
00195
00196
00197 vector<TimeSlot>::iterator curSeq;
00198 for(curSeq = seqs.begin(); curSeq < seqs.end(); curSeq++){
00199 Forward(hmm, *curSeq, true);
00200 Backward(hmm, *curSeq);
00201 ComputeGamma(hmm, *curSeq);
00202 ComputeXi(hmm, *curSeq);
00203 logProbSum_prev += curSeq->logProb[&hmm];
00204 }
00205
00206
00207
00208 do{
00209
00210
00211
00212
00213
00214 for(i = 0; i < hmm.N; i++) {
00215 denominatorA = 0.0;
00216 denominatorB = 0.0;
00217 for(curSeq = seqs.begin(); curSeq < seqs.end(); curSeq++){
00218 double& logProb = curSeq->logProb[&hmm];
00219 vector< vector<double> >& gamma = curSeq->gamma;
00220 T = curSeq->o.size();
00221 denominatorA_partial = 0.0;
00222 for(t = 0; t < T - 1; t++)
00223 denominatorA_partial += gamma[t][i];
00224 denominatorB_partial = denominatorA_partial + gamma[T-1][i];
00225 denominatorA += denominatorA_partial/exp(logProb);
00226 denominatorB += denominatorB_partial/exp(logProb);
00227 }
00228
00229 for(j = 0; j < hmm.N; j++) {
00230 numeratorA = 0.0;
00231 for(curSeq = seqs.begin(); curSeq < seqs.end(); curSeq++){
00232 vector< vector< vector<double> > >& xi = curSeq->xi;
00233 T = curSeq->o.size();
00234 numeratorA_partial = 0.0;
00235 for(t = 0; t < T - 1; t++)
00236 numeratorA_partial += xi[t][i][j];
00237 numeratorA += numeratorA_partial/exp(curSeq->logProb[&hmm]);
00238 }
00239 hmm.TranProb(i,j) = 0.0001 + 0.9999*numeratorA/denominatorA;
00240 }
00241
00242 for(k = 0; k < hmm.M; k++) {
00243 numeratorB = 0.0;
00244 for(curSeq = seqs.begin(); curSeq < seqs.end(); curSeq++){
00245 vector< vector<double> >& gamma = curSeq->gamma;
00246 vector<size_t>& o = curSeq->o;
00247 T = o.size();
00248 numeratorB_partial = 0.0;
00249 for(t = 0; t < T; t++) {
00250 if(o[t] == k)
00251 numeratorB_partial += gamma[t][i];
00252 }
00253 numeratorB += numeratorB_partial/exp(curSeq->logProb[&hmm]);
00254 }
00255 hmm.ObsProb(i,k) = 0.0001 + 0.9999*numeratorB/denominatorB;
00256 }
00257 }
00258
00259
00260 for(curSeq = seqs.begin(); curSeq < seqs.end(); curSeq++){
00261
00262 Forward(hmm, *curSeq, true);
00263 Backward(hmm, *curSeq);
00264 ComputeGamma(hmm, *curSeq);
00265 ComputeXi(hmm, *curSeq);
00266 logProbSum += curSeq->logProb[&hmm];
00267 }
00268
00269
00270 delta = logProbSum - logProbSum_prev;
00271 logProbSum_prev = logProbSum;
00272 loopCount++;
00273 }while(loopCount < maxIteration);
00274 return loopCount;
00275 }
00276
00277 bool HMMLib::CheckAndAllocateMemory(const HMM &hmm, vector<TimeSlot>& seqs)
00278 {
00279
00280
00281
00282
00283
00284 vector<TimeSlot>::iterator curSeq;
00285 for(curSeq = seqs.begin(); curSeq < seqs.end(); curSeq++){
00286 if( curSeq->M != hmm.M)
00287 return false;
00288 }
00289 size_t N = hmm.N;
00290 size_t T;
00291 for(curSeq = seqs.begin(); curSeq < seqs.end(); curSeq++){
00292 T = curSeq->o.size();
00293
00294
00295
00296
00297 curSeq->beta.resize(T);
00298 curSeq->gamma.resize(T);
00299 curSeq->xi.resize(T);
00300 for(size_t t=0; t<T; t++){
00301
00302 curSeq->beta[t].resize(N,0);
00303 curSeq->gamma[t].resize(N,0);
00304 curSeq->xi[t].resize(N);
00305 for(size_t i=0; i<N; i++)
00306 curSeq->xi[t][i].resize(N,0);
00307 }
00308 }
00309 return true;
00310 }
00311
00312
00313
00314
00315
00316
00317 void HMMLib::Forward(const HMM& hmm, TimeSlot& seq, bool restart)
00318 {
00319
00320 const HMM* hmmPtr = &hmm;
00321 vector<size_t>& o = seq.o;
00322 vector< vector<double> >& alpha = seq.alpha[hmmPtr];
00323 vector<double>& scale = seq.scale[hmmPtr];
00324 double& logProb = seq.logProb[hmmPtr];
00325
00326 size_t i, j;
00327 size_t t;
00328 double sum;
00329
00330
00331 if(restart)
00332 alpha.clear();
00333
00334
00335
00336 size_t t_begin = alpha.size();
00337 size_t T = o.size();
00338
00339
00340 alpha.resize(T);
00341 scale.resize(T);
00342
00343
00344
00345
00346
00347 for(t = t_begin; t < T; t++) {
00348
00349
00350
00351
00352 if(t == 0){
00353 logProb = 0.0;
00354 scale[0] = 0.0;
00355 alpha[0].resize(hmm.N);
00356 for(i = 0; i < hmm.N; i++) {
00357 alpha[0][i] = hmm.pi[i] * hmm.ObsProb(i,o[0]);
00358 scale[0] += alpha[0][i];
00359 }
00360 for(i = 0; i < hmm.N; i++)
00361 alpha[0][i] /= scale[0];
00362 }else{
00363 scale[t] = 0.0;
00364 alpha[t].resize(hmm.N);
00365 for(j = 0; j < hmm.N; j++) {
00366 sum = 0.0;
00367 for(i = 0; i < hmm.N; i++)
00368 sum += alpha[t-1][i] * hmm.TranProb(i,j);
00369
00370 alpha[t][j] = sum * hmm.ObsProb(j,o[t]);
00371 scale[t] += alpha[t][j];
00372 }
00373 for(j = 0; j < hmm.N; j++)
00374 alpha[t][j] /= scale[t];
00375 }
00376 }
00377
00378
00379
00380
00381 for(t = t_begin; t < T; t++){
00382 logProb += log(scale[t]);
00383 }
00384 }
00385
00386
00387
00388
00389
00390 void HMMLib::Backward(const HMM& hmm, TimeSlot& seq)
00391 {
00392
00393 vector<size_t>& o = seq.o;
00394 vector< vector<double> >& beta = seq.beta;
00395 vector<double>& scale = seq.scale[&hmm];
00396
00397 size_t i, j;
00398 size_t t;
00399 double sum;
00400
00401 size_t T = seq.o.size();
00402
00403
00404
00405
00406
00407 for(i = 0; i < hmm.N; i++)
00408 beta[T-1][i] = 1.0/scale[T-1];
00409
00410
00411
00412
00413 for(t = T - 2; ; t--) {
00414 for(i = 0; i < hmm.N; i++) {
00415 sum = 0.0;
00416 for(j = 0; j < hmm.N; j++)
00417 sum += hmm.TranProb(i,j)
00418 * hmm.ObsProb(j,o[t+1])
00419 * beta[t+1][j];
00420 beta[t][i] = sum/scale[t];
00421 }
00422 if(t==0)
00423 break;
00424 }
00425
00426 }
00427
00428 void HMMLib::ComputeGamma(const HMM& hmm, TimeSlot& seq)
00429 {
00430
00431
00432 vector< vector<double> >& alpha = seq.alpha[&hmm];
00433 vector< vector<double> >& beta = seq.beta;
00434 vector< vector<double> >& gamma = seq.gamma;
00435
00436 size_t i, j;
00437 size_t t;
00438 double denominator;
00439
00440 size_t T = seq.o.size();
00441
00442 for(t = 0; t < T; t++) {
00443 denominator = 0.0;
00444 for(j = 0; j < hmm.N; j++) {
00445 gamma[t][j] = alpha[t][j] * beta[t][j];
00446 denominator += gamma[t][j];
00447 }
00448
00449 for(i = 0; i < hmm.N; i++)
00450 gamma[t][i] = gamma[t][i]/denominator;
00451 }
00452 }
00453 void HMMLib::ComputeXi(const HMM& hmm, TimeSlot& seq)
00454 {
00455
00456 vector<size_t>& o = seq.o;
00457 vector< vector<double> >& alpha = seq.alpha[&hmm];
00458 vector< vector<double> >& beta = seq.beta;
00459
00460 vector< vector< vector<double> > >& xi = seq.xi;
00461
00462 size_t i, j;
00463 size_t t;
00464 double denominator;
00465
00466 size_t T = seq.o.size();
00467
00468 for(t = 0; t < T-1; t++) {
00469 denominator = 0.0;
00470 for(i = 0; i < hmm.N; i++)
00471 for(j = 0; j < hmm.N; j++) {
00472 xi[t][i][j] = alpha[t][i] * beta[t+1][j] * hmm.TranProb(i,j) * hmm.ObsProb(j,o[t+1]);
00473 denominator += xi[t][i][j];
00474 }
00475
00476 for(i = 0; i < hmm.N; i++)
00477 for(j = 0; j < hmm.N; j++)
00478 xi[t][i][j] /= denominator;
00479 }
00480 }
00481 }