将经过训练的 SVM 从 scikit-learn 导入到 OpenCV

Posted

技术标签:

【中文标题】将经过训练的 SVM 从 scikit-learn 导入到 OpenCV【英文标题】:Import trained SVM from scikit-learn to OpenCV 【发布时间】:2013-05-25 19:33:38 【问题描述】:

我正在将使用支持向量机的算法从 Python(使用 scikit-learn)移植到 C++(使用 OpenCV 的机器学习库)。

我可以使用 Python 访问经过训练的 SVM,并且可以将 SVM 模型参数从 XML 文件导入 OpenCV。由于 scikit-learn 和 OpenCV 的 SVM 实现都是基于 LibSVM,我认为应该可以在 OpenCV 中使用训练好的 scikit SVM 的参数。

以下示例显示了一个 XML 文件,可用于在 OpenCV 中初始化 SVM:

<?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>

我现在想用来自经过训练的 scikit-learn SVM 的值填充这个 XML 文件。但我不确定 scikit-learn 和 OpenCV 的参数是如何对应的。这是我目前所拥有的(clf 是 Python 中的分类器对象):

&lt;kernel&gt;&lt;gamma&gt; 对应于clf.gamma &lt;C&gt; 对应于clf.C &lt;term_criteria&gt;&lt;epsilon&gt; 对应于clf.tol &lt;support_vectors&gt; 对应于clf.support_vectors_

到目前为止这是正确的吗?现在这里是我不太确定的项目:

&lt;term_criteria&gt;&lt;iterations&gt; 呢? &lt;decision_functions&gt;&lt;_&gt;&lt;rho&gt;是否对应clf.intercept_&lt;decision_functions&gt;&lt;_&gt;&lt;alpha&gt; 是否对应于clf.dual_coef_?在这里我不确定,因为 scikit-learn 文档说“dual_coef_ 包含产品 yiαi”。看起来 OpenCV 只需要 αi,而不需要 yiαi

【问题讨论】:

【参考方案1】:

您不再需要epsiloniterations,它们用于训练优化问题。您可以将它们设置为您喜欢的数字或忽略它们。

移植支持向量可能需要一些麻烦,因为scikit-learn 和opencv 之间的索引可能不同。例如,您示例中的 XML 没有稀疏格式。

至于其他参数:

rho 应该对应intercept_,但您可能需要更改符号。 scikit 的 dual_coef_ 对应于标准 libsvm 模型中的 sv_coef(即 alpha_i*y_i)。

如果opencv 在移植时抱怨您为alpha 提供的值,请使用scikit-learn 的dual_coef_ 的绝对值(例如,全部为正)。这些是 SVM 模型的真实 alpha 值。

【讨论】:

感谢您的回答。我还没有尝试过,但无论如何你的答案包含一些非常有用的信息。如何知道是否需要更改intercept_ 的符号? @RobertHegner,您可以使用几个测试点,在 scikit 和 opencv 中相同。如果截距的符号错误,预测中的决策值将相差 2*intercept。 仅供参考:intercept_的符号我不用改,dual_coef_的绝对值也不用改。它似乎工作得很好!再次感谢马克! 您确定需要传递 dual_coef 而不是 coef_ 作为原始问题的系数吗?使用 hog.setSVMDetector() 我知道我需要通过 np.append(coef_, intercept_)

以上是关于将经过训练的 SVM 从 scikit-learn 导入到 OpenCV的主要内容,如果未能解决你的问题,请参考以下文章

使用 scikit-learn 训练数据时,SVM 多类分类停止

将 scikit-learn SVM 模型转换为 LibSVM

如何获取 Scikit-learn 的 svm 中的训练误差?

如何在 scikit-learn 中继续训练 svm 和 knn?

如何从 scikit-learn 中的 TransformedTargetRegressor 管道中的经过训练的估计器访问属性?

scikit-learn svm库使用小结