Strange XML file behaviour

asked 2017-07-25 06:50:55 -0600

Nani gravatar image

updated 2017-07-25 06:58:38 -0600

berak gravatar image

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 ...
(more)
edit retag flag offensive close merge delete

Comments

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.

berak gravatar imageberak ( 2017-07-25 07:05:20 -0600 )edit

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());

Nani gravatar imageNani ( 2017-07-25 07:10:33 -0600 )edit

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 ?

berak gravatar imageberak ( 2017-07-25 07:54:51 -0600 )edit

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.

Nani gravatar imageNani ( 2017-07-25 08:17:19 -0600 )edit

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, ...

berak gravatar imageberak ( 2017-07-25 09:04:40 -0600 )edit

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.

Nani gravatar imageNani ( 2017-07-26 11:11:09 -0600 )edit