2017-12-02 102 views
6

ja jechałem za pośrednictwem kodu za utratę SVM i pochodnej, zrobiłem zrozumieć stratę, ale nie mogę zrozumieć, jak gradient jest obliczana w vectorized sposóbVectorized SVM gradientu

def svm_loss_vectorized(W, X, y, reg): 

loss = 0.0 
dW = np.zeros(W.shape) # initialize the gradient as zero 
num_train = X.shape[0] 

scores = X.dot(W) 
yi_scores = scores[np.arange(scores.shape[0]),y] 
margins = np.maximum(0, scores - np.matrix(yi_scores).T + 1) 
margins[np.arange(num_train),y] = 0 
loss = np.mean(np.sum(margins, axis=1)) 
loss += 0.5 * reg * np.sum(W * W) 

pojętego się tu, Po tutaj nie mogę zrozumieć, dlaczego jesteśmy podsumowując row-wise w macierzy binarnej i odjęcie od jej sumy

binary = margins 
binary[margins > 0] = 1 
row_sum = np.sum(binary, axis=1) 
binary[np.arange(num_train), y] = -row_sum.T 
dW = np.dot(X.T, binary) 

# Average 
dW /= num_train 

# Regularize 
dW += reg*W 

return loss, dW 

Odpowiedz

1

Pozwól nam zakręcić scenariusz i pierwsza funkcja straty, więc jesteśmy na tej samej stronie:

Podane są P - punkty w przestrzeni N - wymiarowa przestrzeń w postaci macierzy PxNX, więc punkty są rzędami tej macierzy. Każdy punkt w X jest przypisany do jednej z kategorii M. Są one podane jako wektory Y o długości P, które mają liczby całkowite od 0 do M-1.

Celem jest, aby przewidzieć klas wszystkich punktów przez M klasyfikatorów liniowych (po jednym dla każdej kategorii) podanych w postaci macierzy wagowej W kształtu NxM, więc klasyfikatorów są kolumny W. Aby przewidzieć kategorie wszystkich próbek X, tworzone są produkty skalarne między wszystkimi punktami i wszystkimi wektorami wagowymi. Jest to to samo, co macierz zwielokrotniająca X i W, dając macierz wyników Y0, która jest ustawiona tak, że jej rzędy są uporządkowane jak te elementy Y, każdy rząd odpowiada jednej próbce. Przewidywana kategoria dla każdej próbki to po prostu ta z największą liczbą punktów.

Nie ma określeń stronniczości, więc zakładam, że istnieje pewien rodzaj symetrii lub zerowego średniego założenia.

Teraz, aby znaleźć dobry zestaw wag, chcemy funkcji straty, która jest mała dla dobrych przewidywań i dużych dla złych przewidywań i która pozwala nam na gradientowe zejście. Jednym z najprostszych sposobów jest po prostu ukaranie za każdą próbkę, która jest większa niż punktacja właściwej kategorii dla tej próbki i pozwolić, by kara rosła liniowo wraz z różnicą. Więc jeśli piszemy A[i] do zbioru kategorii j że strzeli więcej niż poprawnej kategorii Y0[i, j] > Y0[i, Y[i]] strata dla próbki i można zapisać jako

sum_{j in A[i]} (Y0[i, j] - Y0[i, Y[i]])

lub równoważnie, jeśli piszemy #A[i] do liczby elementów w A[i]

(sum_{j in A[i]} Y0[i, j]) - #A[i] Y0[i, Y[i]]

cząstkowe pochodne, w odniesieniu do punktacji to po prostu w ten sposób

    | -#A[i]  if j == Y[i] 
dloss/dY0[i, j] = {  1  if j in A[i] 
        |  0  else 

co jest dokładnie tym, o czym mówisz w pierwszych czterech linijkach, których nie rozumiesz.

Następna linia stosuje regułę łańcucha dloss/dW = dloss/dY0 dY0/dW.

Pozostaje podzielić przez liczbę próbek, aby uzyskać utratę jednej próbki i dodać pochodną terminu regulowania, której regulacja jest tylko funkcją kwadratową składową prostą.

+0

Rozumiem logikę, zrozumiałem, że z niezeralizowanego kodu, Czy możesz wyjaśnić, w jaki sposób jest używana macierz 1,0 (margines> 0), W niewizualizowanym faktycznie używamy wartości w [i] [ j] ie (nie zaokrąglając do 1 lub 0), tutaj 'margin = score [j] - correct_class_score + 1', ale w wektorze zaokrąglamy do 1 lub 0, nie 'binarnie [marginesy> 0 ] = (rzeczywiste wartości, które są> 0, nie 1, inaczej 0) "mają więcej sensu? –

+0

Nie mając niezeroryzowanego kodu, mogę tylko komentować wektoryzację. Jak próbowałem wyjaśnić w odpowiedzi, _ dla pochodnej_ z użyciem 1 i 0, a nie rzeczywiste wartości, jest matematamicznie poprawna rzecz do zrobienia. Ponieważ 'dY0 [i, j]/dY0 [k, l]' wynosi 1, jeśli 'i = k, j = l', 0 else. –

+0

Możesz zajrzeć tutaj: https://github.com/huyouare/CS231n/blob/master/assignment1/cs231n/classifiers/linear_svm.py –