如何强制 SVC 将用户提供的内核视为稀疏的

Posted

技术标签:

【中文标题】如何强制 SVC 将用户提供的内核视为稀疏的【英文标题】:How to force SVC to treat a user-provided kernel as sparse 【发布时间】:2017-01-20 10:46:54 【问题描述】:

SVC 似乎将可以采用稀疏矩阵的内核与不能采用稀疏矩阵的内核区别对待。但是,如果编写用户提供的内核来获取稀疏矩阵,并且在拟合期间提供了稀疏矩阵,它仍然会将稀疏矩阵转换为稠密并将内核视为稠密,因为该内核不是预先的稀疏内核之一在 scikit-learn 中定义。

有没有办法强制 SVC 将内核识别为稀疏的,并且在将稀疏矩阵传递给内核之前不将其转换为密集矩阵?

编辑 1:最小的工作示例

例如,如果在创建时,SVC 被传递给内核的字符串“linear”,然后使用线性内核,将稀疏矩阵直接传递给线性内核,并将支持向量存储为稀疏矩阵如果拟合时提供了稀疏矩阵。但是,如果将 linear_kernel 函数本身传递给 SVC,则稀疏矩阵在传递给内核之前会转换为 ndarray,并且支持向量将存储为 ndarray。

import numpy as np
from scipy.sparse import csr_matrix
from sklearn.metrics.pairwise import linear_kernel
from sklearn.svm import SVC


def make_random_sparsemat(m, n=1024, p=.94):
    """Make mxn sparse matrix with 1-p probability of 1."""
    return csr_matrix(np.random.uniform(size=(m, n)) > p, dtype=np.float64)


X = make_random_sparsemat(100)
Y = np.asarray(np.random.uniform(size=(100)) > .5, dtype=np.float64)
model1 = SVC(kernel="linear")
model1.fit(X, Y)
print("Built-in kernel:")
print("Kernel treated as sparse: ".format(model1._sparse))
print("Type of dual coefficients: ".format(type(model1.dual_coef_)))
print("Type of support vectors: ".format(type(model1.support_vectors_)))

model2 = SVC(kernel=linear_kernel)
model2.fit(X, Y)
print("User-provided kernel:")
print("Kernel treated as sparse: ".format(model2._sparse))
print("Type of dual coefficients: ".format(type(model2.dual_coef_)))
print("Type of support vectors: ".format(type(model2.support_vectors_)))

输出:

Built-in kernel:
Kernel treated as sparse: True
Type of dual coefficients: <class 'scipy.sparse.csr.csr_matrix'>
Type of support vectors: <class 'scipy.sparse.csr.csr_matrix'>
User-provided kernel:
Kernel treated as sparse: False
Type of dual coefficients: <type 'numpy.ndarray'>
Type of support vectors: <type 'numpy.ndarray'>

【问题讨论】:

你能放一些示例代码供我们使用吗? 预定义稀疏内核的例子是什么?我知道稀疏矩阵,但对 SVC 知之甚少。 @maxymoo,我刚刚添加了一些代码。 @hpaulj,预定义的稀疏内核在 sklearn.svm.SVC._sparse_kernels 中指定。例如,线性核是一个稀疏核,因为它可以将稀疏矩阵作为输入并直接处理它们,而无需将它们转换为数组,这样效率会降低。 【参考方案1】:

我在黑暗中摸索,主要使用在github 上找到的scikit-learn 代码。

很多 SVC linear 代码似乎在 C 库中。有人谈论它的内部表示是稀疏的。

你的 linear_kernel 函数就可以了:

X, Y = check_pairwise_arrays(X, Y)
return safe_sparse_dot(X, Y.T, dense_output=True)

如果我让你的XY

In [119]: X
Out[119]: 
<100x1024 sparse matrix of type '<class 'numpy.float64'>'
    with 6108 stored elements in Compressed Sparse Row format>
In [120]: 
In [120]: 
In [120]: Y = np.asarray(np.random.uniform(size=(100)) > .5, dtype=np.float64)

并重新创建sparse_safe_dot

In [122]: safe_sparse_dot(Y,X,dense_output=True)
Out[122]: array([ 3.,  5.,  3., ...,  4.,  2.,  4.])

因此,将其应用于YX(以唯一有意义的顺序),我得到了一个密集数组。更改 dense_output 参数不会改变任何事情。基本上,Y*X,一个稀疏 * 一个稠密,返回一个稠密。

如果我使Y 稀疏,那么我可以得到一个稀疏的产品:

In [125]: Ym=sparse.csr_matrix(Y)
In [126]: Ym*X
Out[126]: 
<1x1024 sparse matrix of type '<class 'numpy.float64'>'
    with 1000 stored elements in Compressed Sparse Row format>
In [127]: safe_sparse_dot(Ym,X,dense_output=False)
Out[127]: 
<1x1024 sparse matrix of type '<class 'numpy.float64'>'
    with 1000 stored elements in Compressed Sparse Row format>
In [128]: safe_sparse_dot(Ym,X,dense_output=True)
Out[128]: array([[ 3.,  5.,  3., ...,  4.,  2.,  4.]])

我不知道SVCfit 的工作原理,但仅从处理稀疏矩阵,我知道在混合稀疏矩阵和稠密矩阵时必须小心。无论您是否愿意,都可以轻松获得密集的结果。

【讨论】:

以上是关于如何强制 SVC 将用户提供的内核视为稀疏的的主要内容,如果未能解决你的问题,请参考以下文章

linux内核如何强制堆栈大小限制?

内核 SVC 不断收到 RandomSearchCV 中的参数错误

带有 rbf 内核的 SVC 的 10 大功能

GridSearchCV 是用 rbf 内核和不同程度计算 SVC 吗?

如何为 sklearn.svm.SVC 定义自定义内核函数?

多核 C++ 线程