svm-loss 關於權重矩陣W的導數(cs231n Assignment 1)

svm-loss 關於權重矩陣W的導數(cs231n Assignment 1)

先給出相應習題的代碼,各位可以自行領會一下:

def svm_loss_vectorized(W, X, y, reg):
  """
  Structured SVM loss function, vectorized implementation.

  Inputs and outputs are the same as svm_loss_naive.
  """
  loss = 0.0
  dW = np.zeros(W.shape) # initialize the gradient as zero
  scores = X.dot(W)
  num_train = X.shape[0]
  num_type = W.shape[1]
  print(num_type)
  #############################################################################
  # TODO:                                                                     #
  # Implement a vectorized version of the structured SVM loss, storing the    #
  # result in loss.                                                           #
  #############################################################################
  correct_scores = scores[range(num_train), y].reshape(-1, 1)
  pre_loss = scores + 1 - correct_scores
  loss = (np.sum(np.maximum(pre_loss, 0)) - num_train) / num_train + reg * np.sum(W * W)
  #############################################################################
  #                             END OF YOUR CODE                              #
  #############################################################################

  #############################################################################
  # TODO:                                                                     #
  # Implement a vectorized version of the gradient for the structured SVM     #
  # loss, storing the result in dW.                                           #
  #                                                                           #
  # Hint: Instead of computing the gradient from scratch, it may be easier    #
  # to reuse some of the intermediate values that you used to compute the     #
  # loss.                                                                     #
  #############################################################################
  mask = np.ones(scores.shape)
  cnt = pre_loss > 0
  mask[range(num_train), y] = 1 - np.sum(cnt, axis = 1)
  dW = X.T.dot(mask * (pre_loss > 0)) / num_train + 2 * reg * W
  #############################################################################
  #                             END OF YOUR CODE                              #
  #############################################################################

  return loss, dW

本題是cs231n Assignment 1中關於svm-loss向量化方法的一個思路,並不是嚴格的數學證明

首先給出SVM-loss的表達式
設輸入矩陣爲XXRN×D ,y 爲樣本標籤集yRN×1 ,權重矩陣爲WWRD×C ,
其中N 爲訓練樣本的個數,D 爲樣本的維數, C 爲標籤的種類數 ,
S 爲SVM的輸出矩陣 S=XWRN×C

L=1Ni=1Nj=1,jyiCmax(Si,jSi,yi+1,0)

關於svm-loss函數此處不再贅述,詳細請參加CS231n的課程內容

在CS231n 的Assignment 1中要求向量化svm-loss函數對於權重矩陣W的導數, 即dLdW

這裏我們將L 的表達式稍做變形, 由於對任意給定的i 有且只有一個j , 使得j=yi (因爲yi 唯一)
且對於該j=yimax(Si,jSi,yi+1,0) 恆等於1,從而,L 可以變形爲:

L=1Ni=1N[j=1C(max(Si,jSi,yi+1,0))1]=1Ni=1Nj=1C(max(Si,jSi,yi+1,0))1

max函數不方便處理,所以我們考慮消去max,由於max(Si,jSi,yi+1,0)Si,jSi,yi+1<0 時爲0故,L 可以簡化爲
L=1Ni=1Nj=1C(max(Si,jSi,yi+1,0))1=1Ni=1Nj=1C(Si,jSi,yi+1)1,ij滿Si,jSi,yi+1>0

展開Si,jSi,yi 得到
L=1Ni=1Nj=1C(k=1DXi,kWk,jk=1DXi,kWk,yi+1)1,ij滿Si,jSi,yi+1>0

下面我們就可以比較方便的求導了,考慮LWk,j 的導數(爲了便於此處的 j 與上式中 j 混淆,我們將上式中的 j 換成字母 l 進行求導)
dLdWk,j=1Ni=1N(Xi,kXi,kl=1CdWk,yidWk,j)=1Ni=1N(Xi,k(1l=1CdWk,yidWk,j)),i滿Si,jSi,yi+1>0il滿Si,lSi,yi+1>0

對於k,j 取定的情況,上式可以寫作兩個向量相乘,同時對條件進行相應的等價變換
dLdWk,j=[X1,kX2,k...XN,k]1Cl=1dWk,y1dWk,j1Cl=1dWk,y2dWk,j...1Cl=1dWk,yNdWk,j
ii滿Si,jSi,yi+1>00il滿Si,lSi,yi+1>0,

可以觀察到等式右邊的行向量實際上是 XT 的第1行。同時,聯繫到梯度矩陣的緯度,
dLdWRD×C=RD×NRN×C ,我們猜測dLdWXT 乘上式等式右邊列向量的一個拓展得到。然而,上述列向量實際上有兩個參數kj ,取遍所有的k,j 我們將得到一個三維矩陣,這顯然不是我們想要的RN×C 的矩陣。實際上我們會發現,上述列向量的值實際上只與j 有關而與k無關,dWk,yidWk,j={1,j=yi0,jyi ,拓展該向量,我們只需要取不同的j 即可(注意,條件要同時進行拓展),
於是我們得到了一個RN×C 的矩陣,記爲mask ,mask=1Cl=1dWk,y1dWk,11Cl=1dWk,y2dWk,1...1Cl=1dWk,yNdWk,11Cl=1dWk,y1dWk,21Cl=1dWk,y2dWk,2...1Cl=1dWk,yNdWk,2.........1Cl=1dWk,y1dWk,C1Cl=1dWk,y2dWk,C...1Cl=1dWk,yNdWk,C
ij滿Si,jSi,yi+1>00,il滿Si,lSi,yi+1>0,

事實上
dLdW=XTL

剩下的問題就是如何計算mask

觀察到L矩陣的每一項都有1,我們初始化mask矩陣爲np.ones([D, C])
接下來就是矩陣中每個entry中導數部分的計算了
首先,我們可以利用broadcast計算出矩陣Si,jSi,yi+10<=i<N,0<=j<=C(0) 在我的代碼爲pre_lost ,該矩陣實際上在計算lost時也用到了。

  correct_scores = scores[range(num_train), y].reshape(-1, 1)
  pre_loss = scores + 1 - correct_scores

pre_lost > 0就可以作爲bool矩陣表示條件 ij滿Si,jSi,yi+1>0
下面計算每一行的l值,實際上每一行的l的意義就是每一行中pre_lost>0矩陣中爲True的元素個數,利用np.sum函數對pre_lost>0的每行進行加和就可得到。
mask矩陣與dW計算代碼爲:(別忘了L2 Regularization部分的導數)

  mask = np.ones(scores.shape)
  cnt = pre_loss > 0
  mask[range(num_train), y] = 1 - np.sum(cnt, axis = 1)
  dW = X.T.dot(mask * (pre_loss > 0)) / num_train + 2 * reg * W

大晚上敲完這篇筆記或許漏洞百出,請各位讀者見諒,改日再仔細檢查一下,如有錯誤懇請指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章