annotate trunk/src/Modules/Features/ModuleGaussians.cc @ 335:71c438f9daf7

- Scripts for running recognition experiments using AIM-C and HTK to compare MFCCs against features generated with AIM-C
author tomwalters
date Wed, 04 Aug 2010 06:41:56 +0000
parents 0a8e7d0c70dc
children 2f4530363f7a
rev   line source
tomwalters@268 1 // Copyright 2008-2010, Thomas Walters
tomwalters@268 2 //
tomwalters@268 3 // AIM-C: A C++ implementation of the Auditory Image Model
tomwalters@268 4 // http://www.acousticscale.org/AIMC
tomwalters@268 5 //
tomwalters@318 6 // Licensed under the Apache License, Version 2.0 (the "License");
tomwalters@318 7 // you may not use this file except in compliance with the License.
tomwalters@318 8 // You may obtain a copy of the License at
tomwalters@268 9 //
tomwalters@318 10 // http://www.apache.org/licenses/LICENSE-2.0
tomwalters@268 11 //
tomwalters@318 12 // Unless required by applicable law or agreed to in writing, software
tomwalters@318 13 // distributed under the License is distributed on an "AS IS" BASIS,
tomwalters@318 14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
tomwalters@318 15 // See the License for the specific language governing permissions and
tomwalters@318 16 // limitations under the License.
tomwalters@268 17
tomwalters@268 18 /*! \file
tomwalters@268 19 * \brief Gaussian features - based on MATLAB code by Christian Feldbauer
tomwalters@268 20 */
tomwalters@268 21
tomwalters@268 22 /*!
tomwalters@273 23 * \author Thomas Walters <tom@acousticscale.org>
tomwalters@268 24 * \date created 2008/06/23
tomwalters@296 25 * \version \$Id$
tomwalters@268 26 */
tomwalters@268 27
tomwalters@268 28 #include <math.h>
tomwalters@268 29
tomwalters@268 30 #include "Modules/Features/ModuleGaussians.h"
tomwalters@268 31 #include "Support/Common.h"
tomwalters@268 32
tomwalters@268 33 namespace aimc {
tomwalters@278 34 ModuleGaussians::ModuleGaussians(Parameters *params) : Module(params) {
tomwalters@268 35 // Set module metadata
tomwalters@268 36 module_description_ = "Gaussian Fitting to SSI profile";
tomwalters@273 37 module_identifier_ = "gaussians";
tomwalters@268 38 module_type_ = "features";
tomwalters@296 39 module_version_ = "$Id$";
tomwalters@268 40
tomwalters@273 41 m_iParamNComp = parameters_->DefaultInt("features.gaussians.ncomp", 4);
tomwalters@273 42 m_fParamVar = parameters_->DefaultFloat("features.gaussians.var", 115.0);
tomwalters@273 43 m_fParamPosteriorExp =
tomwalters@273 44 parameters_->DefaultFloat("features.gaussians.posterior_exp", 6.0);
tomwalters@273 45 m_iParamMaxIt = parameters_->DefaultInt("features.gaussians.maxit", 250);
tomwalters@268 46
tomwalters@273 47 // The parameters system doesn't support tiny numbers well, to define this
tomwalters@273 48 // variable as a string, then convert it to a float afterwards
tomwalters@273 49 parameters_->DefaultString("features.gaussians.priors_converged", "1e-7");
tomwalters@268 50 m_fParamPriorsConverged =
tomwalters@273 51 parameters_->GetFloat("features.gaussians.priors_converged");
tomwalters@268 52 }
tomwalters@268 53
tomwalters@268 54 ModuleGaussians::~ModuleGaussians() {
tomwalters@268 55 }
tomwalters@268 56
tomwalters@268 57 bool ModuleGaussians::InitializeInternal(const SignalBank &input) {
tomwalters@268 58 m_pA.resize(m_iParamNComp, 0.0f);
tomwalters@268 59 m_pMu.resize(m_iParamNComp, 0.0f);
tomwalters@268 60
tomwalters@268 61 // Assuming the number of channels is greater than twice the number of
tomwalters@268 62 // Gaussian components, this is ok
tomwalters@268 63 if (input.channel_count() >= 2 * m_iParamNComp) {
tomwalters@273 64 output_.Initialize(m_iParamNComp, 1, input.sample_rate());
tomwalters@268 65 } else {
tomwalters@268 66 LOG_ERROR(_T("Too few channels in filterbank to produce sensible "
tomwalters@268 67 "Gaussian features. Either increase the number of filterbank"
tomwalters@268 68 " channels, or decrease the number of Gaussian components"));
tomwalters@268 69 return false;
tomwalters@268 70 }
tomwalters@268 71
tomwalters@268 72 m_iNumChannels = input.channel_count();
tomwalters@268 73 m_pSpectralProfile.resize(m_iNumChannels, 0.0f);
tomwalters@268 74
tomwalters@268 75 return true;
tomwalters@268 76 }
tomwalters@268 77
tomwalters@275 78 void ModuleGaussians::ResetInternal() {
tomwalters@268 79 m_pSpectralProfile.clear();
tomwalters@268 80 m_pSpectralProfile.resize(m_iNumChannels, 0.0f);
tomwalters@292 81 m_pA.clear();
tomwalters@292 82 m_pA.resize(m_iParamNComp, 0.0f);
tomwalters@292 83 m_pMu.clear();
tomwalters@292 84 m_pMu.resize(m_iParamNComp, 0.0f);
tomwalters@268 85 }
tomwalters@268 86
tomwalters@268 87 void ModuleGaussians::Process(const SignalBank &input) {
tomwalters@273 88 if (!initialized_) {
tomwalters@273 89 LOG_ERROR(_T("Module ModuleGaussians not initialized."));
tomwalters@273 90 return;
tomwalters@273 91 }
tomwalters@268 92 // Calculate spectral profile
tomwalters@268 93 for (int iChannel = 0;
tomwalters@268 94 iChannel < input.channel_count();
tomwalters@268 95 ++iChannel) {
tomwalters@268 96 m_pSpectralProfile[iChannel] = 0.0f;
tomwalters@268 97 for (int iSample = 0;
tomwalters@268 98 iSample < input.buffer_length();
tomwalters@268 99 ++iSample) {
tomwalters@268 100 m_pSpectralProfile[iChannel] += input[iChannel][iSample];
tomwalters@268 101 }
tomwalters@280 102 m_pSpectralProfile[iChannel] /= static_cast<float>(input.buffer_length());
tomwalters@273 103 }
tomwalters@273 104
tomwalters@280 105 float spectral_profile_sum = 0.0f;
tomwalters@273 106 for (int i = 0; i < input.channel_count(); ++i) {
tomwalters@273 107 spectral_profile_sum += m_pSpectralProfile[i];
tomwalters@273 108 }
tomwalters@273 109
tomwalters@280 110 float logsum = log(spectral_profile_sum);
tomwalters@273 111 if (!isinf(logsum)) {
tomwalters@273 112 output_.set_sample(m_iParamNComp - 1, 0, logsum);
tomwalters@273 113 } else {
tomwalters@273 114 output_.set_sample(m_iParamNComp - 1, 0, -1000.0);
tomwalters@268 115 }
tomwalters@268 116
tomwalters@268 117 for (int iChannel = 0;
tomwalters@268 118 iChannel < input.channel_count();
tomwalters@268 119 ++iChannel) {
tomwalters@330 120 m_pSpectralProfile[iChannel] = pow(m_pSpectralProfile[iChannel], 0.8f);
tomwalters@268 121 }
tomwalters@268 122
tomwalters@268 123 RubberGMMCore(2, true);
tomwalters@268 124
tomwalters@280 125 float fMean1 = m_pMu[0];
tomwalters@280 126 float fMean2 = m_pMu[1];
tomwalters@280 127 // LOG_INFO(_T("Orig. mean 0 = %f"), m_pMu[0]);
tomwalters@280 128 // LOG_INFO(_T("Orig. mean 1 = %f"), m_pMu[1]);
tomwalters@280 129 // LOG_INFO(_T("Orig. prob 0 = %f"), m_pA[0]);
tomwalters@280 130 // LOG_INFO(_T("Orig. prob 1 = %f"), m_pA[1]);
tomwalters@268 131
tomwalters@280 132 float fA1 = 0.05 * m_pA[0];
tomwalters@280 133 float fA2 = 1.0 - 0.25 * m_pA[1];
tomwalters@268 134
tomwalters@280 135 // LOG_INFO(_T("fA1 = %f"), fA1);
tomwalters@280 136 // LOG_INFO(_T("fA2 = %f"), fA2);
tomwalters@274 137
tomwalters@280 138 float fGradient = (fMean2 - fMean1) / (fA2 - fA1);
tomwalters@280 139 float fIntercept = fMean2 - fGradient * fA2;
tomwalters@274 140
tomwalters@280 141 // LOG_INFO(_T("fGradient = %f"), fGradient);
tomwalters@280 142 // LOG_INFO(_T("fIntercept = %f"), fIntercept);
tomwalters@268 143
tomwalters@268 144 for (int i = 0; i < m_iParamNComp; ++i) {
tomwalters@280 145 m_pMu[i] = (static_cast<float>(i)
tomwalters@280 146 / (static_cast<float>(m_iParamNComp) - 1.0f))
tomwalters@280 147 * fGradient + fIntercept;
tomwalters@280 148 // LOG_INFO(_T("mean %d = %f"), i, m_pMu[i]);
tomwalters@268 149 }
tomwalters@268 150
tomwalters@268 151 for (int i = 0; i < m_iParamNComp; ++i) {
tomwalters@280 152 m_pA[i] = 1.0f / static_cast<float>(m_iParamNComp);
tomwalters@268 153 }
tomwalters@268 154
tomwalters@268 155 RubberGMMCore(m_iParamNComp, false);
tomwalters@268 156
tomwalters@268 157 for (int i = 0; i < m_iParamNComp - 1; ++i) {
tomwalters@268 158 if (!isnan(m_pA[i])) {
tomwalters@268 159 output_.set_sample(i, 0, m_pA[i]);
tomwalters@268 160 } else {
tomwalters@268 161 output_.set_sample(i, 0, 0.0f);
tomwalters@268 162 }
tomwalters@268 163 }
tomwalters@273 164
tomwalters@268 165 PushOutput();
tomwalters@268 166 }
tomwalters@268 167
tomwalters@268 168 bool ModuleGaussians::RubberGMMCore(int iNComponents, bool bDoInit) {
tomwalters@268 169 int iSizeX = m_iNumChannels;
tomwalters@268 170
tomwalters@268 171 // Normalise the spectral profile
tomwalters@280 172 float fSpectralProfileTotal = 0.0f;
tomwalters@268 173 for (int iCount = 0; iCount < iSizeX; iCount++) {
tomwalters@268 174 fSpectralProfileTotal += m_pSpectralProfile[iCount];
tomwalters@268 175 }
tomwalters@268 176 for (int iCount = 0; iCount < iSizeX; iCount++) {
tomwalters@268 177 m_pSpectralProfile[iCount] /= fSpectralProfileTotal;
tomwalters@268 178 }
tomwalters@268 179
tomwalters@268 180 if (bDoInit) {
tomwalters@268 181 // Uniformly spaced components
tomwalters@280 182 float dd = (iSizeX - 1.0f) / iNComponents;
tomwalters@268 183 for (int i = 0; i < iNComponents; i++) {
tomwalters@268 184 m_pMu[i] = dd / 2.0f + (i * dd);
tomwalters@268 185 m_pA[i] = 1.0f / iNComponents;
tomwalters@268 186 }
tomwalters@268 187 }
tomwalters@268 188
tomwalters@280 189 vector<float> pA_old;
tomwalters@268 190 pA_old.resize(iNComponents);
tomwalters@280 191 vector<float> pP_mod_X;
tomwalters@268 192 pP_mod_X.resize(iSizeX);
tomwalters@280 193 vector<float> pP_comp;
tomwalters@268 194 pP_comp.resize(iSizeX * iNComponents);
tomwalters@268 195
tomwalters@268 196 for (int iIteration = 0; iIteration < m_iParamMaxIt; iIteration++) {
tomwalters@268 197 // (re)calculate posteriors (component probability given observation)
tomwalters@268 198 // denominator: the model density at all observation points X
tomwalters@268 199 for (int i = 0; i < iSizeX; ++i) {
tomwalters@268 200 pP_mod_X[i] = 0.0f;
tomwalters@268 201 }
tomwalters@268 202
tomwalters@268 203 for (int i = 0; i < iNComponents; i++) {
tomwalters@268 204 for (int iCount = 0; iCount < iSizeX; iCount++) {
tomwalters@268 205 pP_mod_X[iCount] += 1.0f / sqrt(2.0f * M_PI * m_fParamVar)
tomwalters@280 206 * exp((-0.5f)
tomwalters@280 207 * pow(static_cast<float>(iCount+1) - m_pMu[i], 2)
tomwalters@280 208 / m_fParamVar) * m_pA[i];
tomwalters@268 209 }
tomwalters@268 210 }
tomwalters@268 211
tomwalters@268 212 for (int i = 0; i < iSizeX * iNComponents; ++i) {
tomwalters@268 213 pP_comp[i] = 0.0f;
tomwalters@268 214 }
tomwalters@268 215
tomwalters@268 216 for (int i = 0; i < iNComponents; i++) {
tomwalters@268 217 for (int iCount = 0; iCount < iSizeX; iCount++) {
tomwalters@268 218 pP_comp[iCount + i * iSizeX] =
tomwalters@268 219 1.0f / sqrt(2.0f * M_PI * m_fParamVar)
tomwalters@280 220 * exp((-0.5f) * pow((static_cast<float>(iCount + 1) - m_pMu[i]), 2)
tomwalters@280 221 / m_fParamVar);
tomwalters@268 222 pP_comp[iCount + i * iSizeX] =
tomwalters@268 223 pP_comp[iCount + i * iSizeX] * m_pA[i] / pP_mod_X[iCount];
tomwalters@268 224 }
tomwalters@268 225 }
tomwalters@268 226
tomwalters@268 227 for (int iCount = 0; iCount < iSizeX; ++iCount) {
tomwalters@280 228 float fSum = 0.0f;
tomwalters@268 229 for (int i = 0; i < iNComponents; ++i) {
tomwalters@268 230 pP_comp[iCount+i*iSizeX] = pow(pP_comp[iCount + i * iSizeX],
tomwalters@280 231 m_fParamPosteriorExp); // expansion
tomwalters@268 232 fSum += pP_comp[iCount+i*iSizeX];
tomwalters@268 233 }
tomwalters@268 234 for (int i = 0; i < iNComponents; ++i)
tomwalters@268 235 pP_comp[iCount+i*iSizeX] = pP_comp[iCount + i * iSizeX] / fSum;
tomwalters@268 236 // renormalisation
tomwalters@268 237 }
tomwalters@268 238
tomwalters@268 239 for (int i = 0; i < iNComponents; ++i) {
tomwalters@268 240 pA_old[i] = m_pA[i];
tomwalters@268 241 m_pA[i] = 0.0f;
tomwalters@268 242 for (int iCount = 0; iCount < iSizeX; ++iCount) {
tomwalters@268 243 m_pA[i] += pP_comp[iCount + i * iSizeX] * m_pSpectralProfile[iCount];
tomwalters@268 244 }
tomwalters@268 245 }
tomwalters@268 246
tomwalters@268 247 // finish when already converged
tomwalters@280 248 float fPrdist = 0.0f;
tomwalters@268 249 for (int i = 0; i < iNComponents; ++i) {
tomwalters@268 250 fPrdist += pow((m_pA[i] - pA_old[i]), 2);
tomwalters@268 251 }
tomwalters@268 252 fPrdist /= iNComponents;
tomwalters@268 253
tomwalters@268 254 if (fPrdist < m_fParamPriorsConverged) {
tomwalters@280 255 // LOG_INFO("Converged!");
tomwalters@268 256 break;
tomwalters@268 257 }
tomwalters@280 258 // LOG_INFO("Didn't converge!");
tomwalters@274 259
tomwalters@268 260
tomwalters@268 261 // update means (positions)
tomwalters@268 262 for (int i = 0 ; i < iNComponents; ++i) {
tomwalters@280 263 float mu_old = m_pMu[i];
tomwalters@268 264 if (m_pA[i] > 0.0f) {
tomwalters@268 265 m_pMu[i] = 0.0f;
tomwalters@268 266 for (int iCount = 0; iCount < iSizeX; ++iCount) {
tomwalters@268 267 m_pMu[i] += m_pSpectralProfile[iCount]
tomwalters@280 268 * pP_comp[iCount + i * iSizeX]
tomwalters@280 269 * static_cast<float>(iCount + 1);
tomwalters@268 270 }
tomwalters@268 271 m_pMu[i] /= m_pA[i];
tomwalters@268 272 if (isnan(m_pMu[i])) {
tomwalters@268 273 m_pMu[i] = mu_old;
tomwalters@268 274 }
tomwalters@268 275 }
tomwalters@268 276 }
tomwalters@280 277 } // loop over iterations
tomwalters@268 278
tomwalters@268 279 // Ensure they are sorted, using a really simple bubblesort
tomwalters@268 280 bool bSorted = false;
tomwalters@268 281 while (!bSorted) {
tomwalters@268 282 bSorted = true;
tomwalters@268 283 for (int i = 0; i < iNComponents - 1; ++i) {
tomwalters@268 284 if (m_pMu[i] > m_pMu[i + 1]) {
tomwalters@280 285 float fTemp = m_pMu[i];
tomwalters@268 286 m_pMu[i] = m_pMu[i + 1];
tomwalters@268 287 m_pMu[i + 1] = fTemp;
tomwalters@268 288 fTemp = m_pA[i];
tomwalters@268 289 m_pA[i] = m_pA[i + 1];
tomwalters@268 290 m_pA[i + 1] = fTemp;
tomwalters@268 291 bSorted = false;
tomwalters@268 292 }
tomwalters@268 293 }
tomwalters@268 294 }
tomwalters@268 295 return true;
tomwalters@268 296 }
tomwalters@280 297 } // namespace aimc
tomwalters@268 298