3種softmax函式python實現方式(顯式迴圈,向量,矩陣)
阿新 • • 發佈:2018-11-26
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