LTI-Lib latest version v1.9 - last update 10 Apr 2010

ltiHmmTrainer.h

00001 /*
00002  * Copyright (C) 2002, 2003, 2004, 2005, 2006
00003  * Lehrstuhl fuer Technische Informatik, RWTH-Aachen, Germany
00004  *
00005  * This file is part of the LTI-Computer Vision Library (LTI-Lib)
00006  *
00007  * The LTI-Lib is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License (LGPL)
00009  * as published by the Free Software Foundation; either version 2.1 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * The LTI-Lib is distributed in the hope that it will be
00013  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
00014  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with the LTI-Lib; see the file LICENSE.  If
00019  * not, write to the Free Software Foundation, Inc., 59 Temple Place -
00020  * Suite 330, Boston, MA 02111-1307, USA.
00021  */
00022 
00023 /*--------------------------------------------------------------------
00024  * project ....: LTI-Lib: Image Processing and Computer Vision Library
00025  * file .......: ltiHmmTrainer.h
00026  * authors ....: Benjamin Winkler
00027  * organization: LTI, RWTH Aachen
00028  * creation ...: 7.1.2002
00029  * revisions ..: $Id: ltiHmmTrainer.h,v 1.9 2006/02/08 12:27:23 ltilib Exp $
00030  */
00031 
00032 #ifndef _LTI_HMM_TRAINER_H_
00033 #define _LTI_HMM_TRAINER_H_
00034 
00035 #include <vector>
00036 
00037 #include "ltiFunctor.h"
00038 #include "ltiHmmViterbiPathSearch.h"
00039 
00040 namespace lti {
00041   /**
00042    * Hidden Markov Model (HMM) trainer.
00043    * This class creates a hiddenMarkovModel from a given training set of
00044    * feature vector sequences.
00045    *
00046    * By default a bakis-topology is chosen (0-1-2 transitions), but this
00047    * can be changed by redefining minJump and maxJump.
00048    *
00049    * The Viterbi training algorithm, aka segmental K-means, and a mixture
00050    * density estimator are used to determine the HMM %parameters, starting
00051    * from the user-defined %parameters.
00052    *
00053    * See: B.-H. Juang and L. Rabiner, "The segmentation K-means algorithm for
00054    * estimating %parameters of hidden markov models", IEEE ASSP Magazine,
00055    * no.9, vol.38, pp.1639-1641,1990.
00056    *
00057    * <b>Note</b>: for computational efficiency probabilities p are not
00058    * explicitly computed but represented by <b>scores</b>
00059    * (~ -ln(p)). Note that a high score corresponds to a low probability,
00060    * i.e. it actually resembles a cost.
00061    */
00062   class hmmTrainer : public functor {
00063   public:
00064 
00065     /**
00066      * the parameters for the class hmmTrainer
00067      */
00068     class parameters : public functor::parameters {
00069     public:
00070       /**
00071        * default constructor
00072        */
00073       parameters();
00074 
00075       /**
00076        * copy constructor
00077        * @param other the parameters object to be copied
00078        */
00079       parameters(const parameters& other);
00080 
00081       /**
00082        * destructor
00083        */
00084       ~parameters();
00085 
00086       /**
00087        * returns name of this type
00088        */
00089       const char* getTypeName() const;
00090 
00091       /**
00092        * copy the contents of a parameters object
00093        * @param other the parameters object to be copied
00094        * @return a reference to this parameters object
00095        */
00096       parameters& copy(const parameters& other);
00097 
00098       /**
00099        * copy the contents of a parameters object
00100        * @param other the parameters object to be copied
00101        * @return a reference to this parameters object
00102        */
00103       parameters& operator=(const parameters& other);
00104 
00105 
00106       /**
00107        * returns a pointer to a clone of the parameters
00108        */
00109       virtual functor::parameters* clone() const;
00110 
00111       /**
00112        * write the parameters in the given ioHandler
00113        * @param handler the ioHandler to be used
00114        * @param complete if true (the default) the enclosing begin/end will
00115        *        be also written, otherwise only the data block will be written.
00116        * @return true if write was successful
00117        */
00118       virtual bool write(ioHandler& handler,const bool complete=true) const;
00119 
00120       /**
00121        * read the parameters from the given ioHandler
00122        * @param handler the ioHandler to be used
00123        * @param complete if true (the default) the enclosing begin/end will
00124        *        be also written, otherwise only the data block will be written.
00125        * @return true if write was successful
00126        */
00127       virtual bool read(ioHandler& handler,const bool complete=true);
00128 
00129 #     ifdef _LTI_MSC_6
00130       /**
00131        * this function is required by MSVC only, as a workaround for a
00132        * very awful bug, which exists since MSVC V.4.0, and still by
00133        * V.6.0 with all bugfixes (so called "service packs") remains
00134        * there...  This method is also public due to another bug, so please
00135        * NEVER EVER call this method directly: use read() instead
00136        */
00137       bool readMS(ioHandler& handler,const bool complete=true);
00138 
00139       /**
00140        * this function is required by MSVC only, as a workaround for a
00141        * very awful bug, which exists since MSVC V.4.0, and still by
00142        * V.6.0 with all bugfixes (so called "service packs") remains
00143        * there...  This method is also public due to another bug, so please
00144        * NEVER EVER call this method directly: use write() instead
00145        */
00146       bool writeMS(ioHandler& handler,const bool complete=true) const;
00147 #     endif
00148 
00149       // ------------------------------------------------
00150       // the parameters
00151       // ------------------------------------------------
00152 
00153       /**
00154        * Pooling modes
00155        */
00156       enum poolingType {
00157         noPooling,   /*!< don't pool variances */
00158         statePooling,/*!< pool variances within one state */
00159         modelPooling /*!< pool variances of a dimension for all states */
00160       };
00161 
00162       /**
00163        * Estimator types:
00164        */
00165       enum estimatorType {
00166         estimMaximumLikelihood, /*!< select estimator for given score
00167                                   function (default) */
00168         estimStandardDeviation, /*!< standard deviation (gaussian
00169                                   maximum-likelihood) */
00170         estimMeanDeviation,     /*!< mean absolute deviation
00171                                   (laplacian maximum-likelihood) */
00172         estimMeanDeviationRoot  /*!< root of mean absolute deviation
00173                                   (laplacian maximum-likelihood) */
00174       };
00175 
00176       /**
00177        * special definitions for numberOfStates
00178        */
00179       enum {
00180         minimumSequenceLength = 0, /*!< uses the minimum length of all
00181                                      sequences as number of states */
00182         averageSequenceLength = -1 /*!< uses the average length of all
00183                                      sequences as number of states */
00184       };
00185 
00186 
00187       /** @name Training termination
00188        *  These members are the training iteration control %parameters.
00189        *  <b>For experienced users!</b>
00190        */
00191       //@{
00192 
00193         /**
00194          * Maximum number of training iterations.
00195          *
00196          * Default is 0 (iterate, until convergenceThreshold is reached).
00197          */
00198         int maxIterations;
00199 
00200         /**
00201          * Estimation of the HMM %parameters is finished, when score
00202          * enhancement within one iteration is below or equal to
00203          * convergence threshold for given training data.
00204          *
00205          * Default is 0.0 (iterate, while model score is improving)
00206          */
00207         double convergenceThreshold;
00208 
00209       //@}
00210 
00211 
00212     /** @name HMM attributes
00213      *  These members are the model attributes.
00214      */
00215       //@{
00216 
00217         /**
00218          * Number of states of the model to be generated.
00219          *
00220          * A value of <b>minimumSequenceLength</b> (0) indicates to
00221          * pick the size of the shortest observation sequence,
00222          * <b>averageSequenceLength</b> (-1) picks the average size of
00223          * all considered observation sequences.
00224          *
00225          * Default: minimumSequenceLength (0)
00226          */
00227         int numberOfStates;
00228 
00229         /**
00230          * Minimum relative forward jump within HMM.
00231          *
00232          * Default: 0 , i.e. loop to current state
00233          */
00234         int minimumJump;
00235 
00236         /**
00237          * Maximum relative forward jump within HMM.
00238          *
00239          * Default: 2
00240          */
00241         int maximumJump;
00242 
00243         /**
00244          * Vector of initial scores.
00245          * If the size of this vector differs from numberOfStates, the default
00246          * initialScore is used:
00247          *
00248          * <code>
00249          * <TABLE>
00250          *  <TR> <TD>            </TD><TD>state 0 </TD><TD>other states</TD> </TR>
00251          *  <TR> <TD><b>score</b></TD><TD><b>0</b></TD><TD><b>oo</b>   </TD> </TR>
00252          *  <TR> <TD>(prob)      </TD><TD>(1)     </TD><TD>(0)         </TD> </TR>
00253          * </TABLE>
00254          * </code>
00255          *
00256          * Remember to specify the initialScore as <b>scores</b>
00257          * (i.e. ~ -ln(p)). Note that the initialScore vector doesn't have
00258          * to be normalized.
00259          */
00260         dvector initialScore;
00261       //@}
00262 
00263 
00264     /** @name Emission density
00265      *
00266      *  %Parameters defining the kind of emission density and the
00267      *  estimator to use.
00268      */
00269       //@{
00270 
00271         /**
00272          * Density function type to be used for the emission scores.
00273          *
00274          * Default: laplaceScore
00275          */
00276         hiddenMarkovModel::scoreType scoreFunction;
00277 
00278         /**
00279          * Method for estimating the scaling factor (ie spread) of the
00280          * density functions.
00281          *
00282          * Default: estimMaximumLikelihood
00283          */
00284         estimatorType estimatorFunction;
00285 
00286         /**
00287          * Minimum scaling factor. This is required to avoid very
00288          * narrow and high density functions, which are obtained, when
00289          * variation in data is too little.
00290          *
00291          * Default is 0.1
00292          */
00293         double minScalingFactor;
00294 
00295       //@}
00296 
00297     /** @name Splitting (mixture densities)
00298      *  These members can be adjusted to change the splitting process, where
00299      *  the density functions are successively divided into smaller ones to
00300      *  describe the actual distribution better.
00301      *
00302      *  <b>For intermediate users!</b>
00303      */
00304       //@{
00305 
00306         /**
00307          * Maximum allowed number of densities per state.
00308          *
00309          * Default = 5
00310          */
00311         int maxDensities;
00312 
00313         /**
00314          * Number of iterations between two split processes.
00315          *
00316          * A value of 0 will reassign observations until no further
00317          * changes occur (nope, not yet!).
00318          *
00319          * The default value is 5 (split densities at every 5th iteration).
00320          */
00321         int reassignmentIterations;
00322 
00323         /**
00324          * Number of iteration, where splitting is taken into
00325          * consideration for the first time.
00326          *
00327          * By default, this is set to 0.
00328          */
00329         int firstSplit;
00330 
00331         /**
00332          * Pooling means to compute a common scaling factor (spread,
00333          * variance) for several densities. You can select to have no
00334          * pooling, state pooling or model pooling.
00335          *
00336          * Default: noPooling
00337          */
00338         poolingType pooling;
00339 
00340         /**
00341          * Minimum number of observations assigned to a density to be
00342          * splittable.
00343          *
00344          * Default: 3
00345          */
00346         int minFramesForSplit;
00347 
00348       //@}
00349 
00350 
00351     };
00352 
00353     /**
00354      * default constructor
00355      */
00356     hmmTrainer();
00357 
00358     /**
00359      * copy constructor
00360      * @param other the object to be copied
00361      */
00362     hmmTrainer(const hmmTrainer& other);
00363 
00364     /**
00365      * destructor
00366      */
00367     virtual ~hmmTrainer();
00368 
00369     /**
00370      * returns the name of this type ("hmmTrainer")
00371      */
00372     virtual const char* getTypeName() const;
00373 
00374     /**
00375      * Discard sequences considered so far.
00376      */
00377     void reset();
00378 
00379     /**
00380      * Consider this sequence for computing the hidden markov model.
00381      * The sequence is added to an internal data store.
00382      */
00383     void consider(const sequence<dvector> &theSeq);
00384 
00385     /**
00386      * Consider multiple sequences for computing the hidden markov model.
00387      * The sequences are added to an internal data store.
00388      */
00389     void consider(const std::vector< sequence<dvector> > &theSequences);
00390 
00391     /**
00392      * Generate hiddenMarkovModel from the data in the internal data store,
00393      * that has been filled with the consider() members so far.
00394      */
00395     void apply(hiddenMarkovModel &model);
00396 
00397     /**
00398      * Get the progress of the total score over training data. The returned
00399      * vector contains the scores of each iteration as a result of the training
00400      * (apply()).
00401      */
00402     dvector getScoreProgressSequence() {
00403       return scoreSequence;
00404     }
00405 
00406     /**
00407      * copy data of "other" functor.
00408      * @param other the functor to be copied
00409      * @return a reference to this functor object
00410      */
00411     hmmTrainer& copy(const hmmTrainer& other);
00412 
00413     /**
00414      * alias for copy member
00415      * @param other the functor to be copied
00416      * @return a reference to this functor object
00417      */
00418     hmmTrainer& operator=(const hmmTrainer& other);
00419 
00420     /**
00421      * returns a pointer to a clone of this functor.
00422      */
00423     virtual functor* clone() const;
00424 
00425     /**
00426      * returns used parameters
00427      */
00428     const parameters& getParameters() const;
00429 
00430     //TODO: comment the attributes of your functor
00431     // If you add more attributes manually, do not forget to do following:
00432     // 1. indicate in the default constructor the default values
00433     // 2. make sure that the copy member also copy your new attributes, or
00434     //    to ensure there, that these attributes are properly initialized.
00435 
00436 
00437   private:
00438 
00439     /**
00440      * this private class defines an assignment of frames to a density
00441      * overall scores of the density are also saved here
00442      */
00443     class densityAssignment {
00444     public:
00445 
00446       /**
00447        * pointer to the frames (observations) assigned to this density
00448        */
00449       std::vector<const dvector *> frames;
00450 
00451       /**
00452        * calculated density center is written here.
00453        */
00454       hiddenMarkovModel::singleDensity center;
00455 
00456       /**
00457        * average score for this density
00458        */
00459       double score;
00460     };
00461 
00462     /**
00463      * assignment of densities to a state
00464      */
00465     typedef std::vector<densityAssignment> stateAssignment;
00466 
00467     /**
00468      * improve given model with respect to the training sequences
00469      * (might become public)
00470      */
00471     double improveModel(hiddenMarkovModel &model, bool split);
00472 
00473     /**
00474      * change state number, assign frames to state/density in a linear fashion
00475      */
00476     void initializeAssignments();
00477 
00478     /**
00479      * clears all assignments of densities/frames (does not change the
00480      * number of states or densities)
00481      */
00482     void clearAssignments();
00483 
00484     /**
00485      * initialize the model
00486      */
00487     void initializeModel(hiddenMarkovModel &model);
00488 
00489     /**
00490      * copy parameters and modify them if necessary
00491      */
00492     void copyParameters();
00493 
00494     /**
00495      * calculate transition matrix, i.e. do smoothing and -log()
00496      */
00497     void calculateTransitionMatrix(matrix<double> &transitionScore);
00498 
00499     /**
00500      * test model on training data, return average score
00501      */
00502     double evaluateModel(const hiddenMarkovModel &model);
00503 
00504     /**
00505      * create model from the current transitions and assignments
00506      */
00507     void createModel(hiddenMarkovModel &model);
00508 
00509     /**
00510      * calculate mean values and variances
00511      */
00512     void calculateDensities();
00513 
00514     /**
00515      * calculate single density
00516      */
00517     void calculateThisDensity(densityAssignment &theDensity);
00518 
00519     /**
00520      * calculate transition scores from the viterbi search
00521      * return achieved score
00522      */
00523     double considerTrainingSequence(const hiddenMarkovModel &lastModel,
00524                                     const sequence<dvector> &theSeq);
00525 
00526     /**
00527      * divide emission scores by number of assigned frames
00528      * (i.e. number of emissions)
00529      */
00530     void normalizeEmissionScores();
00531 
00532     /**
00533      * check density scores and split if appropriate
00534      * return true, if new densities were actually created
00535      */
00536     bool splitDensities();
00537 
00538     /**
00539      * split one density center by disturbance of the center
00540      */
00541     void splitThisDensity(densityAssignment &thisDensity,
00542                           densityAssignment &newDensity);
00543 
00544     /**
00545      * delete empty densities and states
00546      */
00547     void garbageCollection();
00548 
00549     /**
00550      * delete state with the given number
00551      */
00552     void deleteState(const int stateNumber);
00553 
00554     /**
00555      * delete state with the given number
00556      */
00557     void deleteDensity(const int stateNumber, const int densityCenter);
00558 
00559     /**
00560      * viterbi path search
00561      */
00562     hmmViterbiPathSearch viterbi;
00563 
00564     /**
00565      * training data will be saved here
00566      */
00567     sequence< sequence<dvector> > theTrainingData;
00568 
00569     /**
00570      * assignments of all states and densities
00571      * assignedFrames[state][density]
00572      */
00573     std::vector<stateAssignment> assignedFrames;
00574 
00575     /**
00576      * score sequence is saved here by apply
00577      */
00578     dvector scoreSequence;
00579 
00580 
00581 
00582     /**
00583      * length of the shortest sequence will be saved here
00584      */
00585     int minSequenceLength;
00586 
00587     /**
00588      * total number of frames in all considered sequences is saved
00589      * here to quickly calculate the average sequence length, if
00590      * needed.
00591      */
00592     int totalFramesInSequences;
00593 
00594     /**
00595      * temporary copy of parameters
00596      */
00597     parameters params;
00598 
00599     /**
00600      * feature dimension.
00601      * will be saved here by the first call to consider.
00602      * sequences will then be checked for consecutive calls to consider.
00603      */
00604     int featureDimension;
00605 
00606     /**
00607      * feature weights
00608      */
00609     dvector featureWeights;
00610 
00611     /**
00612      * transition frequency
00613      * for every transition from state i to j, trans[i][j] is increased.
00614      * calculateTransitionMatrix creates score matrix from this matrix
00615      */
00616     matrix<int> transitionFrequency;
00617 
00618 
00619     // calculation of mean and scaling factor (i.e. deviation etc.)
00620 
00621     /**
00622      * calculate mean
00623      */
00624     void calculateDensityCenter(const std::vector<const dvector *> &frames,
00625                                       dvector &mean) const;
00626 
00627     /**
00628      * reset scaling factor calculation
00629      */
00630     void resetScaleCalculation();
00631 
00632     /**
00633      * scaling factor calculation: take vector into consideration
00634      */
00635     void considerScale(const dvector &mean, dvector vec);
00636 
00637     /**
00638      * calculate scaling factor from considered vectors
00639      */
00640     void calculateScale(dvector &deviation);
00641 
00642     // scale calculation variables
00643     dvector scaleVector;
00644     int scaleConsidered;
00645 
00646   };
00647 }
00648 
00649 #endif

Generated on Sat Apr 10 15:25:38 2010 for LTI-Lib by Doxygen 1.6.1