Marsyas
0.6.0-alpha
|
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 }