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"
106 #define Malloc(type,n) (type *)malloc((n)*sizeof(type))
108 double objFunction(
const std::vector<double> &x, std::vector<double> &grad,
void *my_func_data);
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");
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);
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);
132 double objFunction(
const std::vector<double> &x, std::vector<double> &grad,
void *my_func_data){
134 assert(grad.empty());
135 vector<Vector2d<float> > *tf=
reinterpret_cast<vector<Vector2d<float>
>*> (my_func_data);
138 double error=1.0/epsilon_tol_opt[0];
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]);
148 costfactory.setCv(cv_opt[0]);
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]);
156 costfactory.setNameVector(nameVector);
158 for(
int iname=0;iname<nameVector.size();++iname){
159 if(costfactory.getClassValueMap().empty()){
160 costfactory.pushBackClassName(nameVector[iname]);
163 else if(costfactory.getClassIndex(type2string<short>((costfactory.getClassValueMap())[nameVector[iname]]))<0)
164 costfactory.pushBackClassName(type2string<short>((costfactory.getClassValueMap())[nameVector[iname]]));
167 costfactory.setNcTraining(nctraining);
168 costfactory.setNcTest(nctest);
170 kappa=costfactory.getCost(*tf);
174 int main(
int argc,
char *argv[])
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);
185 Optionpk<string> label_opt(
"label",
"label",
"identifier for class label in training vector file.",
"label");
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)");
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);
197 Optionpk<double> tolerance_opt(
"tol",
"tolerance",
"relative tolerance for stopping criterion",0.0001);
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);
206 bstart_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);
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);
221 costfunction_opt.setHide(1);
222 maxit_opt.setHide(1);
223 tolerance_opt.setHide(1);
225 classname_opt.setHide(1);
226 classvalue_opt.setHide(1);
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);
261 classname_opt.retrieveOption(argc,argv);
262 classvalue_opt.retrieveOption(argc,argv);
263 verbose_opt.retrieveOption(argc,argv);
265 catch(
string predefinedString){
266 std::cout << predefinedString << std::endl;
271 cout <<
"Usage: pkoptsvm -t training" << endl;
273 std::cout <<
"short option -h shows basic options only, use long option --help to show all options" << std::endl;
277 assert(training_opt.size());
281 if(verbose_opt[0]>=1){
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;
290 unsigned int totalSamples=0;
291 unsigned int totalTestSamples=0;
293 unsigned short nclass=0;
297 vector<double> offset;
298 vector<double> scale;
299 vector< Vector2d<float> > trainingPixels;
300 vector< Vector2d<float> > testPixels;
316 std::sort(band_opt.begin(),band_opt.end());
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];
327 vector<string> fields;
329 trainingPixels.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;
338 totalSamples=trainingReader.readDataImageOgr(trainingMap,fields,band_opt,label_opt[0],tlayer_opt,verbose_opt[0]);
339 if(input_opt.size()){
341 totalTestSamples=inputReader.readDataImageOgr(testMap,fields,band_opt,label_opt[0],tlayer_opt,verbose_opt[0]);
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()){
349 totalTestSamples=inputReader.readDataImageOgr(testMap,fields,bstart_opt[0],bend_opt[0],label_opt[0],tlayer_opt,verbose_opt[0]);
352 trainingReader.close();
354 if(trainingMap.size()<2){
358 string errorstring=
"Error: could not read at least two classes from training input file";
361 if(input_opt.size()&&testMap.size()<2){
362 string errorstring=
"Error: could not read at least two classes from test input file";
367 cerr << error << std::endl;
371 cerr <<
"error catched" << std::endl;
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()){
387 if(classValueMap[mapit->first]>0){
389 std::cout << mapit->first <<
" -> " << classValueMap[mapit->first] << std::endl;
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;
397 if((mapit->second).size()<minSize_opt[0]){
398 trainingMap.erase(mapit);
401 nameVector.push_back(mapit->first);
402 trainingPixels.push_back(mapit->second);
404 std::cout << mapit->first <<
": " << (mapit->second).size() <<
" samples" << std::endl;
409 nclass=trainingPixels.size();
410 if(classname_opt.size())
411 assert(nclass==classname_opt.size());
412 nband=trainingPixels[0][0].size()-2;
414 mapit=testMap.begin();
415 while(mapit!=testMap.end()){
416 if(classValueMap.size()){
418 if(classValueMap[mapit->first]>0){
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;
427 testPixels.push_back(mapit->second);
429 std::cout << mapit->first <<
": " << (mapit->second).size() <<
" samples" << std::endl;
432 if(input_opt.size()){
433 assert(nclass==testPixels.size());
434 assert(nband=testPixels[0][0].size()-2);
440 if(balance_opt[0]>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);
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]);
458 totalSamples+=trainingPixels[iclass].size();
460 assert(totalSamples==nclass*balance_opt[0]);
465 offset.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){
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];
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];
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;
505 if(verbose_opt[0]>=1){
506 std::cout <<
"number of bands: " << nband << std::endl;
507 std::cout <<
"number of classes: " << nclass << std::endl;
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;
533 trainingFeatures[iclass].resize(nctraining[iclass]+nctest[iclass]);
534 for(
int isample=0;isample<nctraining[iclass];++isample){
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]);
546 for(
int isample=0;isample<nctest[iclass];++isample){
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];
555 trainingFeatures[iclass][nctraining[iclass]+isample].push_back((value-offset[iband])/scale[iband]);
558 assert(trainingFeatures[iclass].size()==nctraining[iclass]+nctest[iclass]);
561 assert(ccost_opt.size()>1);
562 if(ccost_opt.size()<3)
563 ccost_opt.push_back(sqrt(ccost_opt[0]*ccost_opt[1]));
564 assert(gamma_opt.size()>1);
565 if(gamma_opt.size()<3)
566 gamma_opt.push_back(sqrt(gamma_opt[0]*gamma_opt[1]));
567 assert(ccost_opt.size()==3);
568 assert(gamma_opt.size()==3);
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]);
576 std::vector<double> x(2);
585 const char* pszMessage;
586 void* pProgressArg=NULL;
587 GDALProgressFunc pfnProgress=GDALTermProgress;
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]){
597 std::vector<double> theGrad;
599 kappa=objFunction(x,theGrad,&trainingFeatures);
606 std::cout << ccost <<
" " << gamma <<
" " << kappa<< std::endl;
607 progress+=1.0/ncost/ngamma;
609 pfnProgress(progress,pszMessage,pProgressArg);
614 pfnProgress(progress,pszMessage,pProgressArg);
665 std::cout <<
" --ccost " << x[0];
666 std::cout <<
" --gamma " << x[1];
667 std::cout << std::endl;