Я пытаюсь решить первое задание Стэнфорда CS231n. В частности, у меня возникают трудности при кодировании векторизованной версии SVM-градиента в svm_loss_vectorized
. В скалярной функции мы использовали вложенный l oop для вычисления градиента:
for i in xrange(num_train):
scores = X[i].dot(W)
correct_class_score = scores[y[i]]
for j in xrange(num_classes):
if j == y[i]:
continue # run over all the all the classes except the right one
margin = scores[j] - correct_class_score + 1 # note delta = 1
if margin > 0:
dW[:,j] += X[i]
dW[:,y[i]] -= X[i]
loss += margin
Словом, для каждого наблюдения i
мы вычисляем для каждой категории, которая не является правильной j != y[i]
наценка. Если оно больше 0, мы добавляем i
-ю строку X к dW j
-ому столбцу . В конечном итоге, dW[:,j]
- это сумма всех X[i]
с, из которых модель предсказала j
метку неправильно, вместо истинной метки y[i]
(верно?). Более того, для каждого i
, в котором модель предсказывает более высокую вероятность неправильной метки, мы подставляем X[i]
из dW[:,y[i]]
, то есть столбца, которому на самом деле принадлежит наблюдение i
.
Теперь я закончил кодировать скалярную версию и пытаюсь получить те же числа в векторизованной форме.
SCORES = X.dot(W)
CORRECT_cs = SCORES[np.arange(SCORES.shape[0]),y]
MARGINs = (SCORES.T - CORRECT_cs.T + np.ones(CORRECT_cs.T.shape)).T # note delta = 1
MARGINs = MARGINs * (MARGINs != 1) * (MARGINs > 0)
Когда j==y[i]
, у нас есть MARGINs[i,j] = 1
. Более того, нам нужны только положительные значения (аналогично утверждению if). Потеря - это сумма этой матрицы, деленная на общее количество наблюдений. Пока здесь все одинаково, но сейчас начинается сложная часть. Я хочу вычислить для каждого j
сумму X[i]
s, как в скалярной версии. Я думаю, что мне удалось сделать это:
for j in xrange(10):
sumXi = X[(MARGINs>0)[:,j] * (np.repeat(j,500)!=y),:].sum(axis = 0)
dW_vec[:,j] = sumXi
Но теперь я хочу вычислить часть dW[:,y[i]] -= X[i]
. Я думал об этих строках:
for j in xrange(10):
sumXi = X[(MARGINs>0)[:,j] * (np.repeat(j,500)!=y),:].sum(axis = 0)
dW_vec[:,j] = sumXi
sumYj = X[(MARGINs>0)[:,j] * (np.repeat(j,500)==y),:].sum(axis = 0)
dW_vec[:,j] -= sumYj
Но, к сожалению, значения градиента не совпадают. Что мне не хватает? Неправильные ли условия на X
? Есть ли более удобный способ расчета градиента?
Спасибо!