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. ]