【问题标题】:Implementation of SVM for classification without library in c++在C++中实现无库分类的SVM
【发布时间】:2015-02-14 13:49:32
【问题描述】:

我最近几周正在研究支持向量机。我了解如何将数据分为两类的理论概念。但我不清楚如何选择支持向量并生成分隔线以使用 C++ 对新数据进行分类。

假设,我有两个类的两个训练数据集

绘制数据后,我得到以下带有向量的特征空间,这里的分隔线也很清晰。

如何在没有库函数的情况下在 C++ 中实现这一点。它将帮助我理清关于 SVM 的实现概念。我需要明确实施,因为我将在我的母语的意见挖掘中应用 SVM。

【问题讨论】:

  • SVM 导致优化问题。您需要非常强大的计算数学知识来解决它,例如二次规划优化
  • 那么,我应该去图书馆吗?
  • 不使用现有库的限制是否是自我强加的,以便了解实现的工作原理?
  • @AerofoilKite:你应该总是去图书馆。尽管如此,这个问题很有趣,可以从计算的角度更好地理解如何处理这样的问题
  • @MatthiasB,现有库无法帮助我理解支持向量选择的实现。你能推荐我吗?

标签: c++ machine-learning classification svm


【解决方案1】:

我会同意大多数人的建议,并说您应该真正考虑使用库。如果由于您的实现中的错误而导致某些东西无法正常工作,SVM 算法就足够棘手了。甚至没有谈论在内存大小和时间上进行可扩展的实现有多难。

也就是说,如果您想将其作为一种学习体验进行探索,那么 SMO 可能是您的最佳选择。以下是您可以使用的一些资源:

The Simplified SMO Algorithm - Stanford material PDF

Fast Training of Support Vector Machines - PDF

The implementation of Support Vector Machines using the sequential minimal optimization algorithm - PDF

我找到的最实用的解释可能是 Peter Harrington 所著的 Machine Learning in action 一书第 6 章中的解释。代码本身在 Python 上,但您应该能够将其移植到 C++。我不认为这是最好的实现,但它可能足以了解正在发生的事情。

代码免费提供:

https://github.com/pbharrin/machinelearninginaction/tree/master/Ch06

很遗憾,该章节没有样例,但许多本地图书馆倾向于提供这本书。

【讨论】:

    【解决方案2】:

    大多数情况下,SVM 都使用 SMO 算法进行训练——这是一种坐标下降的变体,特别适合问题的拉格朗日。 这有点复杂,但如果简化版本可以满足您的目的,我可以提供 Python 实现。 可能,您将能够将其翻译成 C++

    class SVM:
      def __init__(self, kernel='linear', C=10000.0, max_iter=100000, degree=3, gamma=1):
        self.kernel = {'poly'  : lambda x,y: np.dot(x, y.T)**degree,
                       'rbf'   : lambda x,y: np.exp(-gamma*np.sum((y - x[:,np.newaxis])**2, axis=-1)),
                       'linear': lambda x,y: np.dot(x, y.T)}[kernel]
        self.C = C
        self.max_iter = max_iter
    
      def restrict_to_square(self, t, v0, u):
        t = (np.clip(v0 + t*u, 0, self.C) - v0)[1]/u[1]
        return (np.clip(v0 + t*u, 0, self.C) - v0)[0]/u[0]
    
      def fit(self, X, y):
        self.X = X.copy()
        self.y = y * 2 - 1
        self.lambdas = np.zeros_like(self.y, dtype=float)
        self.K = self.kernel(self.X, self.X) * self.y[:,np.newaxis] * self.y
        
        for _ in range(self.max_iter):
          for idxM in range(len(self.lambdas)):
            idxL = np.random.randint(0, len(self.lambdas))
            Q = self.K[[[idxM, idxM], [idxL, idxL]], [[idxM, idxL], [idxM, idxL]]]
            v0 = self.lambdas[[idxM, idxL]]
            k0 = 1 - np.sum(self.lambdas * self.K[[idxM, idxL]], axis=1)
            u = np.array([-self.y[idxL], self.y[idxM]])
            t_max = np.dot(k0, u) / (np.dot(np.dot(Q, u), u) + 1E-15)
            self.lambdas[[idxM, idxL]] = v0 + u * self.restrict_to_square(t_max, v0, u)
        
        idx, = np.nonzero(self.lambdas > 1E-15)
        self.b = np.sum((1.0 - np.sum(self.K[idx] * self.lambdas, axis=1)) * self.y[idx]) / len(idx)
      
      def decision_function(self, X):
        return np.sum(self.kernel(X, self.X) * self.y * self.lambdas, axis=1) + self.b
    

    在简单的情况下,它的效果并不比 sklearn.svm.SVC 好,比较如下所示

    有关公式的更详细解释,您可能需要参考this ResearchGate preprint。 生成图片的代码可以在GitHub找到。

    【讨论】:

      猜你喜欢
      • 2020-06-10
      • 2013-11-22
      • 2019-06-04
      • 2019-04-02
      • 2012-02-07
      • 2015-03-05
      • 2020-08-29
      • 2019-01-14
      • 2015-01-08
      相关资源
      最近更新 更多