comparison trunk/src/Modules/Features/ModuleGaussians.cc @ 268:e14c70d1b171

- Initial add of support code and modules. Not everything is working yet.
author tomwalters
date Fri, 12 Feb 2010 12:31:23 +0000
parents
children c26222c51fb7
comparison
equal deleted inserted replaced
-1:000000000000 268:e14c70d1b171
1 // Copyright 2008-2010, Thomas Walters
2 //
3 // AIM-C: A C++ implementation of the Auditory Image Model
4 // http://www.acousticscale.org/AIMC
5 //
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19 /*! \file
20 * \brief Gaussian features - based on MATLAB code by Christian Feldbauer
21 */
22
23 /*!
24 * \author Tom Walters <tcw24@cam.ac.uk>
25 * \date created 2008/06/23
26 * \version \$Id: ModuleGaussians.cc 2 2010-02-02 12:59:50Z tcw $
27 */
28
29 #include <math.h>
30
31 #include "Modules/Features/ModuleGaussians.h"
32 #include "Support/Common.h"
33
34 namespace aimc {
35 ModuleGaussians::ModuleGaussians(Parameters *pParam)
36 : Module(pParam) {
37 // Set module metadata
38 module_description_ = "Gaussian Fitting to SSI profile";
39 module_identifier_ = "gaussians"; // unique identifier for the module
40 module_type_ = "features";
41 module_version_ = "$Id: ModuleGaussians.cc 2 2010-02-02 12:59:50Z tcw $";
42
43 parameters_->SetDefault("features.gaussians.ncomp", "4");
44 m_iParamNComp = parameters_->GetInt("features.gaussians.ncomp");
45
46 parameters_->SetDefault("features.gaussians.var", "115.0");
47 m_fParamVar = parameters_->GetFloat("features.gaussians.var");
48
49 parameters_->SetDefault("features.gaussians.posterior_exp", "6.0");
50 m_fParamPosteriorExp =
51 parameters_->GetFloat("features.gaussians.posterior_exp");
52
53 parameters_->SetDefault("features.gaussians.maxit", "250");
54 m_iParamMaxIt = parameters_->GetInt("features.gaussians.maxit");
55
56 parameters_->SetDefault("features.gaussians.priors_converged", "1e-7");
57 m_fParamPriorsConverged =
58 parameters_->GetInt("features.gaussians.priors_converged");
59 }
60
61 ModuleGaussians::~ModuleGaussians() {
62 }
63
64 bool ModuleGaussians::InitializeInternal(const SignalBank &input) {
65 m_pA.resize(m_iParamNComp, 0.0f);
66 m_pMu.resize(m_iParamNComp, 0.0f);
67
68 // Assuming the number of channels is greater than twice the number of
69 // Gaussian components, this is ok
70 if (input.channel_count() >= 2 * m_iParamNComp) {
71 output_.Initialize(1, m_iParamNComp, input.sample_rate());
72 } else {
73 LOG_ERROR(_T("Too few channels in filterbank to produce sensible "
74 "Gaussian features. Either increase the number of filterbank"
75 " channels, or decrease the number of Gaussian components"));
76 return false;
77 }
78
79 m_iNumChannels = input.channel_count();
80 m_pSpectralProfile.resize(m_iNumChannels, 0.0f);
81
82 return true;
83 }
84
85 void ModuleGaussians::Reset() {
86 m_pSpectralProfile.clear();
87 m_pSpectralProfile.resize(m_iNumChannels, 0.0f);
88 }
89
90 void ModuleGaussians::Process(const SignalBank &input) {
91 int iAudCh = 0;
92
93 // Calculate spectral profile
94 for (int iChannel = 0;
95 iChannel < input.channel_count();
96 ++iChannel) {
97 m_pSpectralProfile[iChannel] = 0.0f;
98 for (int iSample = 0;
99 iSample < input.buffer_length();
100 ++iSample) {
101 m_pSpectralProfile[iChannel] += input[iChannel][iSample];
102 }
103 }
104
105 for (int iChannel = 0;
106 iChannel < input.channel_count();
107 ++iChannel) {
108 m_pSpectralProfile[iChannel] = pow(m_pSpectralProfile[iChannel], 0.8);
109 }
110
111 float spectral_profile_sum = 0.0f;
112 for (int i = 0; i < input.channel_count(); ++i) {
113 spectral_profile_sum += m_pSpectralProfile[i];
114 }
115
116 RubberGMMCore(2, true);
117
118 float fMean1 = m_pMu[0];
119 float fMean2 = m_pMu[1];
120
121 float fA1 = 0.05 * m_pA[0];
122 float fA2 = 1.0 - 0.25 * m_pA[1];
123
124 float fGradient = (fMean2 - fMean1) / (fA2 - fA1);
125 float fIntercept = fMean2 - fGradient * fA2;
126
127 for (int i = 0; i < m_iParamNComp; ++i) {
128 m_pMu[i] = ((float)i / (float)m_iParamNComp - 1.0f)
129 * -fGradient + fIntercept;
130 }
131
132 for (int i = 0; i < m_iParamNComp; ++i) {
133 m_pA[i] = 1.0f / (float)m_iParamNComp;
134 }
135
136 RubberGMMCore(m_iParamNComp, false);
137
138 for (int i = 0; i < m_iParamNComp - 1; ++i) {
139 if (!isnan(m_pA[i])) {
140 output_.set_sample(i, 0, m_pA[i]);
141 } else {
142 output_.set_sample(i, 0, 0.0f);
143 }
144 }
145 /*for (int i = m_iParamNComp; i < m_iParamNComp * 2; ++i) {
146 m_pOutputData->getSignal(i)->setSample(iAudCh, 0, m_pMu[i-m_iParamNComp]);
147 }*/
148 double logsum = log(spectral_profile_sum);
149 if (!isinf(logsum)) {
150 output_.set_sample(m_iParamNComp - 1, 0, logsum);
151 } else {
152 output_.set_sample(m_iParamNComp - 1, 0, -1000.0);
153 }
154 PushOutput();
155 }
156
157 bool ModuleGaussians::RubberGMMCore(int iNComponents, bool bDoInit) {
158 int iSizeX = m_iNumChannels;
159
160 // Normalise the spectral profile
161 float fSpectralProfileTotal = 0.0f;
162 for (int iCount = 0; iCount < iSizeX; iCount++) {
163 fSpectralProfileTotal += m_pSpectralProfile[iCount];
164 }
165 for (int iCount = 0; iCount < iSizeX; iCount++) {
166 m_pSpectralProfile[iCount] /= fSpectralProfileTotal;
167 }
168
169 if (bDoInit) {
170 // Uniformly spaced components
171 float dd = (iSizeX - 1.0f) / iNComponents;
172 for (int i = 0; i < iNComponents; i++) {
173 m_pMu[i] = dd / 2.0f + (i * dd);
174 m_pA[i] = 1.0f / iNComponents;
175 }
176 }
177
178 vector<float> pA_old;
179 pA_old.resize(iNComponents);
180 vector<float> pP_mod_X;
181 pP_mod_X.resize(iSizeX);
182 vector<float> pP_comp;
183 pP_comp.resize(iSizeX * iNComponents);
184
185 for (int iIteration = 0; iIteration < m_iParamMaxIt; iIteration++) {
186 // (re)calculate posteriors (component probability given observation)
187 // denominator: the model density at all observation points X
188 for (int i = 0; i < iSizeX; ++i) {
189 pP_mod_X[i] = 0.0f;
190 }
191
192 for (int i = 0; i < iNComponents; i++) {
193 for (int iCount = 0; iCount < iSizeX; iCount++) {
194 pP_mod_X[iCount] += 1.0f / sqrt(2.0f * M_PI * m_fParamVar)
195 * exp((-0.5f) * pow(((float)iCount-m_pMu[i]), 2)
196 / m_fParamVar) * m_pA[i];
197 }
198 }
199
200 for (int i = 0; i < iSizeX * iNComponents; ++i) {
201 pP_comp[i] = 0.0f;
202 }
203
204 for (int i = 0; i < iNComponents; i++) {
205 for (int iCount = 0; iCount < iSizeX; iCount++) {
206 pP_comp[iCount + i * iSizeX] =
207 1.0f / sqrt(2.0f * M_PI * m_fParamVar)
208 * exp((-0.5f) * pow(((float)iCount - m_pMu[i]), 2) / m_fParamVar);
209 pP_comp[iCount + i * iSizeX] =
210 pP_comp[iCount + i * iSizeX] * m_pA[i] / pP_mod_X[iCount];
211 }
212 }
213
214 for (int iCount = 0; iCount < iSizeX; ++iCount) {
215 float fSum = 0.0f;
216 for (int i = 0; i < iNComponents; ++i) {
217 pP_comp[iCount+i*iSizeX] = pow(pP_comp[iCount + i * iSizeX],
218 m_fParamPosteriorExp); // expansion
219 fSum += pP_comp[iCount+i*iSizeX];
220 }
221 for (int i = 0; i < iNComponents; ++i)
222 pP_comp[iCount+i*iSizeX] = pP_comp[iCount + i * iSizeX] / fSum;
223 // renormalisation
224 }
225
226 for (int i = 0; i < iNComponents; ++i) {
227 pA_old[i] = m_pA[i];
228 m_pA[i] = 0.0f;
229 for (int iCount = 0; iCount < iSizeX; ++iCount) {
230 m_pA[i] += pP_comp[iCount + i * iSizeX] * m_pSpectralProfile[iCount];
231 }
232 }
233
234 // finish when already converged
235 float fPrdist = 0.0f;
236 for (int i = 0; i < iNComponents; ++i) {
237 fPrdist += pow((m_pA[i] - pA_old[i]), 2);
238 }
239 fPrdist /= iNComponents;
240
241 if (fPrdist < m_fParamPriorsConverged) {
242 LOG_INFO("Converged!");
243 break;
244 }
245
246 // update means (positions)
247 for (int i = 0 ; i < iNComponents; ++i) {
248 float mu_old = m_pMu[i];
249 if (m_pA[i] > 0.0f) {
250 m_pMu[i] = 0.0f;
251 for (int iCount = 0; iCount < iSizeX; ++iCount) {
252 m_pMu[i] += m_pSpectralProfile[iCount]
253 * pP_comp[iCount + i * iSizeX] * (float)iCount;
254 }
255 m_pMu[i] /= m_pA[i];
256 if (isnan(m_pMu[i])) {
257 m_pMu[i] = mu_old;
258 }
259 }
260 }
261 } // loop over iterations
262
263 // Ensure they are sorted, using a really simple bubblesort
264 bool bSorted = false;
265 while (!bSorted) {
266 bSorted = true;
267 for (int i = 0; i < iNComponents - 1; ++i) {
268 if (m_pMu[i] > m_pMu[i + 1]) {
269 float fTemp = m_pMu[i];
270 m_pMu[i] = m_pMu[i + 1];
271 m_pMu[i + 1] = fTemp;
272 fTemp = m_pA[i];
273 m_pA[i] = m_pA[i + 1];
274 m_pA[i + 1] = fTemp;
275 bSorted = false;
276 }
277 }
278 }
279 return true;
280 }
281 } //namespace aimc
282