Marsyas  0.6.0-alpha
/usr/src/RPM/BUILD/marsyas-0.6.0/src/marsyas/QGMMModel.cpp
Go to the documentation of this file.
00001 /*
00002 ** Copyright (C) 1998-2006 George Tzanetakis <gtzan@cs.uvic.ca>
00003 **
00004 ** This program is free software; you can redistribute it and/or modify
00005 ** it under the terms of the GNU General Public License as published by
00006 ** the Free Software Foundation; either version 2 of the License, or
00007 ** (at your option) any later version.
00008 **
00009 ** This program is distributed in the hope that it will be useful,
00010 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 ** GNU General Public License for more details.
00013 **
00014 ** You should have received a copy of the GNU General Public License
00015 ** along with this program; if not, write to the Free Software
00016 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017 */
00018 
00019 #include "QGMMModel.h"
00020 #include <marsyas/NumericLib.h>
00021 
00022 using namespace std;
00023 using namespace Marsyas;
00024 
00025 //***********************************************************************************************
00026 // class QGMMModel
00027 //***********************************************************************************************
00028 QGMMModel::QGMMModel()
00029 {
00030   resetModel();
00031 }
00032 
00033 QGMMModel::QGMMModel(const QGMMModel &a)
00034 {
00035   maxNrGSMixes_ = a.maxNrGSMixes_;
00036   nrGSMixes_ = a.nrGSMixes_;
00037   GSmixNrFrames_ = a.GSmixNrFrames_;
00038   GSmixCovMatrix_ = a.GSmixCovMatrix_;
00039   totalNrFrames_ = a.totalNrFrames_;
00040 
00041   divergenceThres_ = a.divergenceThres_;
00042 }
00043 QGMMModel::~QGMMModel()
00044 {
00045 
00046 }
00047 
00048 void
00049 QGMMModel::resetModel()
00050 {
00051   maxNrGSMixes_ = 32;
00052   nrGSMixes_ = 0;
00053   GSmixNrFrames_.clear();
00054   GSmixCovMatrix_.clear();
00055   totalNrFrames_ = 0;
00056   divergenceThres_ = 0.50; // [!]
00057 }
00058 
00059 realvec
00060 QGMMModel::updateCovModel(realvec C, mrs_natural N, realvec Cm, mrs_natural Nm)
00061 {
00062   C *=  ((mrs_real)N / (mrs_real)(N+Nm));
00063   Cm *= ((mrs_real)Nm / (mrs_real)(N+Nm));
00064   C += Cm;
00065 
00066   return C;
00067 }
00068 
00069 void
00070 QGMMModel::updateModel(realvec &covMatrix, mrs_natural nrModelFrames)
00071 {
00072   static mrs_real meanDiv, count;
00073   static bool stopUpdate;
00074 
00078 //  if(nrGSMixes_ == 0)
00079 //  {
00080 //      nrGSMixes_++;
00081 //      GSmixCovMatrix_.push_back(covMatrix);
00082 //      GSmixNrFrames_.push_back(nrModelFrames);
00083 //      totalNrFrames_ = nrModelFrames;
00084 //      return;
00085 //  }
00086 //  else
00087 //  {
00088 //      //do not update - replace using the most recent segment data...
00089 //      GSmixCovMatrix_[0] = covMatrix;
00090 //      GSmixNrFrames_[0] = nrModelFrames;
00091 //      totalNrFrames_ = nrModelFrames;
00092 //      return;
00093 //  }
00095 
00096   //if this is the first time the model gets speaker data
00097   //create first mixture with that data
00098   if(nrGSMixes_ == 0)
00099   {
00100     meanDiv = 0;
00101     count = 0;
00102     stopUpdate = false;
00103 
00104     nrGSMixes_++;
00105     GSmixCovMatrix_.push_back(covMatrix);
00106     GSmixNrFrames_.push_back(nrModelFrames);
00107     totalNrFrames_ = nrModelFrames;
00108 
00109     return;
00110   }
00111   //otherwise update current speaker model or create a new mix...
00112   else
00113   {
00114     mrs_natural curMix = nrGSMixes_ - 1;
00115 
00116     //calculate updated model using the new speaker data
00117     realvec updatedModel = updateCovModel(GSmixCovMatrix_[curMix], GSmixNrFrames_[curMix],
00118                                           covMatrix, nrModelFrames);
00119 
00120     //calculate the divergence between the current model and the updated one
00121     mrs_real divergenceShape = NumericLib::divergenceShape(GSmixCovMatrix_[curMix],updatedModel);
00122 
00123     //recursive mean divergenceShape calculation
00124     meanDiv = meanDiv + 1/(count+1)*(divergenceShape - meanDiv);
00125     count++;
00126 
00127     //if the updated model has a big enough dissimilarity when compared
00128     //with current model, update current model...
00129     if (divergenceShape > meanDiv*divergenceThres_ && stopUpdate == false)
00130     {
00131       GSmixCovMatrix_[curMix] = updatedModel;
00132       GSmixNrFrames_[curMix] += nrModelFrames;
00133       totalNrFrames_ += nrModelFrames;
00134     }
00135     //...if the updated model is very similar to the current one (i.e. divergence distnace < threshold)
00136     //give up updating and create instead a new mixture...
00137     else
00138     {
00139       if (nrGSMixes_ < maxNrGSMixes_)
00140       {
00141         nrGSMixes_++;
00142         GSmixCovMatrix_.push_back(covMatrix);
00143         GSmixNrFrames_.push_back(nrModelFrames);
00144         totalNrFrames_ += nrModelFrames;
00145 
00146         meanDiv = 0;
00147         count = 0;
00148       }
00149       else
00150       {
00151         stopUpdate = true;
00152       }
00153     }
00154   }
00155 }
00156 
00157 mrs_real
00158 QGMMModel::deltaBIC(realvec C1, mrs_natural N1, realvec C2, mrs_natural N2, realvec C, mrs_real lambda)
00159 {
00160   //matrices should be square and equal sized
00161   if(C1.getCols() != C2.getCols() && C1.getCols() != C.getCols() &&
00162       C1.getCols()!= C1.getRows())
00163   {
00164     MRSERR("QGMMModel:deltaBIC: matrices should all be squared and equal sized...");
00165     return MAXREAL; //just a way to sinalize the above error... [!]
00166   }
00167 
00168   mrs_real res;
00169   mrs_real N = (mrs_real)(N1 + N2);
00170   mrs_real d = (mrs_real)C1.getCols();
00171 
00172 
00173   res = N * log(C.det());
00174   res -= (mrs_real)N1 * log(C1.det());
00175   res -= (mrs_real)N2 * log(C2.det());
00176   res *= 0.5f;
00177 
00178   res -= 0.5f * lambda * (d + 0.5f*d*(d+1.0f))* log(N);
00179 
00180   return res;
00181 }
00182 
00183 mrs_real
00184 QGMMModel::BICdistance(realvec &covMatrix, mrs_natural Nframes, mrs_real lambda)
00185 {
00186   mrs_real wi;
00187   mrs_real res = 0;
00188 
00189   //mrs_real d = (mrs_real)covMatrix.getCols();
00190 
00191   //mrs_natural curMix = nrGSMixes_ - 1;
00192 
00193   for(mrs_natural i = 0; i < nrGSMixes_; ++i)
00194   {
00195     realvec combinedModel = updateCovModel(GSmixCovMatrix_[i],GSmixNrFrames_[i],
00196                                            covMatrix, Nframes);
00197 
00198     wi = (mrs_real)GSmixNrFrames_[i]/(mrs_real)totalNrFrames_;
00199     res += wi * deltaBIC(GSmixCovMatrix_[i], GSmixNrFrames_[i], covMatrix, Nframes, combinedModel, lambda);
00200   }
00201 
00202   return res;
00203 }