我有用于文本分类的大型SVC模型(约50Mb cPickles),我正在尝试在生产环境中使用它们的各种方法。对文档批次进行分类非常有效(使用predict
和predict_proba
每分钟大约有1k个文档)。然而,对单个文档的预测是另一回事,正如对这个问题的评论所解释的那样:
您是否批量进行预测?不幸的是,SVC.predict方法产生了大量的开销,因为它必须重建类似于训练算法产生的LibSVM数据结构,在支持向量中进行浅拷贝,并将测试样本转换为可能不同于NumPy/SciPy格式的LibSVM格式。因此,对单个样本的预测必然是缓慢的larsmans
我已经将SVC模型作为Flask web应用程序提供服务,因此部分开销已经消失(取消拾取),但单个文档的预测时间仍然偏高(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))
我可以看到三种可能的解决方案。
自定义服务器
这不是";"变暖";什么都可以。简单地说,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的缩放,但它仍然是可能的。
您不能预先构造LibSVM数据结构。当一个对文档进行分类的请求到达时,你会得到文档的文本,用if生成一个向量,然后转换为LibSVM格式,这样你就可以做出决定。
LinearSVC
应该比具有线性内核的SVC
快得多,因为它使用liblinear
。如果不太降低性能,您可以尝试使用不同的分类器。