softmax求导
[先看这个,别的网页有误导]简单易懂的softmax交叉熵损失函数求导
https://www.jianshu.com/p/c02a1fbffad6
[适当看看]详解softmax函数以及相关求导过程
https://zhuanlan.zhihu.com/p/25723112
loss定义及本级导数
loss定义
公式:
其中:
C表示数据共有C个分类,
h是输出(Hypothesis),也即概率prob
y是标签,C个值中,只有一个是1,其他是0。假设本次推导时第j个标签是1。
loss对
的导数
这里切记不要把先把y值分类代入再求导,因为是对函数求导,y是个变量。
softmax定义及本级导数
softmax定义
公式:
其中:
h是输出(Hypothesis),
是前端输入,一般是logits,即未经激活的加权和。
softmax本级导数
求对
的导数
这个操作实际上没有意义,继续往下看。
求loss对
的导数
这里要看一下softmax的公式了,因为softmax公式的特性,它的分母包含了所有神经元的作用,所以,单个分支的导数受到了所有分支的影响。
分析一下这个求和表达式。由于只有j支路的y为1,其他支路为0。因此求和表达式中的偏导数中,只有k=j时有非0值,上式可化简为:
分2种情况
式中即
。
情况1:i=j,即标签为1的支路
情况2:i
j,即标签为0的支路
特别注意下标。
组合
ok,接下来我们只需要把上面的组合起来:
最后的结果看起来简单了很多,最后,针对分类问题,我们给定的结果y_i最终只会有一个类别是1,其他类别都是0,因此,对于分类问题,这个梯度等于:
代码
相关代码如下。
喜欢看代码的同学看这里。
# forward z1 = X.dot(W1) + b1 a1 = np.tanh(z1) z2 = a1.dot(W2) + b2 exp_scores = np.exp(z2) probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True) # bp delta3 = probs delta3[range(num_examples), y] -= 1 # softmax求导,就一句话 dW2 = (a1.T).dot(delta3) db2 = np.sum(delta3, axis=0, keepdims=True) delta2 = delta3.dot(W2.T) * (1 - np.power(a1, 2)) # tanh derivative dW1 = np.dot(X.T, delta2) db1 = np.sum(delta2, axis=0) # optional W1 += -lr * dW1 b1 += -lr * db1 W2 += -lr * dW2 b2 += -lr * db2