Strange XML file behaviour
I trained the svm classifier using the following code and it gave me wrong classification and when i looked at the saved xml file, i found strange contents. Only one vector is in the xml file and the classification is -1 for all the test data. I found that the classifier will be the same before and after classifier.train(...). Here is the code:
Log.i(TAG,"Training...");
v_features.copyTo(trainingData);
trainingData.convertTo(trainingData, CvType.CV_32F);
trainingLabels.copyTo(classes);
classes.convertTo(classes, CvType.CV_32S);
classes.convertTo(classes, CvType.CV_32S);
CvSVMParams params = new CvSVMParams();
//first method working fine
params.set_svm_type(CvSVM.C_SVC);
params.set_kernel_type(CvSVM.LINEAR);
params.set_gamma(0.01);
params.set_nu(0.5);
params.set_C(1000);
TermCriteria criteria = new TermCriteria(TermCriteria.MAX_ITER,100, 1e-6);
params.set_term_crit(criteria);
// initialize SVM object to avoid being Null object
classifier = new CvSVM(trainingData, classes, new Mat(), new Mat(), params);
classifier.save(XML1.toString());
classifier.train(trainingData, classes, new Mat(), new Mat(), params);
classifier.save(XML.toString());
Here the xml file:
<?xml version="1.0"?>
<opencv_storage>
<my_svm type_id="opencv-ml-svm">
<svm_type>C_SVC</svm_type>
<kernel>
<type>LINEAR</type>
</kernel>
<C>1000.</C>
<term_criteria>
<epsilon>2.2204460492503131e-16</epsilon>
<iterations>100</iterations>
</term_criteria>
<var_all>18</var_all>
<var_count>18</var_count>
<class_count>2</class_count>
<class_labels type_id="opencv-matrix">
<rows>1</rows>
<cols>2</cols>
<dt>i</dt>
<data> -1 1</data>
</class_labels>
<sv_total>1</sv_total>
<support_vectors>
<_> -9.17065036e-18 7.35845397e-18 -5.99237967e-18 4.50786054e-18 1.91758168e-18 1.38351872e-18 -3.33754597e-18 1.15368551e-17 -2.76280041e-18 3.05637369e-19 -6.48722237e-19 -2.11365533e-18 -1.00750228e-10 3.54062057e-10 1.56639299e-10 0. 3.43815959e-14 -2.05199830e-14</_>
</support_vectors>
-<decision_functions>
-<_>
<sv_count>1</sv_count>
<rho>-4.7668412450595643e-01</rho>
<alpha> 1.</alpha>
<index> 0</index>
</_>
</decision_functions>
</my_svm>
</opencv_storage>
while when I change the line classifier.train(trainingData, classes, new Mat(), new Mat(), params); to classifier.train(trainingData, classes);, the classifier will take the default values instead of the assigned parameter and the decision function will be 1.
here is the xml file:
<?xml version="1.0"?>
-<opencv_storage>
-<my_svm type_id="opencv-ml-svm">
<svm_type>C_SVC</svm_type>
-<kernel>
<type>RBF</type>
<gamma>1.</gamma>
</kernel>
<C>1.</C>
-<term_criteria>
<epsilon>1.1920928955078125e-07</epsilon>
<iterations>1000</iterations>
</term_criteria>
<var_all>18</var_all>
<var_count>18</var_count>
<class_count>2</class_count>
-<class_labels type_id="opencv-matrix">
<rows>1</rows>
<cols>2</cols>
<dt>i</dt>
<data> -1 1</data>
</class_labels>
<sv_total>78</sv_total>
-<support_vectors>
<_> 3.82838593e+01 7.11920929e+00 -4.67479944e+00 1.22517595e+01 3.15141797e+00 2.35791826e+00 4.94117661e+01 13. -1. -9.08270061e-01 -1.86607766e+00 -1.55849302e+00 1.53999995e+10 531000000. 229000000. 0. 4.85476406e+04 -2.60734746e+04</_>
<_> 3.96895714e+01 9.19926834e+00 -3.27970743e+00 1.25011663e+01 3.11253858e+00 1.48126924e+00 4.98039207e+01 14. -1. -8.09072375e-01 -1.54238451e+00 -1.53902304e+00 471000000. 25300000. 3218436. 0. 1.16598379e+04 -2.38160229e+03</_>
<_> 3.66479874e+01 9.63044548e+00 -8.07036877e+00 8.72248554e+00 2.52424383e+00 2.28012586e+00 4.86274529e+01 14. -4. -1.37340033e ...
if you do not pass svm params to the constructor or to train(), an RBF kernel will be used, not a linear one.
a LINEAR SVM uses a single support vector, RBF many.
Thanks for your comment. I passed them in the constructor but it doesn't work. I explained this in the question.
classifier = new CvSVM(trainingData, classes, new Mat(), new Mat(), params); classifier.save(XML1.toString()); classifier.train(trainingData, classes); classifier.save(XML.toString());
if you pass your traindata to the constructor, it will do a training, too. so you got 2 train runs saved to disc, one is using your params anda linear kernel, the second is using default values (RBM kernel)
sure, results differ, but where is the actual problem ?
Thanks. I did not know that even the constructor will train the model with out calling the method .train(). The problem why the number of support vector in the first case is 1 while in the second case is 78 which exactly equal to my training data. the other problem in the first case all the predictions will be -1 while on the second case the predictions will be 1.
again, then the problem will be more in the svm params. e.g. nu and gamma are never used for linear kernel & SVC, but try to change C to 100,50,20,10,0.5, ...
Thank you so much @berak for the support. I knew the problem now: it is because I put the constructor after defining the SVM parameters. It seems I have now good accuracy and I changed the c variables and it makes difference.