Import trained SVM from scikit-learn to OpenCV
Asked Answered
W

1

5

I'm porting an algorithm that uses a Support Vector Machine from Python (using scikit-learn) to C++ (using the machine learning library of OpenCV).

I have access to the trained SVM in Python, and I can import SVM model parameters from an XML file into OpenCV. Since the SVM implementation of both scikit-learn and OpenCV is based on LibSVM, I think it should be possible to use the parameters of the trained scikit SVM in OpenCV.

The example below shows an XML file which can be used to initialize an SVM in OpenCV:

<?xml version="1.0"?>
<opencv_storage>
<my_svm type_id="opencv-ml-svm">
  <svm_type>C_SVC</svm_type>
  <kernel><type>RBF</type>
    <gamma>0.058823529411764705</gamma></kernel>
  <C>100</C>
  <term_criteria><epsilon>0.0</epsilon>
    <iterations>1000</iterations></term_criteria>
  <var_all>17</var_all>
  <var_count>17</var_count>
  <class_count>2</class_count>
  <class_labels type_id="opencv-matrix">
    <rows>1</rows>
    <cols>2</cols>
    <dt>i</dt>
    <data>
      0 1</data></class_labels>
  <sv_total>20</sv_total>
  <support_vectors>
    <_>
      2.562423055146794554e-02 1.195797425735170838e-01
      8.541410183822648050e-02 9.395551202204914520e-02
      1.622867934926303379e-01 3.074907666176152077e-01
      4.099876888234874062e-01 4.697775601102455179e-01
      3.074907666176152077e-01 3.416564073529061440e-01
      5.124846110293592716e-01 5.039432008455355660e-01
      5.466502517646497639e-01 1.494746782168964394e+00
      4.168208169705446942e+00 7.214937388193202183e-01
      7.400275229357797802e-01</_>
    <!-- omit 19 vectors to keep it short -->
  </support_vectors>
  <decision_functions>
    <_>
      <sv_count>20</sv_count>
      <rho>-5.137523249549433402e+00</rho>
      <alpha>
        2.668992955678978518e+01 7.079767098112181145e+01
        3.554240018130368384e+01 4.787014908624512088e+01
        1.308470223155845069e+01 5.499185410034550614e+01
        4.160483074010306126e+01 2.885504210853826379e+01
        7.816431542954153144e+01 6.882061506693679576e+01
        1.069534676985309574e+01 -1.000000000000000000e+02
        -5.088050252552544350e+01 -1.101740897543916375e+01
        -7.519686789702373630e+01 -3.893481464245511603e+01
        -9.497774056452135483e+01 -4.688632332663718927e+00
        -1.972745089701982835e+01 -8.169343841768861125e+01</alpha>
      <index>
        0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
        </index></_></decision_functions></my_svm>
</opencv_storage>

I would now like to fill this XML file with values from the trained scikit-learn SVM. But I'm not sure how the parameters of scikit-learn and OpenCV correspond. Here is what I have so far (clf is the classifier object in Python):

  • <kernel><gamma> corresponds to clf.gamma
  • <C> corresponds to clf.C
  • <term_criteria><epsilon> corresponds to clf.tol
  • <support_vectors> corresponds to clf.support_vectors_

Is this correct so far? Now here are the items I'm not really sure:

  • What about <term_criteria><iterations>?
  • Does <decision_functions><_><rho> correspond to clf.intercept_?
  • Does <decision_functions><_><alpha> correspond to clf.dual_coef_? Here I'm not sure because the scikit-learn documentation says "dual_coef_ which holds the product yiαi". It looks like OpenCV expects only αi, and not yiαi.
Ways answered 30/5, 2013 at 9:32 Comment(0)
E
7

You don't need epsilon and iterations anymore, those are used in the training optimization problem. You can set them to your favorite number or ignore them.

Porting the support vectors may require some fiddling, as indexing may be different between and . The XML in your example has no sparse format for example.

As for the other parameters:

  • rho should correspond to intercept_, but you may need to change sign.
  • scikit's dual_coef_ corresponds to sv_coef in standard models (which is alpha_i*y_i).

If complains about the values you provide for alpha when porting, use absolute values of 's dual_coef_ (e.g. all positive). These are the true alpha values of an SVM model.

Euphrosyne answered 30/5, 2013 at 14:18 Comment(4)
Thank you for this answer. I haven't tried it yet, but anyway your answer contains some very useful information. How can I find out if I need to change the sign of intercept_?Ways
@RobertHegner, you can use a few test points, identical in scikit and opencv. If the intercept's sign is wrong, the decision values in prediction will differ by exactly 2*intercept.Euphrosyne
Just as a reference for others: I didn't have to change the sign of intercept_, and I didn't have to use the absolute value of dual_coef_. It seems to work perfectly well! Thanks again Marc!Ways
are you sure you need to pass dual_coef and not coef_ as the coefficient of the primal problem? Using the hog.setSVMDetector() i understood i need to pass np.append(coef_, intercept_)Aspirator

© 2022 - 2024 — McMap. All rights reserved.