26 DiscreteHiddenMarkovModel::DiscreteHiddenMarkovModel(){
30 numRandomTrainingIterations = 5;
33 modelType = HMM_LEFTRIGHT;
37 debugLog.setProceedingText(
"[DEBUG DiscreteHiddenMarkovModel]");
38 errorLog.setProceedingText(
"[ERROR DiscreteHiddenMarkovModel]");
39 warningLog.setProceedingText(
"[WARNING DiscreteHiddenMarkovModel]");
40 trainingLog.setProceedingText(
"[TRAINING DiscreteHiddenMarkovModel]");
44 DiscreteHiddenMarkovModel::DiscreteHiddenMarkovModel(
const UINT numStates,
const UINT numSymbols,
const UINT modelType,
const UINT delta){
45 this->numStates = numStates;
46 this->numSymbols = numSymbols;
47 this->modelType = modelType;
50 numRandomTrainingIterations = 5;
54 debugLog.setProceedingText(
"[DEBUG DiscreteHiddenMarkovModel]");
55 errorLog.setProceedingText(
"[ERROR DiscreteHiddenMarkovModel]");
56 warningLog.setProceedingText(
"[WARNING DiscreteHiddenMarkovModel]");
57 trainingLog.setProceedingText(
"[TRAINING DiscreteHiddenMarkovModel]");
59 randomizeMatrices(numStates,numSymbols);
67 numRandomTrainingIterations = 5;
73 debugLog.setProceedingText(
"[DEBUG DiscreteHiddenMarkovModel]");
74 errorLog.setProceedingText(
"[ERROR DiscreteHiddenMarkovModel]");
75 warningLog.setProceedingText(
"[WARNING DiscreteHiddenMarkovModel]");
76 trainingLog.setProceedingText(
"[TRAINING DiscreteHiddenMarkovModel]");
82 this->modelType = modelType;
88 errorLog <<
"DiscreteHiddenMarkovModel(...) - The a,b,pi sizes are invalid!" << std::endl;
93 this->numStates = rhs.numStates;
94 this->numSymbols = rhs.numSymbols;
95 this->delta = rhs.delta;
96 this->numRandomTrainingIterations = rhs.numRandomTrainingIterations;
97 this->cThreshold = rhs.cThreshold;
98 this->modelType = rhs.modelType;
99 this->logLikelihood = rhs.logLikelihood;
103 this->trainingLog = rhs.trainingLog;
105 debugLog.setProceedingText(
"[DEBUG DiscreteHiddenMarkovModel]");
106 errorLog.setProceedingText(
"[ERROR DiscreteHiddenMarkovModel]");
107 warningLog.setProceedingText(
"[WARNING DiscreteHiddenMarkovModel]");
108 trainingLog.setProceedingText(
"[TRAINING DiscreteHiddenMarkovModel]");
112 DiscreteHiddenMarkovModel::~DiscreteHiddenMarkovModel(){
117 bool DiscreteHiddenMarkovModel::resetModel(
const UINT numStates,
const UINT numSymbols,
const UINT modelType,
const UINT delta){
118 this->numStates = numStates;
119 this->numSymbols = numSymbols;
120 this->modelType = modelType;
122 return randomizeMatrices(numStates,numSymbols);
125 bool DiscreteHiddenMarkovModel::randomizeMatrices(
const UINT numStates,
const UINT numSymbols){
132 this->numStates = numStates;
133 this->numSymbols = numSymbols;
134 a.
resize(numStates,numStates);
135 b.
resize(numStates,numSymbols);
151 for(UINT i=0; i<numStates; i++)
161 for(UINT i=0; i<numStates; i++)
162 for(UINT j=0; j<numStates; j++)
163 if((j<i) || (j>i+delta)) a[i][j] = 0.0;
166 for(UINT i=0; i<numStates; i++){
167 pi[i] = i==0 ? 1 : 0;
171 throw(
"HMM_ERROR: Unkown model type!");
178 for (UINT i=0; i<numStates; i++) {
180 for (UINT j=0; j<numStates; j++) sum += a[i][j];
181 for (UINT j=0; j<numStates; j++) a[i][j] /= sum;
183 for (UINT i=0; i<numStates; i++) {
185 for (UINT k=0; k<numSymbols; k++) sum += b[i][k];
186 for (UINT k=0; k<numSymbols; k++) b[i][k] /= sum;
191 for (UINT i=0; i<numStates; i++) sum += pi[i];
192 for (UINT i=0; i<numStates; i++) pi[i] /= sum;
197 Float DiscreteHiddenMarkovModel::predict(
const UINT newSample){
203 observationSequence.
push_back( newSample );
213 Float DiscreteHiddenMarkovModel::predict(
const Vector<UINT> &obs){
215 const int N = (int)numStates;
216 const int T = (int)obs.size();
226 alpha[t][i] = pi[i]*b[i][ obs[t] ];
234 for(i=0; i<N; i++) alpha[t][i] *= c[t];
242 alpha[t][j] += alpha[t-1][i] * a[i][j];
244 alpha[t][j] *= b[j][obs[t]];
252 for(j=0; j<N; j++) alpha[t][j] *= c[t];
255 if(
int(estimatedStates.size()) != T ) estimatedStates.
resize(T);
259 if( alpha[t][i] > maxValue ){
260 maxValue = alpha[t][i];
261 estimatedStates[t] = i;
267 Float loglikelihood = 0.0;
268 for(t=0; t<T; t++) loglikelihood += log( c[t] );
269 return -loglikelihood;
275 Float DiscreteHiddenMarkovModel::predictLogLikelihood(
const Vector<UINT> &obs){
277 const UINT T = (
unsigned int)obs.size();
278 UINT t,i,j,minState = 0;
285 for(i=0; i<numStates; i++){
286 alpha[t][i] = (-1.0 * log(pi[i])) - log(b[i][ obs[t] ]);
291 for (j=0; j<numStates; j++){
293 minWeight = alpha[t-1][j] - log(a[0][j]);
295 for (i=1; i<numStates; i++){
296 weight = alpha[t-1][i] - log(a[i][j]);
298 if (weight < minWeight)
305 alpha[t][j] = minWeight - log(b[j][ obs[t] ]);
311 minWeight = alpha[T - 1][0];
313 for(i=1; i<numStates; i++)
315 if (alpha[T-1][i] < minWeight)
318 minWeight = alpha[T-1][i];
323 return exp(-minWeight);
331 const int N = (int)numStates;
332 const int T = (int)obs.size();
340 hmm.alpha[t][i] = pi[i]*b[i][ obs[t] ];
341 hmm.c[t] += hmm.alpha[t][i];
345 hmm.c[t] = 1.0/hmm.c[t];
348 for(i=0; i<N; i++) hmm.alpha[t][i] *= hmm.c[t];
354 hmm.alpha[t][j] = 0.0;
356 hmm.alpha[t][j] += hmm.alpha[t-1][i] * a[i][j];
358 hmm.alpha[t][j] *= b[j][obs[t]];
359 hmm.c[t] += hmm.alpha[t][j];
363 hmm.c[t] = 1.0/hmm.c[t];
366 for(j=0; j<N; j++) hmm.alpha[t][j] *= hmm.c[t];
371 for(t=0; t<T; t++) hmm.pk += log( hmm.c[t] );
374 if( grt_isinf(hmm.pk) ){
381 for(i=0; i<N; i++) hmm.beta[t][i] = 1.0;
384 for(i=0; i<N; i++) hmm.beta[t][i] *= hmm.c[t];
387 for(t=T-2; t>=0; t--){
392 hmm.beta[t][i] += a[i][j] * b[j][ obs[t+1] ] * hmm.beta[t+1][j];
395 hmm.beta[t][i] *= hmm.c[t];
409 observationSequence.
clear();
410 estimatedStates.clear();
411 trainingIterationLog.clear();
413 UINT n,currentIter, bestIndex = 0;
414 Float newLoglikelihood, bestLogValue = 0;
416 if( numRandomTrainingIterations > 1 ){
423 UINT maxNumTestIter = maxNumEpochs > 10 ? 10 : maxNumEpochs;
426 for(n=0; n<numRandomTrainingIterations; n++){
428 randomizeMatrices(numStates,numSymbols);
430 if( !train_(trainingData,maxNumTestIter,currentIter,newLoglikelihood) ){
435 loglikelihoodTracker[n] = newLoglikelihood;
440 bestLogValue = loglikelihoodTracker[0];
441 for(n=1; n<numRandomTrainingIterations; n++){
442 if(bestLogValue < loglikelihoodTracker[n]){
443 bestLogValue = loglikelihoodTracker[n];
449 a = aTracker[bestIndex];
450 b = bTracker[bestIndex];
453 randomizeMatrices(numStates,numSymbols);
457 if( !train_(trainingData,maxNumEpochs,currentIter,newLoglikelihood) ){
462 const UINT numObs = (
unsigned int)trainingData.size();
464 UINT averageObsLength = 0;
465 for(k=0; k<numObs; k++){
466 const UINT T = (
unsigned int)trainingData[k].size();
467 averageObsLength += T;
470 averageObsLength = (UINT)floor( averageObsLength/Float(numObs) );
471 observationSequence.
resize( averageObsLength );
472 estimatedStates.
resize( averageObsLength );
480 bool DiscreteHiddenMarkovModel::train_(
const Vector<
Vector<UINT> > &obs,
const UINT maxIter, UINT ¤tIter,Float &newLoglikelihood){
482 const UINT numObs = (
unsigned int)obs.size();
484 Float num,denom,oldLoglikelihood = 0;
485 bool keepTraining =
true;
486 trainingIterationLog.clear();
496 for(k=0; k<numObs; k++){
497 const UINT T = (UINT)obs[k].size();
498 gamma[k].
resize(T,numStates);
499 epsilon[k].resize(T);
500 for(t=0; t<T; t++) epsilon[k][t].resize(numStates,numStates);
503 hmms[k].alpha.resize(T,numStates);
504 hmms[k].beta.resize(T,numStates);
510 oldLoglikelihood = 0;
511 newLoglikelihood = 0;
515 newLoglikelihood = 0.0;
518 for(k=0; k<numObs; k++){
519 if( !forwardBackward(hmms[k],obs[k]) ){
522 newLoglikelihood += hmms[k].pk;
526 newLoglikelihood /= numObs;
528 trainingIterationLog.push_back( newLoglikelihood );
530 if( ++currentIter >= maxIter ){ keepTraining =
false; trainingLog <<
"Max Iter Reached! Stopping Training" << std::endl; }
531 if( fabs(newLoglikelihood-oldLoglikelihood) < minChange && currentIter > 1 ){ keepTraining =
false; trainingLog <<
"Min Improvement Reached! Stopping Training" << std::endl; }
534 trainingLog <<
"Iter: " << currentIter <<
" logLikelihood: " << newLoglikelihood <<
" change: " << oldLoglikelihood - newLoglikelihood << std::endl;
539 oldLoglikelihood = newLoglikelihood;
545 for(i=0; i<numStates; i++){
549 for(k=0; k<numObs; k++){
550 for(t=0; t<obs[k].size()-1; t++){
551 denom += hmms[k].alpha[t][i] * hmms[k].beta[t][i] / hmms[k].c[t];
557 for(j=0; j<numStates; j++){
559 for(k=0; k<numObs; k++){
560 for(t=0; t<obs[k].size()-1; t++){
561 num += hmms[k].alpha[t][i] * a[i][j] * b[j][ obs[k][t+1] ] * hmms[k].beta[t+1][j];
569 errorLog <<
"Denom is zero for A!" << std::endl;
575 bool renormB =
false;
576 for(i=0; i<numStates; i++){
577 for(j=0; j<numSymbols; j++){
580 for(k=0; k<numObs; k++){
581 const UINT T = (
unsigned int)obs[k].size();
583 if( obs[k][t] == j ){
584 num += hmms[k].alpha[t][i] * hmms[k].beta[t][i] / hmms[k].c[t];
586 denom += hmms[k].alpha[t][i] * hmms[k].beta[t][i] / hmms[k].c[t];
591 errorLog <<
"Denominator is zero for B!" << std::endl;
597 if( num > 0 ) b[i][j] = denom > 0 ? num/denom : 1.0e-5;
598 else{ b[i][j] = 0; renormB =
true; }
604 for (UINT i=0; i<numStates; i++) {
606 for (UINT k=0; k<numSymbols; k++){
607 b[i][k] += 1.0/numSymbols;
610 for (UINT k=0; k<numSymbols; k++) b[i][k] /= sum;
615 if (modelType==HMM_ERGODIC ){
616 for(k=0; k<numObs; k++){
617 const UINT T = (
unsigned int)obs[k].size();
619 for(t=0; t<T-1; t++){
621 for(i=0; i<numStates; i++){
622 for(j=0; j<numStates; j++){
623 epsilon[k][t][i][j] = hmms[k].alpha[t][i] * a[i][j] * b[j][ obs[k][t+1] ] * hmms[k].beta[t+1][j];
624 denom += epsilon[k][t][i][j];
628 for(i=0; i<numStates; i++){
629 for(j=0; j<numStates; j++){
630 if(denom!=0) epsilon[k][t][i][j] /= denom;
631 else{ epsilon[k][t][i][j] = 0; }
637 for(t=0; t<T-1; t++){
638 for(i=0; i<numStates; i++){
640 for(j=0; j<numStates; j++)
641 gamma[k][t][i] += epsilon[k][t][i][j];
647 for(i=0; i<numStates; i++){
649 for(k=0; k<numObs; k++){
650 sum += gamma[k][0][i];
652 pi[i] = sum / numObs;
657 }
while(keepTraining);
665 for(UINT i=0; i<observationSequence.
getSize(); i++){
676 errorLog <<
"saveModelToFile( fstream &file ) - File is not open!" << std::endl;
681 file <<
"DISCRETE_HMM_MODEL_FILE_V1.0\n";
685 errorLog <<
"saveModelToFile(fstream &file) - Failed to save classifier base settings to file!" << std::endl;
689 file <<
"NumStates: " << numStates << std::endl;
690 file <<
"NumSymbols: " << numSymbols << std::endl;
691 file <<
"ModelType: " << modelType << std::endl;
692 file <<
"Delta: " << delta << std::endl;
693 file <<
"Threshold: " << cThreshold << std::endl;
694 file <<
"NumRandomTrainingIterations: " << numRandomTrainingIterations << std::endl;
697 for(UINT i=0; i<numStates; i++){
698 for(UINT j=0; j<numStates; j++){
700 if( j+1 < numStates ) file <<
"\t";
705 for(UINT i=0; i<numStates; i++){
706 for(UINT j=0; j<numSymbols; j++){
708 if( j+1 < numSymbols ) file <<
"\t";
713 for(UINT i=0; i<numStates; i++){
715 if( i+1 < numStates ) file <<
"\t";
728 errorLog <<
"loadModelFromFile( fstream &file ) - File is not open!" << std::endl;
737 if(word !=
"DISCRETE_HMM_MODEL_FILE_V1.0"){
738 errorLog <<
"loadModelFromFile( fstream &file ) - Could not find Model File Header!" << std::endl;
744 errorLog <<
"loadModelFromFile(string filename) - Failed to load base settings from file!" << std::endl;
749 if(word !=
"NumStates:"){
750 errorLog <<
"loadModelFromFile( fstream &file ) - Could not find the NumStates header." << std::endl;
756 if(word !=
"NumSymbols:"){
757 errorLog <<
"loadModelFromFile( fstream &file ) - Could not find the NumSymbols header." << std::endl;
763 if(word !=
"ModelType:"){
764 errorLog <<
"loadModelFromFile( fstream &file ) - Could not find the modelType for the header." << std::endl;
770 if(word !=
"Delta:"){
771 errorLog <<
"loadModelFromFile( fstream &file ) - Could not find the Delta for the header." << std::endl;
777 if(word !=
"Threshold:"){
778 errorLog <<
"loadModelFromFile( fstream &file ) - Could not find the Threshold for the header." << std::endl;
784 if(word !=
"NumRandomTrainingIterations:"){
785 errorLog <<
"loadModelFromFile( fstream &file ) - Could not find the numRandomTrainingIterations header." << std::endl;
788 file >> numRandomTrainingIterations;
790 a.
resize(numStates,numStates);
791 b.
resize(numStates,numSymbols);
797 errorLog <<
"loadModelFromFile( fstream &file ) - Could not find the A matrix header." << std::endl;
802 for(UINT i=0; i<numStates; i++){
803 for(UINT j=0; j<numStates; j++){
810 errorLog <<
"loadModelFromFile( fstream &file ) - Could not find the B matrix header." << std::endl;
815 for(UINT i=0; i<numStates; i++){
816 for(UINT j=0; j<numSymbols; j++){
823 errorLog <<
"loadModelFromFile( fstream &file ) - Could not find the Pi matrix header." << std::endl;
828 for(UINT i=0; i<numStates; i++){
837 trainingLog <<
"A: " << std::endl;
840 trainingLog << a[i][j] <<
"\t";
842 trainingLog << std::endl;
845 trainingLog <<
"B: " << std::endl;
848 trainingLog << b[i][j] <<
"\t";
850 trainingLog << std::endl;
853 trainingLog <<
"Pi: ";
854 for(UINT i=0; i<pi.size(); i++){
855 trainingLog << pi[i] <<
"\t";
857 trainingLog << std::endl;
864 for(UINT j=0; j<a.
getNumCols(); j++) sum += a[i][j];
865 if( sum <= 0.99 || sum >= 1.01 ) warningLog <<
"WARNING: A Row " << i <<
" Sum: "<< sum << std::endl;
870 for(UINT j=0; j<b.
getNumCols(); j++) sum += b[i][j];
871 if( sum <= 0.99 || sum >= 1.01 ) warningLog <<
"WARNING: B Row " << i <<
" Sum: " << sum << std::endl;
878 VectorFloat DiscreteHiddenMarkovModel::getTrainingIterationLog()
const{
879 return trainingIterationLog;
bool saveBaseSettingsToFile(std::fstream &file) const
bool push_back(const T &value)
virtual bool saveModelToFile(std::fstream &file) const
virtual bool resize(const unsigned int size)
virtual bool loadModelFromFile(std::fstream &file)
unsigned int getNumRows() const
unsigned int getNumCols() const
bool loadBaseSettingsFromFile(std::fstream &file)
This class implements a discrete Hidden Markov Model.
virtual bool print() const
Float getRandomNumberUniform(Float minRange=0.0, Float maxRange=1.0)
virtual bool resize(const unsigned int r, const unsigned int c)
Vector< T > getData(const bool rawBuffer=false) const
unsigned int getSize() const
bool resize(const unsigned int newBufferSize)