簡體   English   中英

用C++實現無庫分類的SVM

[英]Implementation of SVM for classification without library in c++

我最近幾周正在學習支持向量機。 我了解如何將數據分為兩類的理論概念。 但是我不清楚如何選擇支持向量並生成分隔線以使用 C++ 對新數據進行分類。

假設,我有兩個類的兩個訓練數據集

在此處輸入圖片說明

繪制數據后,我得到以下帶有向量的特征空間,在這里,分隔線也很清晰。

在此處輸入圖片說明

如何在沒有庫函數的情況下在 C++ 中實現這一點。 它將幫助我明確我關於 SVM 的實現概念。 我需要明確實施,因為我將在我的母語的意見挖掘中應用 SVM。

我會加入大多數人的建議,並說你真的應該考慮使用圖書館。 如果由於您的實現中的錯誤而導致某些內容無法正常工作,SVM 算法會非常棘手,可以添加噪音。 甚至沒有談論在內存大小和時間上實現可擴展的實現有多困難。

也就是說,如果您想將其作為一種學習體驗來探索,那么 SMO 可能是您最好的選擇。 以下是您可以使用的一些資源:

簡化的 SMO 算法 - 斯坦福材料 PDF

支持向量機的快速訓練 - PDF

使用順序最小優化算法實現支持向量機 - PDF

可能我找到的最實用的解釋是 Peter Harrington 所著《機器學習實戰》一書第 6 章中的解釋。 代碼本身在 Python 上,但您應該能夠將其移植到 C++。 我不認為這是最好的實現,但它可能足以了解正在發生的事情。

代碼是免費提供的:

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

不幸的是,該章節沒有樣本,但許多當地圖書館傾向於提供這本書。

大多數情況下 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 值多少,比較如下所示在此處輸入圖片說明

有關公式的更詳細解釋,您可能需要參考此 ResearchGate 預印本 可以在GitHub 上找到生成圖像的代碼。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM