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

ltiGaussianMixtureModel.h

00001 /*
00002  * Copyright (C) 2000, 2001, 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 /*----------------------------------------------------------------
00025  * project ....: LTI Digital Image/Signal Processing Library
00026  * file .......: ltiGaussianMixtureModel.h
00027  * authors ....: Jochen Wickel
00028  * organization: LTI, RWTH Aachen
00029  * creation ...: 25.9.2000
00030  * revisions ..: $Id: ltiGaussianMixtureModel.h,v 1.11 2006/02/08 12:23:56 ltilib Exp $
00031  */
00032 
00033 #ifndef _LTI_GAUSSIAN_MIXTURE_MODEL_H_
00034 #define _LTI_GAUSSIAN_MIXTURE_MODEL_H_
00035 
00036 #include "ltiConfig.h"
00037 #include "ltiStatisticsFunctor.h"
00038 #include "ltiMeansFunctor.h"
00039 #include "ltiVarianceFunctor.h"
00040 #include "ltiMatrixInversion.h"
00041 #include "ltiL2Distance.h"
00042 #include "ltiProgressInfo.h"
00043 #include "ltiMatrixDecomposition.h"
00044 
00045 
00046 #ifdef _LTI_WIN32
00047 #define random rand
00048 #endif
00049 
00050 
00051 namespace lti {
00052   /**
00053    * Functor which estimates a gaussian mixture model of a given data set.
00054    * See documentation of the apply() methods for details.
00055    * Please note that, even though this is a template class, it does not
00056    * make much sense to use it with anything but floating-point types.
00057    * The higher the precision, the better. So, if you use
00058    * gaussianMixtureModel<float> and get crappy results, you should not
00059    * wonder. If you get reasonable results, you're just lucky.
00060    * Other template arguments than float or double probably won't even
00061    * compile.
00062    */
00063   template <class T> class gaussianMixtureModel : public statisticsFunctor {
00064   public:
00065     /**
00066      * The parameters for the class gaussianMixtureModel
00067      */
00068     class parameters : public statisticsFunctor::parameters {
00069     public:
00070       /**
00071        * Default constructor
00072        */
00073       parameters()
00074         : statisticsFunctor::parameters() {
00075         partialIterations=50;
00076         iterations=100;
00077         forceIterations=false;
00078         numberOfComponents=3;
00079         useSM=false;
00080         lambda=T(0.1);
00081         emergencyLambda=T(0.1);
00082         cMax=5;
00083         epsilon=T(0.2);
00084         reportProgress=false;
00085       };
00086 
00087       /**
00088        * copy constructor
00089        * @param other the parameters object to be copied
00090        */
00091       parameters(const parameters& other) 
00092         : statisticsFunctor::parameters() {
00093         copy(other);
00094       };
00095 
00096       /**
00097        * destructor
00098        */
00099       ~parameters() {
00100       };
00101 
00102       /**
00103        * returns name of this type
00104        */
00105       const char* getTypeName() const {
00106         return "gaussianMixtureModel::parameters";
00107       };
00108 
00109       /**
00110        * copy the contents of a parameters object
00111        * @param other the parameters object to be copied
00112        * @return a reference to this parameters object
00113        */
00114       parameters& copy(const parameters& other) {
00115 #       ifndef _LTI_MSC_6
00116         // MS Visual C++ 6 is not able to compile this...
00117         statisticsFunctor::parameters::copy(other);
00118 #       else
00119         // ...so we have to use this workaround.
00120         // Conditional on that, copy may not be virtual.
00121         statisticsFunctor::parameters&
00122           (statisticsFunctor::parameters::* p_copy)
00123           (const statisticsFunctor::parameters&) =
00124           statisticsFunctor::parameters::copy;
00125         (this->*p_copy)(other);
00126 #      endif
00127 
00128         numberOfComponents=other.numberOfComponents;
00129         partialIterations=other.partialIterations;
00130         iterations=other.iterations;
00131         forceIterations=other.forceIterations;
00132         useSM=other.useSM;
00133         lambda=other.lambda;
00134         emergencyLambda=other.emergencyLambda;
00135         cMax=other.cMax;
00136         epsilon=other.epsilon;
00137         reportProgress=other.reportProgress;
00138         return *this;
00139       };
00140 
00141 #     ifndef _LTI_MSC_6
00142         /**
00143          * write the parameters in the given ioHandler
00144          * @param handler the ioHandler to be used
00145          * @param complete if true (the default) the enclosing begin/end will
00146          *        be also written, otherwise only the data block will be
00147          *        written.
00148          * @return true if write was successful
00149          */
00150         virtual bool write(ioHandler& handler,const bool complete=true) const
00151 #     else
00152         /**
00153          * workaround for MS-VC bug.  Never use this method directly,
00154          * use write() instead
00155          */
00156         bool writeMS(ioHandler& handler,const bool complete=true) const
00157 #     endif
00158         {
00159           bool b = true;
00160           if (complete) {
00161             b = handler.writeBegin();
00162           }
00163 
00164           if (b) {
00165             lti::write(handler,"numberOfComponents",numberOfComponents);
00166             lti::write(handler,"iterations",iterations);
00167             lti::write(handler,"forceIterations",iterations);
00168             lti::write(handler,"partialIterations",partialIterations);
00169             lti::write(handler, "useSM", useSM);
00170             lti::write(handler, "lambda", lambda);
00171             lti::write(handler, "emergencyLambda", emergencyLambda);
00172             lti::write(handler, "Cmax", cMax);
00173             lti::write(handler, "epsilon", epsilon);
00174             lti::write(handler, "reportProgress", reportProgress);
00175           }
00176 
00177 #       ifndef _LTI_MSC_6
00178           // This is the standard C++ code, which MS Visual C++ 6 is not
00179           // able to compile...
00180           b = b && statisticsFunctor::parameters::write(handler,false);
00181 #       else
00182           bool (functor::parameters::* p_writeMS)(ioHandler&,
00183                                                    const bool) const =
00184             functor::parameters::writeMS;
00185           b = b && (this->*p_writeMS)(handler,false);
00186 #       endif
00187 
00188           if (complete) {
00189             b = b && handler.writeEnd();
00190           }
00191 
00192           return b;
00193         }
00194 
00195 #     ifdef _LTI_MSC_6
00196         /**
00197          * write the parameters in the given ioHandler
00198          * @param handler the ioHandler to be used
00199          * @param complete if true (the default) the enclosing begin/end will
00200          *        be also written, otherwise only the data block will be
00201          *        written.
00202          * @return true if write was successful
00203          */
00204         virtual bool write(ioHandler& handler,
00205                            const bool complete = true) const {
00206            // ...we need this workaround to cope with another really
00207            // awful MSVC bug.
00208            return writeMS(handler,complete);
00209         }
00210 #     endif
00211 
00212 #     ifndef _LTI_MSC_6
00213         /**
00214          * read the parameters from the given ioHandler
00215          * @param handler the ioHandler to be used
00216          * @param complete if true (the default) the enclosing begin/end will
00217          *        be also read, otherwise only the data block will be read.
00218          * @return true if write was successful
00219          */
00220         virtual bool read(ioHandler& handler,const bool complete = true)
00221 #     else
00222         /**
00223          * workaround for MS-VC bug.  Never use this method directly,
00224          * use read() instead
00225          */
00226         bool readMS(ioHandler& handler,const bool complete=true)
00227 #     endif
00228         {
00229           bool b = true;
00230           if (complete) {
00231             b = handler.readBegin();
00232           }
00233 
00234           if (b) {
00235             lti::read(handler,"numberOfComponents",numberOfComponents);
00236             lti::read(handler,"iterations",iterations);
00237             lti::read(handler,"forceIterations",iterations);
00238             lti::read(handler,"partialIterations",partialIterations);
00239             lti::read(handler, "useSM", useSM);
00240             lti::read(handler, "lambda", lambda);
00241             lti::read(handler, "emergencyLambda", emergencyLambda);
00242             lti::read(handler, "Cmax", cMax);
00243             lti::read(handler, "epsilon", epsilon);
00244             lti::read(handler, "reportProgress", reportProgress);
00245           }
00246 
00247 #     ifndef _LTI_MSC_6
00248           // This is the standard C++ code, which MS Visual C++ 6 is not
00249           // able to compile...
00250           b = b && statisticsFunctor::parameters::read(handler,false);
00251 #     else
00252           bool (functor::parameters::* p_readMS)(ioHandler&,const bool) =
00253           functor::parameters::readMS;
00254           b = b && (this->*p_readMS)(handler,false);
00255 #     endif
00256 
00257 
00258 
00259           if (complete) {
00260             b = b && handler.readEnd();
00261           }
00262 
00263           return b;
00264         }
00265 
00266 #     ifdef _LTI_MSC_6
00267         /**
00268          * read the parameters from the given ioHandler
00269          * @param handler the ioHandler to be used
00270          * @param complete if true (the default) the enclosing begin/end will
00271          *        be also read, otherwise only the data block will be read.
00272          * @return true if write was successful
00273          */
00274         virtual bool read(ioHandler& handler,const bool complete=true) {
00275           // ...we need this workaround to cope with another really awful MSVC
00276           // bug.
00277           return readMS(handler,complete);
00278         }
00279 #      endif
00280 
00281 
00282       /**
00283        * returns a pointer to a clone of the parameters
00284        */
00285       virtual functor::parameters* clone() const {
00286         return new parameters(*this);
00287       };
00288 
00289       /**
00290        * This is the number of components of the mixture.
00291        */
00292       int numberOfComponents;
00293 
00294       /**
00295        * This is the maximum number of iterations that the EM
00296        * algorithm is supposed to be run.
00297        */
00298       int iterations;
00299 
00300       /**
00301        * If this is true, the EM always executes the maximum
00302        * number of iterations, no matter if it converges earlier
00303        * or not.
00304        */
00305       bool forceIterations;
00306 
00307       /**
00308        * This is the maximum number of partial iterations that the SMEM
00309        * algorithm is supposed to be run.
00310        */
00311       int partialIterations;
00312 
00313       /**
00314        * This flag is true, if the estimator should use the
00315        * <a href="http://citeseer.nj.nec.com/ueda99smem.html">Split-and-Merge EM</a>
00316        * algorithm by <a href="http://www.kecl.ntt.co.jp/icl/as/members/ueda/">Ueda</a>,
00317        * <a href="http://www-nkn.ics.nitech.ac.jp/nakano/">Nakano</a>,
00318        * <a href="http://www.db.toronto.edu/~zoubin/">Ghahramani</a>, and
00319        * <a href="http://www.cs.utoronto.ca/~hinton/">Hinton</a>
00320        * (<a href="http://mitpress.mit.edu/NECO/">Neural Computation</a> 12(9), pp. 2109-2128).
00321        */
00322       bool useSM;
00323 
00324 
00325       /**
00326        * If You use the split-and-merge version, this parameter is used as
00327        * the regularization constant. The larger this constant, the more
00328        * a covariance matrix will be drawn to be the identity matrix.
00329        */
00330       T lambda;
00331 
00332       /**
00333        * This is a factor for regularizing the covariance matrices in
00334        * emergencies. An emergency occurs when the determinant of a
00335        * covariance matrix is almost zero (which often occurs due to
00336        * numerical problems). In that case, the diagonal of the
00337        * matrix will be emphasized by this factor, until the
00338        * determinant becomes reasonable.
00339        */
00340       T emergencyLambda;
00341 
00342       /**
00343        * This is the maximum number of split-and-merge trials
00344        * that are done in each SM step.
00345        */
00346       int cMax;
00347 
00348       /**
00349        * The magnitude of the random perturbation of the split
00350        * algorithm.
00351        */
00352       T epsilon;
00353 
00354       /**
00355        * Is true if the functor should report its result to a progress
00356        * info object
00357        */
00358       bool reportProgress;
00359     };
00360 
00361     /**
00362      * default constructor */
00363     gaussianMixtureModel();
00364 
00365     /**
00366      * copy constructor
00367      * @param other the object to be copied
00368      */
00369     gaussianMixtureModel(const gaussianMixtureModel& other);
00370 
00371     /**
00372      * destructor
00373      */
00374     virtual ~gaussianMixtureModel();
00375 
00376     /**
00377      * returns the name of this type ("gaussianMixtureModel")
00378      */
00379     virtual const char* getTypeName() const;
00380 
00381 
00382     /**
00383      * Performs estimation of a gaussian mixture model for the given
00384      * data matrix. The matrix is interpreted as having a data point
00385      * in each row.
00386      * The method uses the Expectation Maximization method; for a really
00387      * nice explanation of the algorithm, see the paper
00388      * <a href="http://ssli.ee.washington.edu/people/bilmes/mypapers/em.ps.gz">
00389      * A Gentle Tutorial of the EM Algorithm and its Application to
00390      * Parameter Estimation for Gaussian Mixture and Hidden Markov Models</a>
00391      * by <a href="http://ssli.ee.washington.edu/people/bilmes/">Jeff Bilmes</a>.
00392      * (published as Technical Report TR-97-021 by the
00393      * <a href="http://www.icsi.berkeley.edu/">International Computer
00394      * Science Institute</a>).
00395      * If the useSM parameter is true, the split-and-merge algorithm by
00396      * <a href="http://citeseer.nj.nec.com/ueda99smem.html">Split-and-Merge EM</a>
00397      * algorithm by <a href="http://www.kecl.ntt.co.jp/icl/as/members/ueda/">Ueda</a>,
00398      * <a href="http://www-nkn.ics.nitech.ac.jp/nakano/">Nakano</a>,
00399      * <a href="http://www.db.toronto.edu/~zoubin/">Ghahramani</a>, and
00400      * <a href="http://www.cs.utoronto.ca/~hinton/">Hinton</a>
00401      * (<a href="http://mitpress.mit.edu/NECO/">Neural Computation</a> 12(9), pp. 2109-2128)
00402      * is used instead.
00403      *
00404      * @param src matrix<T> with the source data, each row is
00405      *            considered a data point.
00406      * @result true if the estimation was successfull.
00407      */
00408     inline bool apply(const matrix<T>& src) {
00409       return estimate(src);
00410     }
00411 
00412     /**
00413      * Equivalent to apply.
00414      * @param src matrix<T> with the source data, each row is
00415      *            considered a data point.
00416      * @result true if the estimation was successfull.
00417      */
00418     bool estimate(const matrix<T>& src);
00419 
00420     /**
00421      * Returns a std::vector of covariance matrices of the
00422      * components. Each vector element is the covariance matrix
00423      * of a model component.
00424      * @result a reference to the component covariance matrices
00425      *         of the last estimation
00426      */
00427     inline const std::vector< matrix<T> >& getComponentSigmas() const {
00428       return sigmas;
00429     };
00430 
00431     /**
00432      * Returns a std::vector of mean vectors of the
00433      * components. Each vector element is the mean vector of
00434      * a model component.
00435      * @result a reference to the component means
00436      *         of the last estimation
00437      */
00438     const std::vector< vector<T> >& getComponentMus() const {
00439       return mus;
00440     };
00441 
00442     /**
00443      * Returns the mixing coefficient vector. Each element
00444      * is the mixing coefficient of a model component. It
00445      * can be viewed as a
00446      * @result a reference to the mixing coefficients
00447      *         of the last estimation
00448      */
00449     const vector<T>& getAlpha() const {
00450       return alpha;
00451     };
00452 
00453     /**
00454      * Copies a std::vector of covariance matrices of the
00455      * components to the given parameter.
00456      * Each vector element is the covariance matrix
00457      * of a model component.
00458      * @param sigs will receive the component covariance matrices
00459      *         of the last estimation
00460      */
00461     void getComponentSigmas(std::vector< matrix<T> >& sigs) const {
00462       sigs=sigmas;
00463     };
00464 
00465     /**
00466      * Copies a std::vector of mean vectors of the
00467      * components to the given parameter.
00468      * Each vector element is the mean vector
00469      * of a model component.
00470      * @param ms will receive the component means
00471      *         of the last estimation
00472      */
00473     void getComponentMus(std::vector< vector<T> >& ms) const {
00474       ms=mus;
00475     };
00476 
00477     /**
00478      * Copies the mixing coefficients to the given parameter.
00479      * Each vector element is the a-priori probability
00480      * of a model component.
00481      * @param a will receive the component mixture coefficients
00482      *         of the last estimation
00483      */
00484     void getAlpha(vector<T>& a) const {
00485       a=alpha;
00486     };
00487 
00488 
00489     /*
00490      * This is exactly as the other apply method, however, with this
00491      * one you pass pointers to already-allocated objects within the
00492      * std::vector. The function only modifies the pointed-to vectors
00493      * and matrices, but not the pointers themselves, and not the
00494      * list.
00495      *
00496      bool apply(const matrix<T>& src,
00497                const std::vector< vector<T>* >& means,
00498                const std::vector< matrix<T>* >& sigmas,
00499                vector<T>& alphas) const;
00500     */
00501 
00502     /**
00503      * copy data of "other" functor.
00504      * @param other the functor to be copied
00505      * @return a reference to this functor object
00506      */
00507     gaussianMixtureModel& copy(const gaussianMixtureModel& other);
00508 
00509     /**
00510      * returns a pointer to a clone of this functor.
00511      */
00512     virtual functor* clone() const;
00513 
00514     /**
00515      * returns used parameters
00516      */
00517     const parameters& getParameters() const;
00518 
00519     /**
00520      * Sets the progress info object.
00521      */
00522     void setProgressInfo(progressInfo& pi);
00523 
00524     /*
00525      * This computes the likelihood of a vector x given this model.
00526      *
00527     T getLikelihood(const vector<T>& x);
00528     */
00529   protected:
00530     // estimates a mixture model by plain EM
00531     bool plainEstimate();
00532     // estimates a mixture model by SMEM
00533     bool smemEstimate();
00534 
00535     // returns the likelihood of x being generated by component k
00536     T getPartialLikelihood(const vector<T>& x, const int k);
00537     // returns the likelihood of x being generated by component k,
00538     // debug version
00539     T getDBGPartialLikelihood(const vector<T>& x, const int k);
00540     // returns the log of the likelihood of x being generated by component k
00541     T getPartialLogLikelihood(const vector<T>& x, const int k);
00542     // returns the log of the likelihood of x being generated by component k,
00543     // debug version
00544     T getDBGPartialLogLikelihood(const vector<T>& x, const int k);
00545 
00546     // performs a full EM step over all components
00547     // if evalQ is true, the quality measure value will be returned in q
00548     bool fullEMStep(bool evalQ, T& q);
00549 
00550     // performs a full EM step over all components
00551     inline bool fullEMStep() {
00552       T q;
00553       return fullEMStep(false,q);
00554     };
00555 
00556     // returns the quality measure value for the mixture; this is the
00557     // objective function which is maximized
00558     // if the result is below zero, all is in order. If it is above
00559     // zero, then you have most probably a crappy estimation
00560     T computeQ();
00561 
00562     // returns the quality measure value for the mixture of
00563     // the components whose indices are given in index.
00564     // This array MUST CONTAIN EXACTLY 3 elements (needed for SMEM)
00565     T updateQ(const int index[]);
00566 
00567     // Performs a partial EM step, considering only the components
00568     // whose indices are given in index.
00569     // This array MUST CONTAIN EXACTLY 3 elements (needed for SMEM)
00570     bool partialEMStep(const int index[], bool evalQ, T& q);
00571 
00572     // Performs a partial EM step, considering only the components
00573     // whose indices are given in index.
00574     // This array MUST CONTAIN EXACTLY 3 elements (needed for SMEM)
00575     inline bool partialEMStep(const int index[]) {
00576       T q;
00577       return partialEMStep(index,false,q);
00578     };
00579 
00580   private:
00581 
00582     // tries to rescue a covariance matrix from singularity
00583     // returns the determinant of the rescued matrix
00584     T rescueMatrix(matrix<T>& victim);
00585 
00586     /**
00587      * Returns a uniformly distributed random number between 0 and a.
00588      */
00589     inline T frand(T a) const {
00590       return (T(random())/T(RAND_MAX))*a;
00591     }
00592 
00593     /**
00594      * This computes the a-posteriori probability matrix p with
00595      * p[l][i]=P(l|xi);
00596      * Therefore, the sum of a row l is the a-posteriori probability of model
00597      * l.
00598      */
00599     void computeP();
00600 
00601     /**
00602      * This computes the a-posteriori probability matrix p with
00603      * p[l][i]=P(l|xi);
00604      * The values of l are given in the parameter. The array must have
00605      * exactly 3 elements.
00606      * Therefore, the sum of a row l is the a-posteriori probability of model
00607      * l.
00608      */
00609     void updateP(const int ijk[]);
00610 
00611     // functors
00612     meansFunctor<T> mean;
00613     matrixInversion<T> inverter;
00614     varianceFunctor<T> var;
00615     luDecomposition<T> luDecomposer;
00616     l2Distance<T> dist;
00617 
00618     // the data for which the model is generated
00619     const matrix<T>* data;
00620 
00621     // the regularizer matrix
00622     matrix<T> regularizer;
00623 
00624     // the mean vectors of the components
00625     std::vector< vector<T> > mus;
00626     // the covariance matrices of the components
00627     std::vector< matrix<T> > sigmas;
00628     // the inverses of the covariance matrices of the components
00629     std::vector< matrix<T> > sigmaInvs;
00630     // the determinants of the covariance matrices of the components
00631     vector<T> dets;
00632     // the a-priori probabilities of the components
00633     vector<T> alpha;
00634     // the a-posteriori probabilities of each data point
00635     // being generated by each component
00636     matrix<T> p;
00637     // number of components and number of data vectors.
00638     int M,N;
00639 
00640     progressInfo* reporter;
00641   };
00642 }
00643 
00644 #endif

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