从 SVM 获得的平均线性分隔符

Averaging linear separators obtained from SVM

出于研究目的,我发现自己需要在大型 DS(即大量示例)上通过 SGD 训练 SVM。这使得使用 scikit-learn 的实现 (SGDClassifier) 存在问题,因为它需要一次加载整个 DS。

我熟悉的算法是用n步SGD得到n个不同的分隔符w_i,然后取平均(具体可以看https://www.cse.huji.ac.il/~shais/Lectures2014/lecture8.pdf的slide 12)

这让我想到也许我可以使用 scikit-learn 来训练多个这样的分类器,然后取所得线性分隔符的平均值(假设没有偏差)。

这是一个合理的思路,还是 scikit-learn 的实现不符合我的逻辑?

编辑:我很清楚以不同方式训练 SVM 的替代方案,但这是为了特定的研究目的。我只想知道这种思路是否可以通过 scikit-learn 的实现实现,或者您是否知道一种替代方法,它允许我使用 SGD 训练 SVM 而无需将整个 DS 加载到内存中。

基于将所有数据加载到内存中的考虑,如果您可以访问更多计算资源,您可能希望使用 PySpark 的 SVM 实现:https://spark.apache.org/docs/2.2.0/ml-classification-regression.html#linear-support-vector-machine, as that Spark is built for large scale data processing. I don't know if averaging the separators from multiple Scikit-Learn models would work as expected; there isn't a clean way to instantiate a new model with new separators, based on the documentation (https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html),因此它可能必须是作为整体方法实施。

如果您坚持使用整个 DS 进行训练而不是采样(顺便说一句,这就是幻灯片所描述的)并且您不关心性能,我会训练 n 个分类器,然后 select 仅他们的支持向量并仅在这些支持向量上重新训练最终版本。通过这种方式,您可以有效地忽略大部分数据,只专注于对分类很重要的点。

SGDClassifier 有一个 partial_fit 方法,partial_fit 方法的主要目标之一是将 sklearn 模型扩展到大规模数据集。使用它,您可以将一部分数据集加载到 RAM 中,将其提供给 SGD,并不断重复此过程,除非使用了完整的数据集。

在下面的代码中,我使用KFold主要是为了模拟加载数据块。

class GD_SVM(BaseEstimator, ClassifierMixin):
    def __init__(self):
        self.sgd = SGDClassifier(loss='hinge',random_state=42,fit_intercept=True,l1_ratio=0,tol=.001)

    def fit(self,X,y):
        cv = KFold(n_splits=10,random_state=42,shuffle=True)
        for _,test_id in cv.split(X,y):
            xt,yt = X[test_id],y[test_id]
            self.sgd = self.sgd.partial_fit(xt,yt,classes=np.unique(y))

    def predict(self,X):
        return self.sgd.predict(X)

针对常规(线性)SVM 进行测试:

X,y = load_breast_cancer(return_X_y=True)
X = StandardScaler().fit_transform(X)   #For simplicity, Pipeline is better choice
cv = RepeatedStratifiedKFold(n_splits=5,n_repeats=5,random_state=43)
sgd = GD_SVM()
svm = LinearSVC(loss='hinge',max_iter=1,random_state=42,
                C=1.0,fit_intercept=True,tol=.001)
r = cross_val_score(sgd,X,y,cv=cv)    #cross_val_score(svm,X,y,cv=cv)
print(r.mean())

以上 GD_SVM 的准确率为 95%,SVM 的准确率为 96%。在 Digits 数据集中,SVM 的准确率为 93%,而 GD_SVM 的准确率为 91%。尽管这些性能大致相似,但正如这些测量结果所示,请注意它们并不完全相同。这是预料之中的,因为这些算法使用 ,但我认为仔细调整超参数会缩小差距。