00001
00002 #ifndef vpdt_update_mog_h_
00003 #define vpdt_update_mog_h_
00004
00005
00006
00007
00008
00009
00010 #include <vpdl/vpdt/vpdt_field_traits.h>
00011 #include <vpdl/vpdt/vpdt_gaussian.h>
00012 #include <vpdl/vpdt/vpdt_mixture_of.h>
00013 #include <vpdl/vpdt/vpdt_update_gaussian.h>
00014 #include <vpdl/vpdt/vpdt_mog_fitness.h>
00015 #include <vpdl/vpdt/vpdt_num_obs.h>
00016 #include <vcl_utility.h>
00017 #include <vcl_cassert.h>
00018
00019
00020
00021 template <class mog_type>
00022 class vpdt_mog_updater
00023 {
00024 public:
00025 typedef mog_type distribution_type;
00026 typedef typename mog_type::field_type field_type;
00027
00028 private:
00029 typedef typename mog_type::component_type gaussian_type;
00030 typedef typename gaussian_type::field_type F;
00031 typedef typename vpdt_field_traits<F>::scalar_type T;
00032
00033 protected:
00034
00035 vpdt_mog_updater(const gaussian_type& init_gaussian,
00036 unsigned int max_cmp = 5)
00037 : init_gaussian_(init_gaussian), max_components_(max_cmp) {}
00038
00039
00040
00041
00042
00043
00044 void insert(mog_type& mixture, const F& sample, T init_weight) const
00045 {
00046
00047
00048
00049 bool removed = false;
00050 while (mixture.num_components() >= max_components_)
00051 {
00052 mixture.remove_last();
00053 removed = true;
00054 }
00055
00056
00057
00058 if (mixture.num_components() > 0)
00059 init_weight /= (1-init_weight)*mixture.norm_const();
00060 else
00061 init_weight = T(1);
00062
00063
00064 init_gaussian_.mean = sample;
00065 mixture.insert(init_gaussian_,init_weight);
00066 }
00067
00068
00069
00070
00071
00072 unsigned int match( const mog_type& mix, const F& sample,
00073 const T& gt2, T& sqr_dist ) const
00074 {
00075 const unsigned int mix_nc = mix.num_components();
00076 for (unsigned int i=0; i<mix_nc; ++i) {
00077 const gaussian_type& g = mix.distribution(i);
00078 sqr_dist = g.sqr_mahal_dist(sample);
00079 if (sqr_dist < gt2)
00080 return i;
00081 }
00082 return mix_nc;
00083 }
00084
00085
00086 mutable gaussian_type init_gaussian_;
00087
00088 unsigned int max_components_;
00089 };
00090
00091
00092
00093
00094
00095
00096 template <class mog_type>
00097 class vpdt_mog_sg_updater : public vpdt_mog_updater<mog_type>
00098 {
00099 public:
00100 typedef typename mog_type::component_type gaussian_type;
00101 typedef typename gaussian_type::field_type F;
00102 typedef typename vpdt_field_traits<F>::scalar_type T;
00103
00104
00105 vpdt_mog_sg_updater(const gaussian_type& init_gaussian,
00106 unsigned int max_cmp = 5,
00107 T g_thresh = T(2.5),
00108 T alpha = T(0.1),
00109 T init_weight = T(0.1),
00110 T min_stdev = T(0.16) )
00111 : vpdt_mog_updater<mog_type>(init_gaussian, max_cmp),
00112 gt2_(g_thresh*g_thresh), alpha_(alpha), init_weight_(init_weight),
00113 min_var_(min_stdev*min_stdev) {}
00114
00115
00116 void operator() ( mog_type& mix, const F& sample ) const
00117 {
00118 this->update(mix, sample, alpha_);
00119 }
00120
00121 protected:
00122
00123
00124 void update( mog_type& mix, const F& sample, T alpha ) const
00125 {
00126 T sqr_dist;
00127 unsigned int i = vpdt_mog_updater<mog_type>::match(mix,sample,gt2_,sqr_dist);
00128 if (i<mix.num_components())
00129 {
00130 gaussian_type& g = mix.distribution(i);
00131
00132
00133 T rho = alpha * vcl_exp(-sqr_dist/2);
00134 if (min_var_ > T(0))
00135 vpdt_update_gaussian(g, rho, sample, min_var_);
00136 else
00137 vpdt_update_gaussian(g, rho, sample);
00138
00139
00140 mix.set_weight(i, mix.weight(i) + alpha/((1-alpha)*mix.norm_const()));
00141 }
00142 else
00143 {
00144 vpdt_mog_updater<mog_type>::insert(mix,sample,init_weight_);
00145 }
00146 mix.sort(vpdt_mog_fitness<gaussian_type>::order);
00147 }
00148
00149
00150 T gt2_;
00151
00152 T alpha_;
00153
00154 T init_weight_;
00155
00156 T min_var_;
00157 };
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168 template <class mog_type>
00169 class vpdt_mog_lee_updater : public vpdt_mog_updater<mog_type>
00170 {
00171 public:
00172 typedef typename mog_type::component_type gaussian_type;
00173 typedef typename gaussian_type::field_type F;
00174 typedef typename vpdt_field_traits<F>::scalar_type T;
00175
00176
00177 vpdt_mog_lee_updater(const gaussian_type& init_gaussian,
00178 unsigned int max_cmp = 5,
00179 T g_thresh = T(2.5),
00180 T min_stdev = T(0.16),
00181 bool use_wta = false )
00182 : vpdt_mog_updater<mog_type>(init_gaussian, max_cmp),
00183 gt2_(g_thresh*g_thresh), min_var_(min_stdev*min_stdev),
00184 use_winner_take_all_(use_wta) {}
00185
00186
00187 void operator() ( mog_type& mix, const F& sample ) const
00188 {
00189 T num_obs = total_num_obs(mix) + 1;
00190 this->update(mix, sample, T(1)/num_obs);
00191 }
00192
00193 protected:
00194
00195
00196 T total_num_obs( const mog_type& mix ) const
00197 {
00198 T num_obs = T(0);
00199 const unsigned int mix_nc = mix.num_components();
00200 for (unsigned int i=0; i<mix_nc; ++i) {
00201 const gaussian_type& g = mix.distribution(i);
00202 num_obs += g.num_observations;
00203 }
00204 return num_obs;
00205 }
00206
00207
00208 vcl_vector<vcl_pair<unsigned int,double> >
00209 matches(const mog_type& mix, const F& sample) const
00210 {
00211 const unsigned int mix_nc = mix.num_components();
00212 double sum_p = 0.0;
00213 vcl_vector<vcl_pair<unsigned int,double> > matchez;
00214
00215 for (unsigned int i=0; i<mix_nc; ++i) {
00216 const gaussian_type& g = mix.distribution(i);
00217 double sqr_dist = g.sqr_mahal_dist(sample);
00218 if (sqr_dist < gt2_)
00219 matchez.push_back(vcl_pair<unsigned int,double>(i,sqr_dist));
00220 }
00221
00222 if (matchez.size() == 1) {
00223 matchez[0].second = 1.0;
00224 }
00225
00226 else if (matchez.size() > 1) {
00227 for (unsigned int j=0; j<matchez.size(); ++j) {
00228 unsigned int& i = matchez[j].first;
00229 double& p = matchez[j].second;
00230 const gaussian_type& g = mix.distribution(i);
00231 p = mix.weight(i) * g.norm_const() * vcl_exp(-p/2);
00232 sum_p += p;
00233 }
00234
00235 for (unsigned int j=0; j<matchez.size(); ++j) {
00236 matchez[j].second /= sum_p;
00237 }
00238 }
00239 return matchez;
00240 }
00241
00242
00243
00244 void winner_take_all(vcl_vector<vcl_pair<unsigned int,double> >& m) const
00245 {
00246 double max_p = m[0].second;
00247 unsigned int max_j = 0;
00248 for (unsigned int j=1; j<m.size(); ++j) {
00249 if (m[j].second > max_p) {
00250 max_p = m[j].second;
00251 max_j = j;
00252 }
00253 }
00254 m[0].first = m[max_j].first;
00255 m[0].second = 1.0;
00256 m.resize(1);
00257 }
00258
00259
00260 void update( mog_type& mix, const F& sample, T alpha ) const
00261 {
00262 const unsigned int mix_nc = mix.num_components();
00263 if (mix_nc == 0) {
00264 insert(mix,sample,alpha);
00265 return;
00266 }
00267
00268 vcl_vector<vcl_pair<unsigned int,double> > m = matches(mix, sample);
00269
00270 if (!m.empty())
00271 {
00272 if (use_winner_take_all_ && m.size() > 1)
00273 winner_take_all(m);
00274 T w_inc = alpha / ((T(1)-alpha)*mix.norm_const());
00275 for (unsigned int j=0; j<m.size(); ++j) {
00276 unsigned int i = m[j].first;
00277 double p = m[j].second;
00278 gaussian_type& g = mix.distribution(i);
00279 g.num_observations += T(p);
00280 T rho = (T(1)-alpha)/g.num_observations + alpha;
00281 rho *= p;
00282 if (min_var_ > T(0))
00283 vpdt_update_gaussian(g, rho, sample, min_var_);
00284 else
00285 vpdt_update_gaussian(g, rho, sample);
00286
00287
00288 mix.set_weight(i, mix.weight(i)+p*w_inc);
00289 }
00290 }
00291 else
00292 {
00293 insert(mix,sample,alpha);
00294 }
00295 mix.sort(vpdt_mog_fitness<gaussian_type>::order);
00296 }
00297
00298
00299 T gt2_;
00300
00301 T min_var_;
00302
00303
00304 bool use_winner_take_all_;
00305 };
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315 template <class mog_type>
00316 class vpdt_mog_lm_updater : public vpdt_mog_updater<mog_type>
00317 {
00318 public:
00319 typedef typename mog_type::component_type gaussian_type;
00320 typedef typename gaussian_type::field_type F;
00321 typedef typename vpdt_field_traits<F>::scalar_type T;
00322
00323
00324 vpdt_mog_lm_updater(const gaussian_type& init_gaussian,
00325 unsigned int max_cmp = 5,
00326 T g_thresh = T(2.5),
00327 T min_stdev = T(0.16),
00328 unsigned int ws = 300)
00329 : vpdt_mog_updater<mog_type>(init_gaussian, max_cmp),
00330 gt2_(g_thresh*g_thresh), min_var_(min_stdev*min_stdev),
00331 window_size_(ws) {}
00332
00333
00334 void operator() ( mog_type& mix, const F& sample, T sample_weight = T(1) ) const
00335 {
00336 this->update(mix, sample, sample_weight);
00337 }
00338
00339 protected:
00340
00341
00342 T total_weight( const mog_type& mix ) const
00343 {
00344 T tw = T(0);
00345 const unsigned int mix_nc = mix.num_components();
00346 for (unsigned int i=0; i<mix_nc; ++i) {
00347 tw += mix.weight(i);
00348 }
00349 return tw;
00350 }
00351
00352
00353 void update( mog_type& mix, const F& sample, T samp_weight ) const
00354 {
00355 assert(samp_weight > 0.0);
00356 T tw = total_weight(mix);
00357 tw += samp_weight;
00358
00359 T alpha = 1/tw;
00360 T sqr_dist;
00361 unsigned int i = match(mix,sample,gt2_,sqr_dist);
00362 if (i<mix.num_components())
00363 {
00364 gaussian_type& g = mix.distribution(i);
00365 T w = mix.weight(i);
00366 w += samp_weight;
00367 T rho = (T(1)-alpha)/w + alpha;
00368 if (min_var_ > T(0))
00369 vpdt_update_gaussian(g, rho, sample, min_var_);
00370 else
00371 vpdt_update_gaussian(g, rho, sample);
00372 mix.set_weight(i,w);
00373 }
00374 else
00375 {
00376 insert(mix,sample,alpha);
00377 }
00378
00379 if (tw > window_size_) {
00380 T scale = window_size_ / tw;
00381 const unsigned int mix_nc = mix.num_components();
00382 for (unsigned int i=0; i<mix_nc; ++i) {
00383 mix.set_weight(i, mix.weight(i)*scale);
00384 }
00385 }
00386 mix.sort(vpdt_mog_fitness<gaussian_type>::order);
00387 }
00388
00389
00390 T gt2_;
00391
00392 T min_var_;
00393
00394 unsigned int window_size_;
00395 };
00396
00397
00398 #endif // vpdt_update_mog_h_