Learning Curve Plus Plus (LCPP)
paramclass_impl.h
Go to the documentation of this file.
1 /**
2  * @file paramclass_impl.h
3  * @author Ozgur Taylan Turan
4  *
5  * Parametric Classifiers
6  *
7  */
8 
9 #ifndef PARAMCLASS_IMPL_H
10 #define PARAMCLASS_IMPL_H
11 
12 namespace algo {
13 namespace classification {
14 
15 //-----------------------------------------------------------------------------
16 // Linear Discriminant Classifier
17 //-----------------------------------------------------------------------------
18 template<class T>
19 LDC<T>::LDC ( const arma::Mat<T>& inputs,
20  const arma::Row<size_t>& labels,
21  const size_t& num_class ) : num_class_(num_class), lambda_(0.)
22 {
23  Train(inputs, labels);
24 }
25 ///////////////////////////////////////////////////////////////////////////////
26 template<class T>
27 LDC<T>::LDC ( const arma::Mat<T>& inputs,
28  const arma::Row<size_t>& labels,
29  const size_t& num_class,
30  const double& lambda,
31  const arma::Row<T>& priors ) : num_class_(num_class),
32  lambda_(lambda), priors_(priors)
33 {
34  Train(inputs, labels);
35 }
36 ///////////////////////////////////////////////////////////////////////////////
37 template<class T>
38 LDC<T>::LDC ( const arma::Mat<T>& inputs,
39  const arma::Row<size_t>& labels,
40  const size_t& num_class,
41  const double& lambda ) : num_class_(num_class), lambda_(lambda)
42 {
43  Train(inputs, labels);
44 }
45 ///////////////////////////////////////////////////////////////////////////////
46 template<class T>
47 void LDC<T>::Train ( const arma::Mat<T>& inputs,
48  const arma::Row<size_t>& labels )
49 {
50  class_ = arma::regspace<arma::Row<size_t>>(0,1,num_class_);
51  priors_ = get_prior<T>(labels, num_class_);
52 
53  dim_ = inputs.n_rows;
54  size_ = inputs.n_cols;
55  unique_ = arma::unique(labels);
56  if (unique_.n_elem != 1)
57  {
58  cov_.resize(dim_,dim_);
59  cov_.zeros();
60 
61  arma::Row<size_t>::iterator it = unique_.begin();
62  arma::Row<size_t>::iterator end = unique_.end();
63 
64  arma::Mat<T> inx;
65 
66  for(; it!=end; it++)
67  {
68  auto extract = extract_class(inputs, labels, *it);
69  inx = std::get<0>(extract);
70  means_[*it] = arma::conv_to<arma::Row<T>>::from(arma::mean(inx,1));
71  if ( inx.n_cols == 1 )
72  covs_[*it] = arma::eye<arma::Mat<T>>(dim_,dim_);
73  else
74  {
75  covs_[*it] = arma::cov(inx.t());
76  covs_[*it].diag() += jitter_+lambda_;
77  }
78  cov_ += covs_[*it];
79  }
80  cov_ = arma::pinv(cov_) / num_class_;
81  }
82 }
83 ///////////////////////////////////////////////////////////////////////////////
84 template<class T>
85 void LDC<T>::Train ( const arma::Mat<T>& inputs,
86  const arma::Row<size_t>& labels,
87  const size_t num_class )
88 {
89  this->num_class_ = num_class;
90  this->Train(inputs,labels);
91 }
92 ///////////////////////////////////////////////////////////////////////////////
93 template<class T>
94 void LDC<T>::Classify ( const arma::Mat<T>& inputs,
95  arma::Row<size_t>& labels ) const
96 {
97  arma::Mat<T> temp;
98  Classify(inputs, labels, temp);
99 }
100 ///////////////////////////////////////////////////////////////////////////////
101 template<class T>
102 void LDC<T>::Classify ( const arma::Mat<T>& inputs,
103  arma::Row<size_t>& labels,
104  arma::Mat<T>& probs ) const
105 {
106  const size_t N = inputs.n_cols;
107  labels.resize(N);
108  probs.resize(num_class_,N);
109  if ( unique_.n_elem == 1 )
110  {
111  labels.fill(unique_(0));
112  probs.row(unique_(0)).fill(1.);
113  }
114  else
115  {
116  #pragma omp parallel for
117  for ( size_t n=0; n<inputs.n_cols; n++ )
118  {
119  for ( size_t c=0; c<unique_.n_elem; c++ )
120  {
121  probs(class_(unique_(c)),n) = std::log(priors_(c))
122  - 0.5*arma::dot(means_.at(unique_(c))*
123  cov_, means_.at(unique_(c)))
124  + arma::dot(inputs.col(n).t()*cov_,means_.at(unique_(c)));
125  }
126  labels(n) = class_(probs.col(n).index_max());
127  }
128 
129  probs = arma::exp(probs.each_row() - arma::max(probs,0));
130  probs = probs.each_row()/arma::sum(probs,0);
131  }
132 
133 }
134 ///////////////////////////////////////////////////////////////////////////////
135 template<class T>
136 T LDC<T>::ComputeError ( const arma::Mat<T>& points,
137  const arma::Row<size_t>& responses ) const
138 {
139  arma::Row<size_t> predictions;
140  Classify(points,predictions);
141  arma::Row<size_t> temp = predictions - responses;
142  return (arma::accu(temp != 0))/T(predictions.n_elem);
143 }
144 ///////////////////////////////////////////////////////////////////////////////
145 template<class T>
146 T LDC<T>::ComputeAccuracy ( const arma::Mat<T>& points,
147  const arma::Row<size_t>& responses ) const
148 {
149  return (1. - ComputeError(points, responses))*100;
150 }
151 
152 //-----------------------------------------------------------------------------
153 // Quadratic Discriminant Classifier
154 //-----------------------------------------------------------------------------
155 template<class T>
156 QDC<T>::QDC ( const arma::Mat<T>& inputs,
157  const arma::Row<size_t>& labels,
158  const size_t& num_class ) : num_class_(num_class), lambda_(0.)
159 {
160  Train(inputs, labels);
161 }
162 ///////////////////////////////////////////////////////////////////////////////
163 template<class T>
164 QDC<T>::QDC ( const arma::Mat<T>& inputs,
165  const arma::Row<size_t>& labels,
166  const size_t& num_class,
167  const double& lambda,
168  const arma::Row<T>& priors ) : num_class_(num_class),
169  lambda_(lambda), priors_(priors)
170 {
171  Train(inputs, labels);
172 }
173 ///////////////////////////////////////////////////////////////////////////////
174 template<class T>
175 QDC<T>::QDC ( const arma::Mat<T>& inputs,
176  const arma::Row<size_t>& labels,
177  const size_t& num_class,
178  const double& lambda ) : num_class_(num_class), lambda_(lambda)
179 {
180  Train(inputs, labels);
181 }
182 ///////////////////////////////////////////////////////////////////////////////
183 template<class T>
184 void QDC<T>::Train ( const arma::Mat<T>& inputs,
185  const arma::Row<size_t>& labels )
186 {
187 
188  dim_ = inputs.n_rows;
189  size_ = inputs.n_cols;
190  unique_ = arma::unique(labels);
191 
192  class_ = arma::regspace<arma::Row<size_t>>(0,1,num_class_);
193  priors_ = get_prior<T>(labels,num_class_);
194 
195  arma::Row<size_t>::iterator it = unique_.begin();
196  arma::Row<size_t>::iterator end = unique_.end();
197 
198  arma::Mat<T> inx;
199 
200  for(; it!=end; it++)
201  {
202  auto extract = extract_class(inputs, labels, *it);
203 
204  inx = std::get<0>(extract);
205  means_[*it] = arma::conv_to<arma::Row<T>>::from(arma::mean(inx,1));
206  if ( inx.n_cols == 1 )
207  {
208  covs_[*it] = arma::eye<arma::Mat<T>>(dim_,dim_);
209  icovs_[*it] = arma::eye<arma::Mat<T>>(dim_,dim_);
210  }
211  else
212  {
213  covs_[*it] = arma::cov(inx.t());
214  covs_[*it].diag() += jitter_+lambda_;
215  icovs_[*it] = arma::pinv(covs_[*it]);
216  }
217  icovs_[*it] = arma::pinv(covs_[*it]);
218  }
219 }
220 ///////////////////////////////////////////////////////////////////////////////
221 template<class T>
222 void QDC<T>::Train ( const arma::Mat<T>& inputs,
223  const arma::Row<size_t>& labels,
224  const size_t num_class )
225 {
226  this -> num_class_=num_class;
227  this -> Train(inputs,labels);
228 }
229 ///////////////////////////////////////////////////////////////////////////////
230 template<class T>
231 void QDC<T>::Classify ( const arma::Mat<T>& inputs,
232  arma::Row<size_t>& labels ) const
233 {
234  arma::Mat<T> temp;
235  Classify(inputs, labels, temp);
236 }
237 ///////////////////////////////////////////////////////////////////////////////
238 template<class T>
239 void QDC<T>::Classify ( const arma::Mat<T>& inputs,
240  arma::Row<size_t>& labels,
241  arma::Mat<T>& probs ) const
242 {
243  const size_t N = inputs.n_cols;
244  labels.resize(N);
245  probs.resize(num_class_,N);
246 
247  if ( num_class_ == 1 )
248  {
249  labels.fill(unique_(0));
250  probs.row(unique_(0)).fill(1.);
251  }
252  else
253  {
254  arma::Row<T> norm;
255 
256  /* #pragma omp parallel for */
257  for ( size_t n=0; n<inputs.n_cols; n++ )
258  {
259  for ( size_t c=0; c<unique_.n_elem; c++ )
260  {
261  norm = inputs.col(n).t() - means_.at(unique_(c));
262  probs(class_(unique_(c)),n) = std::log(priors_(c))
263  - 0.5*(arma::det(covs_.at(unique_(c)))+inputs.n_rows*std::log(2*arma::datum::pi))
264  - 0.5* arma::dot(norm*icovs_.at(unique_(c)),norm);
265  }
266  labels(n) = class_(probs.col(n).index_max());
267 
268  }
269  probs = arma::exp(probs.each_row() - arma::max(probs,0));
270  probs = probs.each_row()/arma::sum(probs,0);
271  }
272 }
273 ///////////////////////////////////////////////////////////////////////////////
274 template<class T>
275 T QDC<T>::ComputeError ( const arma::Mat<T>& points,
276  const arma::Row<size_t>& responses ) const
277 {
278  arma::Row<size_t> predictions;
279  Classify(points,predictions);
280  arma::Row<size_t> temp = predictions - responses;
281  return (arma::accu(temp != 0))/T(predictions.n_elem);
282 }
283 ///////////////////////////////////////////////////////////////////////////////
284 template<class T>
285 T QDC<T>::ComputeAccuracy ( const arma::Mat<T>& points,
286  const arma::Row<size_t>& responses ) const
287 {
288  return (1. - ComputeError(points, responses))*100;
289 }
290 //-----------------------------------------------------------------------------
291 // Nearest Mean Classifier
292 //-----------------------------------------------------------------------------
293 template<class T>
294 NMC<T>::NMC ( const arma::Mat<T>& inputs,
295  const arma::Row<size_t>& labels,
296  const size_t& num_class,
297  const double& shrink ) : shrink_(shrink), num_class_(num_class)
298 {
299  Train(inputs, labels);
300 }
301 ///////////////////////////////////////////////////////////////////////////////
302 template<class T>
303 NMC<T>::NMC ( const arma::Mat<T>& inputs,
304  const arma::Row<size_t>& labels,
305  const size_t& num_class ) : shrink_(0.), num_class_(num_class)
306 {
307  Train(inputs, labels);
308 }
309 ///////////////////////////////////////////////////////////////////////////////
310 template<class T>
311 void NMC<T>::Train ( const arma::Mat<T>& inputs,
312  const arma::Row<size_t>& labels )
313 {
314  dim_ = inputs.n_rows;
315  unique_ = arma::unique(labels);
316  /* num_class_ = unique_.n_cols; */
317  size_ = inputs.n_cols;
318  arma::vec nk(num_class_);
319  parameters_.resize(inputs.n_rows, num_class_);
320  arma::uvec index;
321  arma::Row<size_t>::iterator it = unique_.begin();
322  arma::Row<size_t>::iterator it_end = unique_.end();
323  size_t counter =0;
324  // you should just iterate over the unique labels here instead of starting
325  // from 0
326 
327  for ( ;it!=it_end; ++it)
328  {
329  auto extract = extract_class(inputs, labels, *it);
330  index = std::get<1>(extract);
331  nk(counter) = index.n_rows;
332  parameters_.col(counter) = arma::mean(inputs.cols(index),1);
333  counter++;
334  }
335  centroid_ = arma::mean(inputs, 1);
336 
337  // Just for the shrinkage part
338  if (shrink_ > 0 && num_class_ != 1)
339  {
340  arma::Mat<T> nk = arma::ones<arma::Mat<T>>(num_class_,1);
341  arma::Mat<T> m = arma::sqrt(1./nk)-1/size_;
342  arma::uvec labs = arma::conv_to<arma::uvec>::from(labels);
343  arma::Mat<T> variance = arma::sum(
344  arma::pow(inputs - parameters_.cols(labs),2),1);
345  arma::Mat<T> s = arma::sqrt(variance/(size_-num_class_)).t();
346  arma::Mat<T> ms = m*s;
347  arma::inplace_trans(ms);
348  arma::Mat<T> devi = (parameters_.each_col() - centroid_) / ms;
349  arma::Mat<T> signs = arma::sign(devi);
350  arma::Mat<T> dev = arma::abs(devi) - shrink_;
351  dev = arma::clamp(dev, 0, arma::datum::inf);
352  dev %= signs;
353  arma::Mat<T> msd = dev % ms;
354  parameters_ = centroid_ + msd.each_col();
355  }
356 }
357 ///////////////////////////////////////////////////////////////////////////////
358 template<class T>
359 void NMC<T>::Train ( const arma::Mat<T>& inputs,
360  const arma::Row<size_t>& labels,
361  const size_t num_class )
362 {
363  this -> num_class_ = num_class;
364  this -> Train (inputs,labels);
365 }
366 ///////////////////////////////////////////////////////////////////////////////
367 template<class T>
368 void NMC<T>::Classify ( const arma::Mat<T>& inputs,
369  arma::Row<size_t>& labels ) const
370 {
371  arma::Mat<T> temp;
372  Classify(inputs,labels,temp);
373 }
374 ///////////////////////////////////////////////////////////////////////////////
375 template<class T>
376 void NMC<T>::Classify ( const arma::Mat<T>& inputs,
377  arma::Row<size_t>& labels,
378  arma::Mat<T>& probs ) const
379 {
380  const size_t N = inputs.n_cols;
381  probs.resize(num_class_, N);
382  labels.resize(N);
383  if ( unique_.n_elem == 1 )
384  {
385  labels.fill(unique_(0));
386  probs.row(unique_(0)).fill(1.);
387  }
388  else
389  {
390  arma::Mat<T> distances(num_class_, N);
391  distances.fill(arma::datum::inf);
392  for ( size_t j=0; j<N; j++ )
393  {
394  for ( size_t i=0; i<unique_.n_elem; i++ )
395  {
396  distances(unique_(i), j) = metric_.Evaluate(parameters_.col(unique_(i))
397  ,inputs.col(j));
398  }
399  labels(j) = arma::index_min(distances.col(j));
400  }
401  if (unique_.n_elem == num_class_)
402  probs = distances.each_row() / arma::sum(distances,0);
403  else
404  {
405  for (arma::uword i = 0; i < distances.n_rows; ++i)
406  {
407  // Check if the row contains any infinite values
408  if (arma::is_finite(distances.row(i)))
409  // Perform the division for this row only if all values are finite
410  // and sum is nonzero
411  probs.row(i) = distances.row(i) / arma::sum(distances, 0);
412  }
413  }
414  probs.elem(arma::find_nonfinite(probs)).fill(1/num_class_);
415  }
416 }
417 ///////////////////////////////////////////////////////////////////////////////
418 template<class T>
419 T NMC<T>::ComputeError ( const arma::Mat<T>& points,
420  const arma::Row<size_t>& responses ) const
421 {
422  arma::Row<size_t> predictions;
423 
424  Classify(points,predictions);
425  arma::Row<size_t> temp = predictions - responses;
426  return (arma::accu(temp != 0))/T(predictions.n_elem);
427 }
428 ///////////////////////////////////////////////////////////////////////////////
429 template<class T>
430 T NMC<T>::ComputeAccuracy ( const arma::Mat<T>& points,
431  const arma::Row<size_t>& responses ) const
432 {
433  return (1. - ComputeError(points, responses))*100;
434 }
435 ///////////////////////////////////////////////////////////////////////////////
436 } // namespace classification
437 } // namespace algo
438 #endif
439 
void Train(const arma::Mat< T > &inputs, const arma::Row< size_t > &labels)
void Classify(const arma::Mat< T > &inputs, arma::Row< size_t > &labels) const
T ComputeAccuracy(const arma::Mat< T > &points, const arma::Row< size_t > &responses) const
T ComputeError(const arma::Mat< T > &points, const arma::Row< size_t > &responses) const
void Train(const arma::Mat< T > &inputs, const arma::Row< size_t > &labels)
void Classify(const arma::Mat< T > &inputs, arma::Row< size_t > &labels) const
T ComputeAccuracy(const arma::Mat< T > &points, const arma::Row< size_t > &responses) const
T ComputeError(const arma::Mat< T > &points, const arma::Row< size_t > &responses) const
void Classify(const arma::Mat< T > &inputs, arma::Row< size_t > &labels) const
T ComputeError(const arma::Mat< T > &points, const arma::Row< size_t > &responses) const
void Train(const arma::Mat< T > &inputs, const arma::Row< size_t > &labels)
T ComputeAccuracy(const arma::Mat< T > &points, const arma::Row< size_t > &responses) const