提高单个样本的 SVC 预测性能

Posted

技术标签:

【中文标题】提高单个样本的 SVC 预测性能【英文标题】:Improving SVC prediction performance on single samples 【发布时间】:2014-02-21 01:44:56 【问题描述】:

我有用于文本分类的大型 SVC 模型(~50Mb cPickles),我正在尝试在生产环境中使用它们的各种方法。对文档批次进行分类效果非常好(使用predictpredict_proba,每分钟大约可以处理1k 个文档)。 但是,对单个文档的预测是另一回事,正如this question 的评论中所解释的那样:

你是在批量做预测吗?不幸的是,SVC.predict 方法会产生大量开销,因为它必须重建类似于训练算法产生的 LibSVM 数据结构,浅拷贝支持向量,并将测试样本转换为 LibSVM 格式可能与 NumPy/SciPy 格式不同。因此,对单个样本的预测必然会很慢。 – larsmans

我已经将 SVC 模型作为 Flask Web 应用程序提供服务,因此一部分开销已经消失(unpickling),但单个文档的预测时间仍然偏高(0.25 秒)。 我查看了predict 方法中的代码,但不知道是否有办法“预热”它们,在服务器启动时提前重建 LibSVM 数据结构......有什么想法吗?

def predict(self, X):
    """Perform classification on samples in X.

    For an one-class model, +1 or -1 is returned.

    Parameters
    ----------
    X : array-like, sparse matrix, shape = [n_samples, n_features]

    Returns
    -------
    y_pred : array, shape = [n_samples]
        Class labels for samples in X.
    """
    y = super(BaseSVC, self).predict(X)
    return self.classes_.take(y.astype(np.int))

【问题讨论】:

不要使用SVC进行文本分类,不值得。 嗨,我明白你的意思,但我应该指定它是一个多类情感分类(非常不同的类大小)。目前,我正在努力达到最高精度。到目前为止,带有 RBF 内核的 SVC 的性能优于其他所有分类器,尽管差距很小(例如 SVC 0.898、PassiveAggressiveClassifier 0.868、MultinomialNB 0.837)。然而,SVC 在很大程度上优于最小类别的竞争(例如 F1 SVC 0.84、PAC 0.76、MNB 0.68)。如果 SVC 对单个文档的处理速度稍微快一点,我看不出有任何理由不将它用于我当前的数据。 【参考方案1】:

不能提前构造LibSVM数据结构。当对文档进行分类的请求到达时,您会获取文档的文本,从 if 中制作一个向量,然后才转换为 LibSVM 格式,以便您做出决定。

LinearSVC 应该比带有线性内核的SVC 快得多,因为它使用liblinear。如果不会过多降低性能,您可以尝试使用不同的分类器。

【讨论】:

当然,您无法避免处理您应要求获得的一份文件。但是,取决于样本数量的性能差异如此之大,以至于我仍然想知道是否可以提前做点什么。例如,在每个文档上同时调用 predictpredict_proba:100 个文档 5.6157s、10 个文档 0.9705s、2 个文档 0.4969s、1 个文档 0.4551s 更改分类器不是问题的一部分。 LinearSVC 只是SVC 的优化版本,所以你并没有真正改变分类器。 ***.com/questions/11508788/… 您知道LinearSVCSVC 选项之间的区别吗(阅读:非线性内核)?我再说一遍:这不是我的问题的一部分,无需建议更改分类器。【参考方案2】:

我可以看到三种可能的解决方案。

自定义服务器

这不是“加热”任何东西的问题。简单地说 - libSVM 是 C 库,您需要将数据打包/解包为正确的格式。这个过程在整个矩阵上比单独在每一行上更有效。克服这个问题的唯一方法是在您的生产环境和 libSVM 之间编写更有效的包装器(您可以编写一个基于 libsvm 的服务器,它将与您的服务一起使用某种共享内存)。不幸的是,这是可以通过现有实现解决的自定义问题。

批次

像缓冲查询这样的简单方法是一种选择(如果它是具有数千个查询的“高性能”系统,您可以简单地将它们存储在 N 元素批次中,然后以此类包的形式发送到 libSVM)。

自己的分类

最后 - 使用 SVM 进行分类真的是简单的任务。您不需要 libSVM 来执行分类。只有训练是一个复杂的问题。获得所有支持向量 (SV_i)、内核 (K)、拉格氏乘数 (alpha_i) 和截距项 (b) 后,您可以使用以下方法进行分类:

cl(x) = sgn( SUM_i y_i alpha_i K(SV_i, x) + b)

您可以在您的应用程序中直接编写此操作,而无需实际打包/解包/发送任何东西到 libsvm。这可以将事情加快一个数量级。显然 - 检索概率更复杂,因为它需要 Platt 标度,但它仍然是可能的。

【讨论】:

非常有帮助,谢谢。我认为分批是目前的解决方案,但我会尽快尝试分类:-)

以上是关于提高单个样本的 SVC 预测性能的主要内容,如果未能解决你的问题,请参考以下文章

R语言使用线性回归模型来预测(predict)单个样本的目标值(响应值response)实战

boosting

训练准确度提高但验证准确度保持在 0.5,并且模型为每个验证样本预测几乎相同的类别

详解支持向量机-SVC真实数据案例:预测明天是否会下雨-探索标签和处理异常值菜菜的sklearn课堂笔记

R语言基于库克距离统计量识别(Cook’s distance)对于回归模型性能或者预测影响(Influential observation)很大的观测样本可视化库克距离并添加阈值线识别影响力大的样本

R语言基于库克距离统计量识别(Cook’s distance)对于回归模型性能或者预测影响(Influential observation)很大的观测样本可视化库克距离并添加阈值线识别影响力大的样本