首页 > 解决方案 > 从 SVM 获得的平均线性分离器

问题描述

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

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

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

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

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

标签: pythonmachine-learningscikit-learnsvm

解决方案


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())

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


推荐阅读