1. 程式人生 > >3種softmax函式python實現方式(顯式迴圈,向量,矩陣)

3種softmax函式python實現方式(顯式迴圈,向量,矩陣)

Python三種方式實現Softmax損失函式計算

python實現的softmax損失函式程式碼,我們先回顧一下softmax損失函式的定義:

其中右邊一項為第y=j項的概率值。令J(w) = log(J(w)):

損失函式的梯度:

 

import numpy as np
"""
    第一種計算softmax_loss, 在計算每一分類的概率時,用到了矩陣運算。
"""
class Softmax:

    def __init__(self):
        pass

    @staticmethod
    def softmax_loss_naive(w, x, y, reg):
        """
        使用顯示迴圈版本計算softmax損失函式
        N:資料個數, D:資料維度, C:資料類別個數
        inputs:
        :param w: shape:[D, C], 分類器權重引數
        :param x: shape:[N, D] 訓練資料
        :param y: shape:[N, ]資料標記
        :param reg: 懲罰項係數
        :return:二元組:loss:資料損失值, dw:權重w對應的梯度,其形狀和w相同
        """
        loss = 0.0
        dw = np.zeros_like(w)
        #############################################################################
        #  任務:使用顯式迴圈實現softmax損失值loss及相應的梯度dW 。                    #
        #  溫馨提示: 如果不慎,將很容易造成數值上溢。別忘了正則化喲。                   #
        #############################################################################
        y = np.asarray(y, dtype=np.int)
        num_train, dim = x.shape
        num_class = w.shape[1]
        score = x.dot(w)
        score_max = np.max(score, axis=1).reshape(num_train, 1)
        # 計算對數概率, prob.shape = N*D, 每一行與一個樣本對應, 每一行的概率和為1
        z = np.sum(np.exp(score - score_max), axis=1, keepdims=True)
        z1 = np.sum(np.exp(score - score_max), axis=1)
        e_j =  np.exp(score - score_max)
        prob = e_j / z
        for i in range(num_train):
            loss += -np.log(prob[i, y[i, 0]]) # loss = 1 - prob[i, y[i, 0]], loss = log(loss), so loss = -np.log(prob[i, y[i]])
            for j in range(num_class):
                if j == y[i]:
                    dw[:, j] += -(1-prob[i, j]) * x[i]
                else:
                    dw[:, j] += prob[i, j] * x[i]
        loss = loss / num_train + 0.5 * reg * np.sum(w*w)
        dw = dw / num_train + reg * w
        return loss, dw

    """
        第二種計算softmax_loss, 純向量計算
    """
    @staticmethod
    def softmax_loss_naive_vec(w, x, y, reg):
        """
           N:資料個數, D:資料維度, C:資料類別個數
           inputs:
           :param w: shape:[D, C], 分類器權重引數
           :param x: shape:[N, D] 訓練資料
           :param y: shape:[N, ]資料標記
           :param reg: 懲罰項係數
           :return:二元組:loss:資料損失值, dw:權重w對應的梯度,其形狀和w相同
           """
        loss = 0.0
        dw = np.zeros_like(w)
        #############################################################################
        #  任務:使用顯式迴圈實現softmax損失值loss及相應的梯度dW 。                    #
        #  溫馨提示: 如果不慎,將很容易造成數值上溢。別忘了正則化喲。                   #
        #############################################################################
        num_train = x.shape[0]
        num_class = w.shape[1]
        y = np.asarray(y, dtype=np.int)
        for i in range(num_train):
            s = x[i].dot(w)
            score = s - np.max(s)
            score_E = np.exp(score)
            Z = np.sum(score_E)
            score_target = score_E[y[i]]
            loss += -np.log(score_target / Z)
            for j in range(num_class):
                if j == y[i]:
                    dw[:, j] += -x[i] * (1 - score_E[j] / Z)
                else:
                    dw[:, j] += x[i] * (score_E[j] / Z)

        loss = loss / num_train + 0.5*reg*np.sum(w*w)
        dw = dw / num_train + reg*w
        return loss, dw

    """
        純矩陣計算
    """
    @staticmethod
    def softmax_loss_matrix(w, x, y, reg):
        """
               使用純矩陣運算
               N:資料個數, D:資料維度, C:資料類別個數
               inputs:
               :param w: shape:[D, C], 分類器權重引數
               :param x: shape:[N, D] 訓練資料
               :param y: shape:[N, ]資料標記
               :param reg: 懲罰項係數
               :return:二元組:loss:資料損失值, dw:權重w對應的梯度,其形狀和w相同
               """
        loss = 0.0
        dw = np.zeros_like(w)
        #############################################################################
        #  任務:使用顯式迴圈實現softmax損失值loss及相應的梯度dW 。                    #
        #  溫馨提示: 如果不慎,將很容易造成數值上溢。別忘了正則化喲。                   #
        #############################################################################
        num_train = x.shape[0]
        y = np.asarray(y, dtype=np.int)
        s = x.dot(w)
        score = s - np.max(s, axis=1, keepdims=True)
        score_E = np.exp(score)
        Z = np.sum(score_E, axis=1, keepdims=True)
        prob = score_E / Z
        y_true_class = np.zeros_like(prob)
        y_true_class[range(num_train), y.reshape(num_train)] = 1.0
        loss += -np.sum(y_true_class * np.log(prob)) / num_train + 0.5*reg*np.sum(w*w)
        dw += -np.dot(x.T,y_true_class - prob) / num_train + reg * w
        return loss, dw