pktools  2.6.3
Processing Kernel for geospatial data
pkoptsvm.cc
1 /**********************************************************************
2 pkoptsvm.cc: program to optimize parameters for support vector machine classifier pksvm
3 Copyright (C) 2008-2014 Pieter Kempeneers
4 
5 This file is part of pktools
6 
7 pktools is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 pktools is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with pktools. If not, see <http://www.gnu.org/licenses/>.
19 ***********************************************************************/
20 #include <iostream>
21 #include <sstream>
22 #include <fstream>
23 #include <vector>
24 #include <math.h>
25 #include <nlopt.hpp>
26 #include "base/Optionpk.h"
27 #include "base/Optionpk.h"
28 #include "algorithms/ConfusionMatrix.h"
29 #include "algorithms/FeatureSelector.h"
30 #include "algorithms/OptFactory.h"
31 #include "algorithms/CostFactorySVM.h"
32 #include "algorithms/svm.h"
33 #include "imageclasses/ImgReaderOgr.h"
34 
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38 
39 /******************************************************************************/
104 using namespace std;
105 
106 #define Malloc(type,n) (type *)malloc((n)*sizeof(type))
107  //declare objective function
108 double objFunction(const std::vector<double> &x, std::vector<double> &grad, void *my_func_data);
109 
110 //global parameters used in objective function
111 map<string,short> classValueMap;
112 vector<std::string> nameVector;
113 vector<unsigned int> nctraining;
114 vector<unsigned int> nctest;
115 Optionpk<std::string> svm_type_opt("svmt", "svmtype", "type of SVM (C_SVC, nu_SVC,one_class, epsilon_SVR, nu_SVR)","C_SVC");
116 Optionpk<std::string> kernel_type_opt("kt", "kerneltype", "type of kernel function (linear,polynomial,radial,sigmoid) ","radial");
117 Optionpk<unsigned short> kernel_degree_opt("kd", "kd", "degree in kernel function",3);
118 Optionpk<float> coef0_opt("c0", "coef0", "coef0 in kernel function",0);
119 Optionpk<float> nu_opt("nu", "nu", "the parameter nu of nu-SVC, one-class SVM, and nu-SVR",0.5);
120 Optionpk<float> epsilon_loss_opt("eloss", "eloss", "the epsilon in loss function of epsilon-SVR",0.1);
121 Optionpk<int> cache_opt("cache", "cache", "cache memory size in MB",100);
122 Optionpk<float> epsilon_tol_opt("etol", "etol", "the tolerance of termination criterion",0.001);
123 Optionpk<bool> shrinking_opt("shrink", "shrink", "whether to use the shrinking heuristics",false);
124 Optionpk<bool> prob_est_opt("pe", "probest", "whether to train a SVC or SVR model for probability estimates",true,2);
125 Optionpk<bool> costfunction_opt("cf", "cf", "use Overall Accuracy instead of kappa",false);
126 // Optionpk<bool> weight_opt("wi", "wi", "set the parameter C of class i to weight*C, for C-SVC",true);
127 Optionpk<unsigned short> cv_opt("cv", "cv", "n-fold cross validation mode",2);
128 Optionpk<string> classname_opt("c", "class", "list of class names.");
129 Optionpk<short> classvalue_opt("r", "reclass", "list of class values (use same order as in class opt).");
130 Optionpk<short> verbose_opt("v", "verbose", "use 1 to output intermediate results for plotting",0,2);
131 
132 double objFunction(const std::vector<double> &x, std::vector<double> &grad, void *my_func_data){
133 
134  assert(grad.empty());
135  vector<Vector2d<float> > *tf=reinterpret_cast<vector<Vector2d<float> >*> (my_func_data);
136  float ccost=x[0];
137  float gamma=x[1];
138  double error=1.0/epsilon_tol_opt[0];
139  double kappa=1.0;
140  double oa=1.0;
141 
142  CostFactorySVM costfactory(svm_type_opt[0], kernel_type_opt[0], kernel_degree_opt[0], gamma, coef0_opt[0], ccost, nu_opt[0], epsilon_loss_opt[0], cache_opt[0], epsilon_tol_opt[0], shrinking_opt[0], prob_est_opt[0], cv_opt[0], verbose_opt[0]);
143 
144  assert(tf->size());
145  // if(nctest>0)
146  // costfactory.setCv(0);
147 
148  costfactory.setCv(cv_opt[0]);
149 
150  if(classname_opt.size()){
151  assert(classname_opt.size()==classvalue_opt.size());
152  for(int iclass=0;iclass<classname_opt.size();++iclass)
153  costfactory.setClassValueMap(classname_opt[iclass],classvalue_opt[iclass]);
154  }
155  //set names in confusion matrix using nameVector
156  costfactory.setNameVector(nameVector);
157  // vector<string> nameVector=costfactory.getNameVector();
158  for(int iname=0;iname<nameVector.size();++iname){
159  if(costfactory.getClassValueMap().empty()){
160  costfactory.pushBackClassName(nameVector[iname]);
161  // cm.pushBackClassName(nameVector[iname]);
162  }
163  else if(costfactory.getClassIndex(type2string<short>((costfactory.getClassValueMap())[nameVector[iname]]))<0)
164  costfactory.pushBackClassName(type2string<short>((costfactory.getClassValueMap())[nameVector[iname]]));
165  }
166 
167  costfactory.setNcTraining(nctraining);
168  costfactory.setNcTest(nctest);
169 
170  kappa=costfactory.getCost(*tf);
171  return(kappa);
172 }
173 
174 int main(int argc, char *argv[])
175 {
176  map<short,int> reclassMap;
177  vector<int> vreclass;
178  Optionpk<string> training_opt("t", "training", "training vector file. A single vector file contains all training features (must be set as: b0, b1, b2,...) for all classes (class numbers identified by label option).");
179  Optionpk<float> ccost_opt("cc", "ccost", "min and max boundaries the parameter C of C-SVC, epsilon-SVR, and nu-SVR (optional: initial value)",1);
180  Optionpk<float> gamma_opt("g", "gamma", "min max boundaries for gamma in kernel function (optional: initial value)",0);
181  Optionpk<double> stepcc_opt("stepcc","stepcc","multiplicative step for ccost in GRID search",2);
182  Optionpk<double> stepg_opt("stepg","stepg","multiplicative step for gamma in GRID search",2);
183  Optionpk<string> input_opt("i", "input", "input test vector file");
184  Optionpk<string> tlayer_opt("tln", "tln", "training layer name(s)");
185  Optionpk<string> label_opt("label", "label", "identifier for class label in training vector file.","label");
186  // Optionpk<unsigned short> reclass_opt("\0", "rc", "reclass code (e.g. --rc=12 --rc=23 to reclass first two classes to 12 and 23 resp.).", 0);
187  Optionpk<unsigned int> balance_opt("bal", "balance", "balance the input data to this number of samples for each class", 0);
188  Optionpk<bool> random_opt("random","random", "in case of balance, randomize input data", true);
189  Optionpk<int> minSize_opt("min", "min", "if number of training pixels is less then min, do not take this class into account", 0);
190  Optionpk<short> band_opt("b", "band", "band index (starting from 0, either use band option or use start to end)");
191  Optionpk<double> bstart_opt("s", "start", "start band sequence number",0);
192  Optionpk<double> bend_opt("e", "end", "end band sequence number (set to 0 to include all bands)", 0);
193  Optionpk<double> offset_opt("\0", "offset", "offset value for each spectral band input features: refl[band]=(DN[band]-offset[band])/scale[band]", 0.0);
194  Optionpk<double> scale_opt("\0", "scale", "scale value for each spectral band input features: refl=(DN[band]-offset[band])/scale[band] (use 0 if scale min and max in each band to -1.0 and 1.0)", 0.0);
195  Optionpk<unsigned int> maxit_opt("maxit","maxit","maximum number of iterations",500);
196 //Optionpk<string> algorithm_opt("a", "algorithm", "GRID, or any optimization algorithm from http://ab-initio.mit.edu/wiki/index.php/NLopt_Algorithms","GRID");
197  Optionpk<double> tolerance_opt("tol","tolerance","relative tolerance for stopping criterion",0.0001);
198 
199  input_opt.setHide(1);
200  tlayer_opt.setHide(1);
201  label_opt.setHide(1);
202  balance_opt.setHide(1);
203  random_opt.setHide(1);
204  minSize_opt.setHide(1);
205  band_opt.setHide(1);
206  bstart_opt.setHide(1);
207  bend_opt.setHide(1);
208  offset_opt.setHide(1);
209  scale_opt.setHide(1);
210  svm_type_opt.setHide(1);
211  kernel_type_opt.setHide(1);
212  kernel_degree_opt.setHide(1);
213  coef0_opt.setHide(1);
214  nu_opt.setHide(1);
215  epsilon_loss_opt.setHide(1);
216  cache_opt.setHide(1);
217  epsilon_tol_opt.setHide(1);
218  shrinking_opt.setHide(1);
219  prob_est_opt.setHide(1);
220  cv_opt.setHide(1);
221  costfunction_opt.setHide(1);
222  maxit_opt.setHide(1);
223  tolerance_opt.setHide(1);
224 // algorithm_opt.setHide(1);
225  classname_opt.setHide(1);
226  classvalue_opt.setHide(1);
227 
228  bool doProcess;//stop process when program was invoked with help option (-h --help)
229  try{
230  doProcess=training_opt.retrieveOption(argc,argv);
231  ccost_opt.retrieveOption(argc,argv);
232  gamma_opt.retrieveOption(argc,argv);
233  stepcc_opt.retrieveOption(argc,argv);
234  stepg_opt.retrieveOption(argc,argv);
235  input_opt.retrieveOption(argc,argv);
236  tlayer_opt.retrieveOption(argc,argv);
237  label_opt.retrieveOption(argc,argv);
238  balance_opt.retrieveOption(argc,argv);
239  random_opt.retrieveOption(argc,argv);
240  minSize_opt.retrieveOption(argc,argv);
241  band_opt.retrieveOption(argc,argv);
242  bstart_opt.retrieveOption(argc,argv);
243  bend_opt.retrieveOption(argc,argv);
244  offset_opt.retrieveOption(argc,argv);
245  scale_opt.retrieveOption(argc,argv);
246  svm_type_opt.retrieveOption(argc,argv);
247  kernel_type_opt.retrieveOption(argc,argv);
248  kernel_degree_opt.retrieveOption(argc,argv);
249  coef0_opt.retrieveOption(argc,argv);
250  nu_opt.retrieveOption(argc,argv);
251  epsilon_loss_opt.retrieveOption(argc,argv);
252  cache_opt.retrieveOption(argc,argv);
253  epsilon_tol_opt.retrieveOption(argc,argv);
254  shrinking_opt.retrieveOption(argc,argv);
255  prob_est_opt.retrieveOption(argc,argv);
256  cv_opt.retrieveOption(argc,argv);
257  costfunction_opt.retrieveOption(argc,argv);
258  maxit_opt.retrieveOption(argc,argv);
259  tolerance_opt.retrieveOption(argc,argv);
260 // algorithm_opt.retrieveOption(argc,argv);
261  classname_opt.retrieveOption(argc,argv);
262  classvalue_opt.retrieveOption(argc,argv);
263  verbose_opt.retrieveOption(argc,argv);
264  }
265  catch(string predefinedString){
266  std::cout << predefinedString << std::endl;
267  exit(0);
268  }
269  if(!doProcess){
270  cout << endl;
271  cout << "Usage: pkoptsvm -t training" << endl;
272  cout << endl;
273  std::cout << "short option -h shows basic options only, use long option --help to show all options" << std::endl;
274  exit(0);//help was invoked, stop processing
275  }
276 
277  assert(training_opt.size());
278  if(input_opt.size())
279  cv_opt[0]=0;
280 
281  if(verbose_opt[0]>=1){
282  if(input_opt.size())
283  std::cout << "input filename: " << input_opt[0] << std::endl;
284  std::cout << "training vector file: " << std::endl;
285  for(int ifile=0;ifile<training_opt.size();++ifile)
286  std::cout << training_opt[ifile] << std::endl;
287  std::cout << "verbose: " << verbose_opt[0] << std::endl;
288  }
289 
290  unsigned int totalSamples=0;
291  unsigned int totalTestSamples=0;
292 
293  unsigned short nclass=0;
294  int nband=0;
295  int startBand=2;//first two bands represent X and Y pos
296 
297  vector<double> offset;
298  vector<double> scale;
299  vector< Vector2d<float> > trainingPixels;//[class][sample][band]
300  vector< Vector2d<float> > testPixels;//[class][sample][band]
301 
302  // if(priors_opt.size()>1){//priors from argument list
303  // priors.resize(priors_opt.size());
304  // double normPrior=0;
305  // for(int iclass=0;iclass<priors_opt.size();++iclass){
306  // priors[iclass]=priors_opt[iclass];
307  // normPrior+=priors[iclass];
308  // }
309  // //normalize
310  // for(int iclass=0;iclass<priors_opt.size();++iclass)
311  // priors[iclass]/=normPrior;
312  // }
313 
314  //sort bands
315  if(band_opt.size())
316  std::sort(band_opt.begin(),band_opt.end());
317 
318  // map<string,short> classValueMap;//global variable for now (due to getCost)
319  if(classname_opt.size()){
320  assert(classname_opt.size()==classvalue_opt.size());
321  for(int iclass=0;iclass<classname_opt.size();++iclass)
322  classValueMap[classname_opt[iclass]]=classvalue_opt[iclass];
323  }
324 
325  //----------------------------------- Training -------------------------------
326  struct svm_problem prob;
327  vector<string> fields;
328  //organize training data
329  trainingPixels.clear();
330  testPixels.clear();
331  map<string,Vector2d<float> > trainingMap;
332  map<string,Vector2d<float> > testMap;
333  if(verbose_opt[0]>=1)
334  std::cout << "reading training file " << training_opt[0] << std::endl;
335  try{
336  ImgReaderOgr trainingReader(training_opt[0]);
337  if(band_opt.size()){
338  totalSamples=trainingReader.readDataImageOgr(trainingMap,fields,band_opt,label_opt[0],tlayer_opt,verbose_opt[0]);
339  if(input_opt.size()){
340  ImgReaderOgr inputReader(input_opt[0]);
341  totalTestSamples=inputReader.readDataImageOgr(testMap,fields,band_opt,label_opt[0],tlayer_opt,verbose_opt[0]);
342  inputReader.close();
343  }
344  }
345  else{
346  totalSamples=trainingReader.readDataImageOgr(trainingMap,fields,bstart_opt[0],bend_opt[0],label_opt[0],tlayer_opt,verbose_opt[0]);
347  if(input_opt.size()){
348  ImgReaderOgr inputReader(input_opt[0]);
349  totalTestSamples=inputReader.readDataImageOgr(testMap,fields,bstart_opt[0],bend_opt[0],label_opt[0],tlayer_opt,verbose_opt[0]);
350  inputReader.close();
351  }
352  trainingReader.close();
353  }
354  if(trainingMap.size()<2){
355  // map<string,Vector2d<float> >::iterator mapit=trainingMap.begin();
356  // while(mapit!=trainingMap.end())
357  // cerr << mapit->first << " -> " << classValueMap[mapit->first] << std::endl;
358  string errorstring="Error: could not read at least two classes from training input file";
359  throw(errorstring);
360  }
361  if(input_opt.size()&&testMap.size()<2){
362  string errorstring="Error: could not read at least two classes from test input file";
363  throw(errorstring);
364  }
365  }
366  catch(string error){
367  cerr << error << std::endl;
368  exit(1);
369  }
370  catch(...){
371  cerr << "error catched" << std::endl;
372  exit(1);
373  }
374  //todo delete class 0 ?
375  // if(verbose_opt[0]>=1)
376  // std::cout << "erasing class 0 from training set (" << trainingMap[0].size() << " from " << totalSamples << ") samples" << std::endl;
377  // totalSamples-=trainingMap[0].size();
378  // trainingMap.erase(0);
379 
380  if(verbose_opt[0]>1)
381  std::cout << "training pixels: " << std::endl;
382  map<string,Vector2d<float> >::iterator mapit;
383  mapit=trainingMap.begin();
384  while(mapit!=trainingMap.end()){
385  if(classValueMap.size()){
386  //check if name in training is covered by classname_opt (values can not be 0)
387  if(classValueMap[mapit->first]>0){
388  if(verbose_opt[0])
389  std::cout << mapit->first << " -> " << classValueMap[mapit->first] << std::endl;
390  }
391  else{
392  std::cerr << "Error: names in classname option are not complete, please check names in training vector and make sure classvalue is > 0" << std::endl;
393  exit(1);
394  }
395  }
396  //delete small classes
397  if((mapit->second).size()<minSize_opt[0]){
398  trainingMap.erase(mapit);
399  continue;
400  }
401  nameVector.push_back(mapit->first);
402  trainingPixels.push_back(mapit->second);
403  if(verbose_opt[0]>1)
404  std::cout << mapit->first << ": " << (mapit->second).size() << " samples" << std::endl;
405  // trainingPixels.push_back(mapit->second); ??
406  // ++iclass;
407  ++mapit;
408  }
409  nclass=trainingPixels.size();
410  if(classname_opt.size())
411  assert(nclass==classname_opt.size());
412  nband=trainingPixels[0][0].size()-2;//X and Y//trainingPixels[0][0].size();
413 
414  mapit=testMap.begin();
415  while(mapit!=testMap.end()){
416  if(classValueMap.size()){
417  //check if name in test is covered by classname_opt (values can not be 0)
418  if(classValueMap[mapit->first]>0){
419  ;//ok, no need to print to std::cout
420  }
421  else{
422  std::cerr << "Error: names in classname option are not complete, please check names in test vector and make sure classvalue is > 0" << std::endl;
423  exit(1);
424  }
425  }
426  //no need to delete small classes for test sample
427  testPixels.push_back(mapit->second);
428  if(verbose_opt[0]>1)
429  std::cout << mapit->first << ": " << (mapit->second).size() << " samples" << std::endl;
430  ++mapit;
431  }
432  if(input_opt.size()){
433  assert(nclass==testPixels.size());
434  assert(nband=testPixels[0][0].size()-2);//X and Y//testPixels[0][0].size();
435  assert(!cv_opt[0]);
436  }
437 
438  //do not remove outliers here: could easily be obtained through ogr2ogr -where 'B2<110' output.shp input.shp
439  //balance training data
440  if(balance_opt[0]>0){
441  if(random_opt[0])
442  srand(time(NULL));
443  totalSamples=0;
444  for(int iclass=0;iclass<nclass;++iclass){
445  if(trainingPixels[iclass].size()>balance_opt[0]){
446  while(trainingPixels[iclass].size()>balance_opt[0]){
447  int index=rand()%trainingPixels[iclass].size();
448  trainingPixels[iclass].erase(trainingPixels[iclass].begin()+index);
449  }
450  }
451  else{
452  int oldsize=trainingPixels[iclass].size();
453  for(int isample=trainingPixels[iclass].size();isample<balance_opt[0];++isample){
454  int index = rand()%oldsize;
455  trainingPixels[iclass].push_back(trainingPixels[iclass][index]);
456  }
457  }
458  totalSamples+=trainingPixels[iclass].size();
459  }
460  assert(totalSamples==nclass*balance_opt[0]);
461  }
462 
463  //no need to balance test sample
464  //set scale and offset
465  offset.resize(nband);
466  scale.resize(nband);
467  if(offset_opt.size()>1)
468  assert(offset_opt.size()==nband);
469  if(scale_opt.size()>1)
470  assert(scale_opt.size()==nband);
471  for(int iband=0;iband<nband;++iband){
472  if(verbose_opt[0]>1)
473  std::cout << "scaling for band" << iband << std::endl;
474  offset[iband]=(offset_opt.size()==1)?offset_opt[0]:offset_opt[iband];
475  scale[iband]=(scale_opt.size()==1)?scale_opt[0]:scale_opt[iband];
476  //search for min and maximum
477  if(scale[iband]<=0){
478  float theMin=trainingPixels[0][0][iband+startBand];
479  float theMax=trainingPixels[0][0][iband+startBand];
480  for(int iclass=0;iclass<nclass;++iclass){
481  for(int isample=0;isample<trainingPixels[iclass].size();++isample){
482  if(theMin>trainingPixels[iclass][isample][iband+startBand])
483  theMin=trainingPixels[iclass][isample][iband+startBand];
484  if(theMax<trainingPixels[iclass][isample][iband+startBand])
485  theMax=trainingPixels[iclass][isample][iband+startBand];
486  }
487  }
488  offset[iband]=theMin+(theMax-theMin)/2.0;
489  scale[iband]=(theMax-theMin)/2.0;
490  if(verbose_opt[0]>1){
491  std::cout << "Extreme image values for band " << iband << ": [" << theMin << "," << theMax << "]" << std::endl;
492  std::cout << "Using offset, scale: " << offset[iband] << ", " << scale[iband] << std::endl;
493  std::cout << "scaled values for band " << iband << ": [" << (theMin-offset[iband])/scale[iband] << "," << (theMax-offset[iband])/scale[iband] << "]" << std::endl;
494  }
495  }
496  }
497 
498  // if(priors_opt.size()==1){//default: equal priors for each class
499  // priors.resize(nclass);
500  // for(int iclass=0;iclass<nclass;++iclass)
501  // priors[iclass]=1.0/nclass;
502  // }
503  // assert(priors_opt.size()==1||priors_opt.size()==nclass);
504 
505  if(verbose_opt[0]>=1){
506  std::cout << "number of bands: " << nband << std::endl;
507  std::cout << "number of classes: " << nclass << std::endl;
508  // std::cout << "priors:";
509  // for(int iclass=0;iclass<nclass;++iclass)
510  // std::cout << " " << priors[iclass];
511  // std::cout << std::endl;
512  }
513 
514  //Calculate features of training (and test) set
515  nctraining.resize(nclass);
516  nctest.resize(nclass);
517  vector< Vector2d<float> > trainingFeatures(nclass);
518  for(int iclass=0;iclass<nclass;++iclass){
519  if(verbose_opt[0]>=1)
520  std::cout << "calculating features for class " << iclass << std::endl;
521  nctraining[iclass]=trainingPixels[iclass].size();
522  if(verbose_opt[0]>=1)
523  std::cout << "nctraining[" << iclass << "]: " << nctraining[iclass] << std::endl;
524  if(testPixels.size()>iclass){
525  nctest[iclass]=testPixels[iclass].size();
526  if(verbose_opt[0]>=1){
527  std::cout << "nctest[" << iclass << "]: " << nctest[iclass] << std::endl;
528  }
529  }
530  else
531  nctest[iclass]=0;
532  // trainingFeatures[iclass].resize(nctraining[iclass]);
533  trainingFeatures[iclass].resize(nctraining[iclass]+nctest[iclass]);
534  for(int isample=0;isample<nctraining[iclass];++isample){
535  //scale pixel values according to scale and offset!!!
536  for(int iband=0;iband<nband;++iband){
537  assert(trainingPixels[iclass].size()>isample);
538  assert(trainingPixels[iclass][isample].size()>iband+startBand);
539  assert(offset.size()>iband);
540  assert(scale.size()>iband);
541  float value=trainingPixels[iclass][isample][iband+startBand];
542  trainingFeatures[iclass][isample].push_back((value-offset[iband])/scale[iband]);
543  }
544  }
545  // assert(trainingFeatures[iclass].size()==nctraining[iclass]);
546  for(int isample=0;isample<nctest[iclass];++isample){
547  //scale pixel values according to scale and offset!!!
548  for(int iband=0;iband<nband;++iband){
549  assert(testPixels[iclass].size()>isample);
550  assert(testPixels[iclass][isample].size()>iband+startBand);
551  assert(offset.size()>iband);
552  assert(scale.size()>iband);
553  float value=testPixels[iclass][isample][iband+startBand];
554  // testFeatures[iclass][isample].push_back((value-offset[iband])/scale[iband]);
555  trainingFeatures[iclass][nctraining[iclass]+isample].push_back((value-offset[iband])/scale[iband]);
556  }
557  }
558  assert(trainingFeatures[iclass].size()==nctraining[iclass]+nctest[iclass]);
559  }
560 
561  assert(ccost_opt.size()>1);//must have boundaries at least (initial value is optional)
562  if(ccost_opt.size()<3)//create initial value
563  ccost_opt.push_back(sqrt(ccost_opt[0]*ccost_opt[1]));
564  assert(gamma_opt.size()>1);//must have boundaries at least (initial value is optional)
565  if(gamma_opt.size()<3)//create initial value
566  gamma_opt.push_back(sqrt(gamma_opt[0]*gamma_opt[1]));//will be translated to 1.0/nFeatures
567  assert(ccost_opt.size()==3);//min, init, max
568  assert(gamma_opt.size()==3);//min, init, max
569  assert(gamma_opt[0]<gamma_opt[1]);
570  assert(gamma_opt[0]<gamma_opt[2]);
571  assert(gamma_opt[2]<gamma_opt[1]);
572  assert(ccost_opt[0]<ccost_opt[1]);
573  assert(ccost_opt[0]<ccost_opt[2]);
574  assert(ccost_opt[2]<ccost_opt[1]);
575 
576  std::vector<double> x(2);
577 // if(algorithm_opt[0]=="GRID"){
578  if (1){
579  // double minError=1000;
580  // double minCost=0;
581  // double minGamma=0;
582  double maxKappa=0;
583  double maxCost=0;
584  double maxGamma=0;
585  const char* pszMessage;
586  void* pProgressArg=NULL;
587  GDALProgressFunc pfnProgress=GDALTermProgress;
588  double progress=0;
589  if(!verbose_opt[0])
590  pfnProgress(progress,pszMessage,pProgressArg);
591  double ncost=log(ccost_opt[1])/log(stepcc_opt[0])-log(ccost_opt[0])/log(stepcc_opt[0]);
592  double ngamma=log(gamma_opt[1])/log(stepg_opt[0])-log(gamma_opt[0])/log(stepg_opt[0]);
593  for(double ccost=ccost_opt[0];ccost<=ccost_opt[1];ccost*=stepcc_opt[0]){
594  for(double gamma=gamma_opt[0];gamma<=gamma_opt[1];gamma*=stepg_opt[0]){
595  x[0]=ccost;
596  x[1]=gamma;
597  std::vector<double> theGrad;
598  double kappa=0;
599  kappa=objFunction(x,theGrad,&trainingFeatures);
600  if(kappa>maxKappa){
601  maxKappa=kappa;
602  maxCost=ccost;
603  maxGamma=gamma;
604  }
605  if(verbose_opt[0])
606  std::cout << ccost << " " << gamma << " " << kappa<< std::endl;
607  progress+=1.0/ncost/ngamma;
608  if(!verbose_opt[0])
609  pfnProgress(progress,pszMessage,pProgressArg);
610  }
611  }
612  progress=1.0;
613  if(!verbose_opt[0])
614  pfnProgress(progress,pszMessage,pProgressArg);
615  x[0]=maxCost;
616  x[1]=maxGamma;
617  }
618  //else{
619  // nlopt::opt optimizer=OptFactory::getOptimizer(algorithm_opt[0],2);
620  // if(verbose_opt[0]>1)
621  // std::cout << "optimization algorithm: " << optimizer.get_algorithm_name() << "..." << std::endl;
622  // std::vector<double> lb(2);
623  // std::vector<double> init(2);
624  // std::vector<double> ub(2);
625 
626  // lb[0]=ccost_opt[0];
627  // lb[1]=(gamma_opt[0]>0)? gamma_opt[0] : 1.0/trainingFeatures[0][0].size();
628  // init[0]=ccost_opt[2];
629  // init[1]=(gamma_opt[2]>0)? gamma_opt[1] : 1.0/trainingFeatures[0][0].size();
630  // ub[0]=ccost_opt[1];
631  // ub[1]=(gamma_opt[1]>0)? gamma_opt[1] : 1.0/trainingFeatures[0][0].size();
632  // // optimizer.set_min_objective(objFunction, &trainingFeatures);
633  // optimizer.set_max_objective(objFunction, &trainingFeatures);
634  // optimizer.set_lower_bounds(lb);
635  // optimizer.set_upper_bounds(ub);
636  // if(verbose_opt[0]>1)
637  // std::cout << "set stopping criteria" << std::endl;
638  // //set stopping criteria
639  // if(maxit_opt[0])
640  // optimizer.set_maxeval(maxit_opt[0]);
641  // else
642  // optimizer.set_xtol_rel(tolerance_opt[0]);
643  // double minf=0;
644  // x=init;
645  // try{
646  // optimizer.optimize(x, minf);
647  // }
648  // catch(string error){
649  // cerr << error << std::endl;
650  // exit(1);
651  // }
652  // catch (exception& e){
653  // cout << e.what() << endl;
654  // }
655  // catch(...){
656  // cerr << "error catched" << std::endl;
657  // exit(1);
658  // }
659 
660  // double ccost=x[0];
661  // double gamma=x[1];
662  // if(verbose_opt[0])
663  // std::cout << "optimized with " << optimizer.get_algorithm_name() << "..." << std::endl;
664  //}
665  std::cout << " --ccost " << x[0];
666  std::cout << " --gamma " << x[1];
667  std::cout << std::endl;
668 }