[英]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.