Softmax Python實作
一 、不使用one-hot編碼
import numpy as np
def data_loss_softmax(scores, labels):
num_examples = scores.shape[0]
exp_scores = np.exp(scores)
exp_scores_sum = np.sum(exp_scores, axis=1)
correct_probs = exp_scores[range(num_examples), labels] / exp_scores_sum
correct_probs = -np.log(correct_probs)
data_loss = np.sum(correct_probs) / num_examples
return data_loss
data=np.array([[0.6,0.2,0.01],[0,0,1],[0.02,0.9,0.3]])
print(data)
labels=np.array([0,2,1])
print(data_loss_softmax(data,labels))
1 【data】 3*3 每行一個樣本,列代表神經網絡最後一層的分類值大小,次元為3
[[0.6 0.2 0.01]
[0. 0. 1. ]
[0.02 0.9 0.3 ]]
2【label】 代表真實的類别 0 1 2代表分類号,這裡不使用one-hot編碼
[0,2,1]
3 num_examples = scores.shape[0]
exp_scores = np.exp(scores)
對矩陣exp_scores 每一個取指數 exp()
[[1.8221188 1.22140276 1.01005017]
[1. 1. 2.71828183]
[1.02020134 2.45960311 1.34985881]]
4 exp_scores_sum = np.sum(exp_scores, axis=1)
對每一行計算和,注意axis=1 代表在第二個軸上計算和這樣第二軸的次元計算完畢後就會變為1
[4.05357173 4.71828183 4.82966326]
5 correct_probs = exp_scores[range(num_examples), labels] / exp_scores_sum
注意此處取出了每個樣本(每行)對應的真實類别号位置的值,這也是為何沒有使用one-hot編碼
的原因
注意 exp_scores[range(num_examples), labels]和 exp_scores[:, labels]的差別 exp_scores[range(num_examples), labels]計算獲得是3*1的次元,而 exp_scores[:, labels]獲得的還是3*3 的次元,使用exp_scores[range(num_examples), labels]可以獲得每一行特定列位置的數值
[0.44950945 0.57611688 0.5092701 ]
6計算softmax值
由于此處correct_probs取出的輸出是對應真實類别位置的值,值越大 計算-np.log(correct_probs)結果越小,代表輸出的類别正确
correct_probs = -np.log(correct_probs)
[0.7995984 0.55144471 0.67477675]
7 計算平均損失
data_loss = np.sum(correct_probs) / num_examples
0.67
二、使用onehot編碼
def data_loss_softmax_onehot(scores, labels):
num_examples = scores.shape[0]
exp_scores = np.exp(scores)
#print(exp_scores)
exp_scores_sum = np.sum(exp_scores, axis=1)
#print(exp_scores_sum)
correct_probs = exp_scores[:] / exp_scores_sum
#print(correct_probs)
correct_probs2 = -labels*np.log(correct_probs)
#print(correct_probs2)
data_loss = np.sum(correct_probs2) / num_examples
return data_loss
data=np.array([[0.6,0.2,0.01],[0,0,1],[0.02,0.9,0.3]])
# print(data)
labels=np.array([[1,0,0],[0,0,1],[0,1,0]])
print(data_loss_softmax_onehot(data, labels))
輸出
--exp_scores
[[1.8221188 1.22140276 1.01005017]
[1. 1. 2.71828183]
[1.02020134 2.45960311 1.34985881]]
--exp_scores_sum
[4.05357173 4.71828183 4.82966326]
--correct_probs
[[0.44950945 0.258866 0.2091347 ]
[0.24669602 0.21194156 0.56283051]
[0.25167961 0.52129211 0.27949336]]
--correct_probs2
[[ 0.7995984 -0. -0. ]
[-0. -0. 0.57477675]
[-0. 0.65144471 -0. ]]
--最後整個矩陣求和取平均
0.6752732868378
代碼不同的地方是
correct_probs = exp_scores[:] / exp_scores_sum
correct_probs = -labels*np.log(correct_probs)
此處使用的是數組*數組
[1,0,0]*[0.44950945 0.258866 0.2091347 ]=[0.7995984 -0. -0. ]