可以參考:cs231n assignment1 SVM 完整代碼
231n作業 多類 SVM 的損失函數及其梯度計算(最好)https://blog.csdn.net/NODIECANFLY/article/details/82927119 (也不錯)
作業部分:
完成結構化SVM的損失梯度的理論計算
完成梯度計算的循環形式的代碼 svm_loss_naive
完成向量化梯度計算的代碼 svm_loss_vectorized
完成隨機梯度下降法的代碼,在linear_classifier.py文件的 SGDLinearClassifier.train()函數中
其中對多分類SVM損失函數的推導先不贅述,最后得到一個對N個樣本計算梯度並返回梯度與損失的矩陣,梯度部分如下:
def svm_loss_naive(W, X, y, reg): """ Structured SVM loss function, naive implementation (with loops). Inputs have dimension D, there are C classes, and we operate on minibatches of N examples. Inputs: - W: A numpy array of shape (D, C) containing weights. - X: A numpy array of shape (N, D) containing a minibatch of data. - y: A numpy array of shape (N,) containing training labels; y[i] = c means that X[i] has label c, where 0 <= c < C. - reg: (float) regularization strength Returns a tuple of: - loss as single float - gradient with respect to weights W; an array of same shape as W """ dW = np.zeros(W.shape) # initialize the gradient as zero # compute the loss and the gradient num_classes = W.shape[1] num_train = X.shape[0] loss = 0.0 for i in range(num_train): scores = X[i].dot(W) correct_class_score = scores[y[i]] for j in range(num_classes): if j == y[i]: continue margin = scores[j] - correct_class_score + 1 # note delta = 1 if margin > 0: loss += margin dW[:,j]+=X[i] #數據分類錯誤時的梯度 dW[:,y[i]]-=X[i] #數據分類正確時的梯度,所有非正確的累減 # Right now the loss is a sum over all training examples, but we want it # to be an average instead so we divide by num_train. loss /= num_train dW /=num_train # 加上正則項的部分:reg? loss += reg * np.sum(W * W) dW+=reg*np.sum(W) #reg是正則化強度的量 ############################################################################# # TODO: # # Compute the gradient of the loss function and store it dW. # # Rather that first computing the loss and then computing the derivative, # # it may be simpler to compute the derivative at the same time that the # # loss is being computed. As a result you may need to modify some of the # # code above to compute the gradient. # ############################################################################# return loss, dW
寫完損失后:進行幾個步驟
圖像預處理
通常我們會將所有圖片,包括訓練數據和待分類數據,減去圖片每個位置像素的均值,使得數據中心化,這樣可以提高模型的效果。同時,也可以對中心化后的數據歸一化處理,使其分布在[-1, 1]區間,進一步優化模型效果。
小批量數據梯度下降(Mini-batch gradient descent)
相比於每次拿一個樣例數據進行梯度更新,每次使用一個小批量數據進行梯度更新能夠更好的避免單個樣本數據的擾動,可以顯著提高模型訓練的效率,損失的變化更加平滑,使得模型更快的收斂。具體操作方法是一次計算一個批量的數據的結果,如256個樣本,計算每個結果下權重矩陣每個變量的梯度。對於每個權重分量,累加256個梯度值,求均值作為該分量的梯度,更新該分量。
梯度下降和梯度檢驗
對求得的理論梯度與數值梯度進行對比,確認沒有問題后進行計算:
理論梯度:
數值梯度:
梯度數值解的計算很簡單,根據下面梯度的公式,在給定的樣本和權重矩陣下,計算輸出,然后讓權重矩陣的變量發生微小的變化,再計算輸出,兩次輸出的差值除以變化量就是權重矩陣的梯度:
向量化的計算:
def svm_loss_vectorized(W, X, y, reg): """ Structured SVM loss function, vectorized implementation. #計算向量化計算損失和梯度 Inputs:輸入都為numpy array - W: 形狀為(D, C)的權重矩陣,3073x10 - X: 形狀為(N, D)的小批量數據,200x3073 - y: 形狀為(N,)的標簽向量,200,由以上關系可得XW為所有樣本的得分,第i行為樣本i的得分,XW的第ij個元素 即為樣本i在第j個分類的得分; y[i] = c means that X[i] has label c, where 0 <= c < C. - reg: (float) 正則化損失系數(無法通過拍腦袋設定,需要多試幾個值,交叉驗證,然后找個最優的) 變量說明: delta:超參數,SVM的間隔,一般取1 """ num_train=X.shape[0] #X形狀的第0個參數,由說明可知是N為小批量樣本數200 num_classes=X.shape[1] loss = 0.0 dW = np.zeros(W.shape) # 零初始化的梯度矩陣DxC delta=1 """ patch_X=X # 200X3073 patch_y=y # 200 """ ############################################################################# # TODO: 計算loss # # Implement a vectorized version of the structured SVM loss, storing the # # result in loss. # ############################################################################# scores=X.dot(W) #所有樣本的得分情況200x10(NxC) scores_y=scores[range(num_train),y] # 其中num_train和y的size都是N,每一個樣本正確分類的得分(1xN)向量 scores_y=np.reshape(scores_y,(num_train,1)) #得到Nx1的矩陣,便於下面廣播 margins =np.maximum(0,scores-scores_y+delta) #Nxc矩陣,第i行的C個元素為樣本i對於第j類的hinge loss margins[range(num_train),y]=0 #將label所在誤差置0 loss+=np.sum(margins)/num_train #計算損失data loss 部分 print(loss) loss+= 0.5*reg * np.sum(W * W) #加上正則項 0.5為了平衡W平方求導后的2 ############################################################################# # END OF YOUR CODE # ############################################################################# ############################################################################# # TODO: 計算梯度dW # # 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. # ############################################################################# margins[margins>0]=1.0 #取大於0的為1,便於計算梯度 row_sum=-np.sum(margins,1) #對每一行不為0的margins求和,用來計算正確分類項的梯度,即該列為減去所有非正確項的特征累加 margins[range(num_train),y] =row_sum #N X C直接更改 margins正確部分的值 dW+=np.dot(X.T,margins)/num_train #x為NxD dW+=reg*W ############################################################################# # END OF YOUR CODE # ############################################################################# return loss, dW
驗證沒有問題之后可以進行訓練。