【问题标题】:Averaging linear separators obtained from SVM从 SVM 获得的平均线性分离器
【发布时间】:2020-07-07 05:25:06
【问题描述】:

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

我熟悉的算法是通过n步SGD得到n个不同的分隔符w_i,然后对它们进行平均(具体可以看https://www.cse.huji.ac.il/~shais/Lectures2014/lecture8.pdf的幻灯片12)。

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

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

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

【问题讨论】:

  • 那么一次加载整个 DS 是您当前的问题吗?您是否尝试过整个 DS 的一小部分样本,看看结果对您来说是否合理?
  • 这不是为了性能,而是为了研究,我确实需要能够使用整个 DS

标签: python machine-learning scikit-learn svm


【解决方案1】:

基于将所有数据加载到内存中的考虑,如果您可以访问更多计算资源,您可能希望使用 PySpark 的 SVM 实现:https://spark.apache.org/docs/2.2.0/ml-classification-regression.html#linear-support-vector-machine,因为 Spark 是为大规模数据处理而构建的。我不知道对来自多个 Scikit-Learn 模型的分隔符进行平均是否会按预期工作;根据文档 (https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html),没有一种干净的方法可以用新的分隔符实例化一个新模型,因此它可能必须作为一种集成方法来实现。

【讨论】:

  • 这个实现不使用 SGD,不幸的是这对我来说是一个要求。另外,改变sklearn的SVM对象的线性分隔符也不难:svm_classifier.coef_ = new_vec
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    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%。尽管这些性能大致相似,但正如这些测量结果所示,请注意它们并不相同。这是意料之中的,因为这些算法使用pretty different optimization algorithms,但我认为仔细调整超参数会缩小差距。

    【讨论】:

      猜你喜欢
      • 2016-02-21
      • 2015-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-14
      • 2018-10-16
      • 2017-05-20
      相关资源
      最近更新 更多