CS231N assignment3 SoftMax

CS231N Assignment3 SoftMaxpython

 

Beginapp


本文主要介紹CS231N系列課程的第三項做業,寫一個SoftMax損失的線形訓練模型。dom

課程主頁:網易雲課堂CS231N系列課程機器學習

語言:Python3.6函數

系統:Windows10學習

 

1 SoftMax分類器測試


 

        簡單介紹SoftMax,它和SVM都是比較經常使用的線形分類器,SoftMax最終獲得的損失是spa

反應每一個分類的機率大小。以下所示:blog

        最左邊藍色框爲每一個分類的分數,咱們取exp能夠獲得紅色框,再歸一化獲得最右邊綠色it

的框,標準化的值就反應它的機率狀況,咱們再取它的-log獲得咱們要的損失值。

       softmax到底什麼含義呢?我查了一下,通常直接max取值使直接取最大值,softmax將

其轉變爲機率問題,這樣就會考察機率狀況,更加合理~~~emmm機器學習知識還不太好,等

我再看看書多補充點解釋。

 

 2 softmax梯度

 


 

前文解釋了前向傳播,計算損失,訓練一個模型,還須要找到梯度,如何計算梯度呢?

下圖是我寫的一個計算,emmm懶得敲公式

 

 而後在網易雲課堂上,寫了說要考慮一個穩定性問題~~~讓每個分數值都減去最大值,

那麼每一個分數都變爲了複數,也就到了左半軸,這樣指數函數變化率就會減少。emmm

大概使考慮這樣就穩定了

 

 

 3 代碼部分


 

 

因爲都是線形分類器,因此代碼的訓練、預測部分都是同樣的,不一樣的在於損失函數

的求解以及梯度的計算。以下爲損失函數的計算部分

 

    def loss(self,W,X,Y,reg):
        loss = 0.0
        num_train = X.shape[0]
        dW = np.zeros(W.shape)
        #計算分數
        scores = X.dot(W)
        scores = scores - np.max(scores,axis=1,keepdims=True)
        #取score的exp
        exp_scores = np.exp(scores)
        #求行和,獲得Pk的底
        sum_row = np.sum(exp_scores,axis = 1,keepdims=True)
        #相除獲得Pk
        P = exp_scores / sum_row
        #計算Loss
        loss = -1.0 / num_train * np.log(P[np.arange(num_train),Y]).sum()
        loss += 0.5 * reg * np.sum(W*W)

        #計算Dw梯度
        grad = np.zeros_like(P)#生成一個和P同樣的0矩陣
        grad[np.arange(num_train),Y] = 1#對矩陣中Y所對應的部分加一個1,由於一會要剪
        dW = X.T.dot(P - grad) #上文剛說要減,如今就減去,只有Y對應的地方有變化
        dW = dW / num_train#加正則
        dW += 0.5 * reg * np.sum(W*W)
        return loss,dW

 

  

測試:損失爲2.5589,梯度以下

 

 其餘代碼以下

 

class Softmax():
    def __init__(self):
        self.W = None
        pass
    def loss(self,W,X,Y,reg):
        loss = 0.0
        num_train = X.shape[0]
        dW = np.zeros(W.shape)
        #計算分數
        scores = X.dot(W)
        scores = scores - np.max(scores,axis=1,keepdims=True)
        #取score的exp
        exp_scores = np.exp(scores)
        #求行和,獲得Pk的底
        sum_row = np.sum(exp_scores,axis = 1,keepdims=True)
        #相除獲得Pk
        P = exp_scores / sum_row
        #計算Loss
        loss = -1.0 / num_train * np.log(P[np.arange(num_train),Y]).sum()
        loss += 0.5 * reg * np.sum(W*W)

        #計算Dw梯度
        grad = np.zeros_like(P)#生成一個和P同樣的0矩陣
        grad[np.arange(num_train),Y] = 1#對矩陣中Y所對應的部分加一個1,由於一會要剪
        dW = X.T.dot(P - grad) #上文剛說要減,如今就減去,只有Y對應的地方有變化
        dW = dW / num_train#加正則
        dW += 0.5 * reg * np.sum(W*W)
        return loss,dW


    def train(self,X,Y,learning_rate=1e-3,reg=1e-5,num_iters=100,batch_size=200,verbose=False):
        '''
        隨機梯度降低法訓練分類器
        輸入參數:
        -learning_rate學習率
        -reg正則化強度
        -num_iters步長值
        -batch_size每一步使用的樣本數量
        -verbose若爲真則打印過程
        輸出參數:
        list損失值
        '''
        num_train,dim = X.shape
        num_classes = np.max(Y) + 1
        
        #if self.W is None:
            #初始化W矩陣
        self.W = 0.001 * np.random.randn(dim,num_classes)
        loss_history = []
        #開始訓練num_iters步
        for it in range(num_iters):
            X_batch = None
            Y_batch = None
            ########################
            # 選取部分訓練樣本
            # 隨機生成一個序列
            batch_inx = np.random.choice(num_train,batch_size)
            X_batch = X[batch_inx,:]
            Y_batch = Y[batch_inx]
            #########################
            # 計算損失與梯度
            loss,grade = self.loss(self.W,X_batch,Y_batch,reg)
            loss_history.append(loss)

            ########################
            # 參數更新
            # 梯度爲正表示損失增大,應該減小,成負相關
            self.W = self.W - learning_rate * grade
            #打印結果
            if verbose and it % 100 == 0:
                print('iteration %d / %d : loss %f'%(it ,num_iters,loss))
        return loss_history


    def predict(self,X_train):
        y_predict = np.zeros(X_train.shape[1])
        #根據訓練後的W矩陣計算分數
        scores = X_train.dot(self.W)
        #找到得分中最大的值做爲類別
        y_predict = np.argmax(scores,axis = 1)#計算每一行最大值
        return y_predict

  

接下來咱們作一步測試,訓練咱們用到的數據。

##############################################################
# step4 調參
# 兩個參數,學習率;正則化強度
learning_rate = [1e-7,2e-7,5e-7]
regularization_strengths = [3e4,3.25e4,3.5e4]

results = {}
best_val = 0
best_svm = None
######################################
# 循環執行代碼
# 對不一樣的學習率以及正則化強度進行測試
#
for rate in learning_rate:
    for regular in regularization_strengths:
        Softmax2 = Softmax()
        #訓練
        Softmax2.train(X_train,Y_train,learning_rate=rate,reg=regular,num_iters=1000)
        #預測
        Y1 = Softmax2.predict(X_train)
        Y2 = Softmax2.predict(X_val)
        accuracy_train = np.mean(Y1==Y_train)
        accuracy_val = np.mean(Y2==Y_val)
        #判斷優略
        if best_val < accuracy_val:
            best_val = accuracy_val
            best_svm = Softmax2#保存當前模型
        #存儲數據
        results[rate,regular] = (accuracy_train,accuracy_val)
#打印數據
for lr,reg in sorted(results):
    accuracy_train,accuracy_val = results[(lr,reg)]
    print('lr:%e reg %e train accuracy: %f val val accuracy : %f'%(lr,reg,accuracy_train,accuracy_val))

  

 

結果以下,emmm有點低,等我之後調調,先學會寫輪子把

相關文章
相關標籤/搜索