在c ++中实现SVM用于无库分类

时间:2014-12-16 09:35:12

标签: c++ machine-learning classification svm

我在几周内学习了支持向量机。我理解如何将数据分类为两个类的理论概念。但我不清楚如何选择支持向量并生成分离线来使用C ++对新数据进行分类。

假设我有两个班级的两个训练数据集

enter image description here

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

enter image description here

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

2 个答案:

答案 0 :(得分: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所着的“机器学习”一书的第6章。代码本身在Python上,但您应该能够将其移植到C ++。我不认为这是最好的实现,但它可能足以了解正在发生的事情。

代码免费提供:

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

不幸的是,该章没有样本,但很多本地图书馆都倾向于提供这本书。

答案 1 :(得分:1)

大多数情况下,使用SMO算法对SVM进行训练-坐标下降的一种变化特别适合该问题的拉格朗日式。 这有点复杂,但是如果简化版本适合您的目的,我可以提供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的价值不高,如下所示 enter image description here

有关公式的更详细说明,您可能需要参考this ResearchGate preprint。 可以在GitHub上找到用于生成图像的代码。