簡體   English   中英

我的玩具 SVM 的 Python 版本有什么錯誤?

[英]What's the mistake in my Python version of a toy SVM?

我目前正在閱讀 Andrej Karpathy 的Hacker's guide to Neural Networks 第 2 章:機器學習,二元分類中,他給出了一個(非常基礎的)SVM 的例子。 這是 Karpathy 的代碼:

var a = 1, b = -2, c = -1; // initial parameters
for(var iter = 0; iter < 400; iter++) {
  // pick a random data point
  var i = Math.floor(Math.random() * data.length);
  var x = data[i][0];
  var y = data[i][1];
  var label = labels[i];

// compute pull
  var score = a*x + b*y + c;
  var pull = 0.0;
  if(label === 1 && score < 1) pull = 1;
  if(label === -1 && score > -1) pull = -1;

// compute gradient and update parameters
  var step_size = 0.01;
  a += step_size * (x * pull - a); // -a is from the regularization
  b += step_size * (y * pull - b); // -b is from the regularization
  c += step_size * (1 * pull);
}

以下是我的 Python 版本:

import numpy
import random

X = numpy.array([[1.2, 0.7],
                 [-0.3, 0.5],
                 [-3, -1],
                 [0.1, 1.0],
                 [3.0, 1.1],
                 [2.1, -3]])

labels = [1, -1, 1, -1, -1, 1]

a = 1
b = -2
c = -1

l = len(X)-1

steps = 400

for n in range(0, steps):
    i = random.randint(0, l)
    x = X[i][0]
    y = X[i][1]
    label = labels[i]

    if n == 0:
            for j in range(0, l+1):
                x = X[j][0]
                y = X[j][1]
                label = labels[j]
                score = a*x + b*y + c
                print x,",",y,"-->", label, "vs.", score

    score = a*x + b*y + c
    pull = 0.0
    if label == 1 and score < 1:
        pull = 1
    if label == -1 and score > -1:
        pull = -1

    step_size = 0.01
    a += step_size * (x * pull - a)
    b += step_size * (y * pull - b)
    c += step_size * (1 * pull)

    if n == steps-1:
        print ""
        for j in range(0, l+1):
            x = X[j][0]
            y = X[j][1]
            label = labels[j]
            score = a*x + b*y + c
            print x,",",y,"-->", label, "vs.", score

問題是,即使在超過建議的 400 次迭代之后,對於某些向量,參數也不會產生正確的標簽。

這是 400 次迭代后的輸出:

1.2 , 0.7 --> 1 vs. -0.939483353298
-0.3 , 0.5 --> -1 vs. -0.589208602761
-3.0 , -1.0 --> 1 vs. 0.651953448705
0.1 , 1.0 --> -1 vs. -0.921882586141
3.0 , 1.1 --> -1 vs. -1.44552077331
2.1 , -3.0 --> 1 vs. 0.896623596303

“-->”后的第一個值是正確的標簽,第二個值是分數,即學習到的標簽。

除了第一個標簽外,所有向量/學習標簽都是正確的(從被分配一個帶有正確符號的值的意義上說)。

我不確定這是什么原因:我在代碼中犯了錯誤嗎? 我檢查了幾次,但沒有找到任何東西。 或者我忘記了這里特定於 Python 的東西。 或者,最后,是否有一些與機器學習相關的原因,為什么在這種情況下沒有學習到正確的標簽。 不過要懷疑,否則 Karpathy 得到正確的結果是沒有意義的。

任何評論或幫助弄清楚它都非常感謝。

我相信我發現了問題:

(A) 您的數據集沒有線性切割。

(B) Karpathy 的“Monte Carlo”梯度下降在這樣的數據集上顛簸。

(C) 你和 Karpathy 使用了不同的數據。

DATA SETS
label   Karpathy's      yours
  1     [1.2, 0.7]      [1.2, 0.7]
 -1     [-0.3, -0.5]    [-0.3, 0.5]
  1     [3.0, 0.1]      [-3, -1]
 -1     [-0.1, -1.0]    [0.1, 1.0]
 -1     [-1.0, 1.1]     [3.0, 1.1]
  1     [2.1, -3]       [2.1, -3]

您提供的數據集幾乎在 y = 1/3x + 1/2 處有一條剖切線(超平面),但最靠近該線的三個點一直在爭論除法問題。 事實證明,最好的分隔符明顯不同,將 [1.2, 0.7] 嚴重地留在了錯誤的一邊,但對此非常不滿意。

原始數據在大約 y = -3x + 1 處有一條整齊的切割線,該算法大致近似為(四舍五入)0.6x - 0.1y - 0.5

同樣,該算法正在尋找最小成本的擬合,而不是最寬分離通道的“純”SVM。 即使整齊的切口線,該算法確實n要在其上收斂; 相反,它侵入了可接受解決方案的一般附近。

它選擇一個隨機點。 如果該點是可靠分類的——分數是正確的,幅度 > 1——沒有任何反應。 但是,如果該點位於線的錯誤一側,或者甚至太靠近以至於不舒服,那么它會拉動參數以獲得更有利的治療。

除非通道寬度為 2 個單位,否則爭議領土內的點將繼續輪流來回推擠。 沒有收斂標准……事實上,在某一點之后沒有收斂保證。

仔細查看 Karpathy 的代碼:主要算法對分數 < 1 或 > -1 的數據點進行更改(取決於訓練類別)。 然而,如果結果的符號是正確的,則評估算法聲稱勝利。 這是合理的,但與訓練功能並不完全一致。 在我的試驗中,第一點的得分總是小於 0.07,但實際值在 0 的任一側搖擺不定。其他點完全沒有 0,但只有兩個點通過 1。有四點爭論線應該在哪里。


這對你來說清楚了嗎?

暫無
暫無

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

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