寻找 SVM 最佳元参数的快速方法(比网格搜索更快)

机器算法验证 交叉验证 支持向量机
2022-01-31 20:44:43

我正在使用 SVM 模型对空气污染物进行短期预测。为了训练一个新模型,我需要为 SVM 模型找到合适的元参数(我的意思是 C、gamma 等)。

Libsvm 文档(以及我读过的许多其他书籍)建议使用网格搜索来查找这些参数 - 所以我基本上为特定集合中这些参数的每个组合训练模型并选择最佳模型。

有没有更好的方法来找到最优(或接近最优)的元参数?对我来说,这主要是计算时间的问题——这个问题的一次网格搜索大约需要两个小时(在我做了一些优化之后)。

网格搜索的优点:

  • 它可以很容易地并行化——如果你有 20 个 CPU,它的运行速度会快 20 倍,并行化其他方法更难
  • 你检查元参数空间的大部分,所以如果有一个好的解决方案,你会找到它。
4个回答

网格搜索的缺点是运行时间的增长速度与每个参数的选项数量的乘积一样快。

这是Alex Smola 的博客中与您的问题相关的一个条目

这是一个报价:

[...] 从您的数据集中随机挑选 1000 对 (x,x'),计算所有这些对的距离并取中位数、0.1 和 0.9 分位数。现在选择 λ 作为这三个数字中的任何一个的倒数。通过一点交叉验证,您将找出三者中的哪一个是最好的。在大多数情况下,您不需要进一步搜索。

我自己没有尝试过,但它看起来确实很有希望。

如果您假设在参数网格下存在一个相对平滑的函数,那么您可以做一些事情。例如,一种简单的启发式方法是从一个非常粗略的参数网格开始,然后在粗网格中最好的参数设置周围使用更精细的网格。

这在实践中往往效果很好,当然有一些警告。首先是空间不一定是平滑的,可能存在局部最优粗网格可能会完全错过这些,您最终可能会得到一个次优的解决方案。另请注意,如果您的保留集中的样本相对较少,那么您可能有很多参数设置给出相同的分数(错误或您使用的任何指标)。如果您正在进行多类学习(例如,使用一对多的方法),并且您的保留集中每个类中只有几个示例,这可能会特别成问题。然而,如果不求助于讨厌的非线性优化技术,这可能是一个很好的起点。

这里有一组很好的参考资料在过去,我采用的方法是,您可以通过检查内核来合理地估计一个好的内核超参数范围(例如,在 RBF 内核的情况下,确保内核值的直方图给出了良好的值分布,而不是偏向 0 或 1 - 您也可以自动执行此操作而无需太多工作),这意味着您可以在开始之前缩小范围。然后,您可以将搜索重点放在任何其他参数上,例如正则化/容量参数。然而,这当然只适用于预先计算的内核,尽管如果您不想使用预先计算的内核,您可以在点的随机子集上估计它,我认为这种方法也可以。

我使用模拟退火来搜索参数。

该行为由几个参数控制:

  • k是玻尔兹曼常数。
  • T_max是你的起始温度。
  • T_min是你的结束门槛。
  • mu_T( μ) 是你降低了多少温度 ( T->T/μ)
  • i是每个温度下的迭代次数
  • z是一个步长 - 你确定这到底意味着什么。我在里面随意移动 old*(1±z)
  1. 取一个起点(一组参数值)。
  2. 为它获取能量(它与您的数据的匹配程度;我使用卡方值)。
  3. 朝随机方向看(“迈出一步”)。
    • 如果能量低于你当前的点,移动到那里。
    • 如果它更高,则以概率移动到那里p = e^{-(E_{i+1} - E_i)/(kT)}
  4. 重复,偶尔降低T->T/μ每次i迭代,直到你击中T_min.

稍微调整一下参数,您应该能够找到一个运行良好且快速的集合。

GNU 科学图书馆包括模拟退火。

如果有人对此感兴趣,请谈谈我对这个主题的一些想法:

  • 正如@tdc 建议的那样,我正在做粗/细网格搜索。这引入了两个问题:
    • 在大多数情况下,我会得到一组具有完全不同参数的好的元参数集——我以这种方式解释这些参数是最佳解决方案,但为了确保我应该检查所有这些好的参数附近的所有精细网格(这将花费很多时间),所以现在我只检查下注元参数集的邻域。
    • 在大多数情况下,精细搜索不会提高 SVM 性能(这可能是因为我只检查粗网格中最佳点的邻域。
  • 我观察到大多数计算时间都花在不会产生良好结果的元参数集上的行为,例如:大多数元参数集将在 15 秒内计算(其中最好的错误率为 15%),有些需要 15 分钟(其中大多数的错误率大于 100%)。因此,在进行网格搜索时,我会杀死计算时间超过 30 秒的点,并假设它们存在无限错误。
  • 我使用多处理(这很简单)